diff --git a/.DS_Store b/.DS_Store index ecbd8745b852288b7ee3372bccde4f5e9307ec7d..30f3834918176a2c2f81213b84951d66311c943f 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Lab_3/.DS_Store b/Lab_3/.DS_Store index 83a1aa3fd55c0ed8fb03b5810757026de4044fb2..38e64d943bd45b70ad540b986a392aaf8d1e02b2 100644 Binary files a/Lab_3/.DS_Store and b/Lab_3/.DS_Store differ diff --git a/Lab_4/.DS_Store b/Lab_4/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..cd477194c8e26360739930522ab27ccf72594546 Binary files /dev/null and b/Lab_4/.DS_Store differ diff --git a/Lab_4/Lab4_TDDD97.pdf b/Lab_4/Lab4_TDDD97.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c7a742939df36c247406b95ce3dedcc23ad3982e Binary files /dev/null and b/Lab_4/Lab4_TDDD97.pdf differ diff --git a/Lab_4/Twidder/.DS_Store b/Lab_4/Twidder/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..aeb683ff2abafaefdd695afac5298539b9a4f169 Binary files /dev/null and b/Lab_4/Twidder/.DS_Store differ diff --git a/Lab_4/Twidder/__pycache__/database_helper.cpython-38.pyc b/Lab_4/Twidder/__pycache__/database_helper.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e4a18eb4153651973e42af292cfa4aab521d882 Binary files /dev/null and b/Lab_4/Twidder/__pycache__/database_helper.cpython-38.pyc differ diff --git a/Lab_4/Twidder/database b/Lab_4/Twidder/database new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Lab_4/Twidder/database.db b/Lab_4/Twidder/database.db new file mode 100644 index 0000000000000000000000000000000000000000..b8863ccbb4f1c57137f8f44aa97d3cac6c1560e4 Binary files /dev/null and b/Lab_4/Twidder/database.db differ diff --git a/Lab_4/Twidder/database_helper.py b/Lab_4/Twidder/database_helper.py new file mode 100644 index 0000000000000000000000000000000000000000..31c99f0531e7f57e98969af95424b4399729d5ea --- /dev/null +++ b/Lab_4/Twidder/database_helper.py @@ -0,0 +1,73 @@ +"""Database Helper""" +import sqlite3 +from sqlite3 import * +from flask import g + +DATABASE_URL = 'database.db' + +def get_db(): + """Connect to database""" + db = getattr(g, 'db', None) + if db is None: + db = g.db = sqlite3.connect(DATABASE_URL) + return db + +def close_db(): + """Disconnect""" + try: + db = getattr(g, 'db', None) + if db is not None: + db.close() + return True + else: + return False + except: + return False + +def create_user(email, password, firstname, familyname, gender, city, country): + """Create user""" + try: + get_db().execute("INSERT into user (email, password, firstname, familyname, gender, city, country) VALUES (?,?,?,?,?,?,?)",(email, password, firstname, familyname, gender, city, country)) + print("Success, User has been inserted into database") + get_db().commit() + return True + except: + return False + +def update_user(new_password, email): + """Update user""" + try: + get_db().execute("UPDATE user SET password = ? WHERE email = ?", (new_password,email)) + get_db().commit() + return True + except: + return False + +def create_post(my_email, destination_email, message): + """Add a messages to the database""" + try: + get_db().execute("INSERT INTO messages (email, emailPostedBy, message) VALUES (?, ?, ?)",(destination_email, my_email, message)) + get_db().commit() + return True + except: + return False + +def get_post(email): + """Get all messages from selected user from the database""" + try: + cursor = get_db().execute("SELECT * FROM messages WHERE email = ? ",[email]) + posts = cursor.fetchall() + cursor.close() + return posts + except Exception as e: + return [] + +def find_user(email): + """Read user by email""" + try: + cursor = get_db().execute("SELECT * FROM user WHERE email like ?", [email]) + rows = cursor.fetchone() + cursor.close() + return rows + except: + return [] diff --git a/Lab_4/Twidder/schema.sql b/Lab_4/Twidder/schema.sql new file mode 100644 index 0000000000000000000000000000000000000000..9ef51ab6c057777700d879dbd0e758e18187e194 --- /dev/null +++ b/Lab_4/Twidder/schema.sql @@ -0,0 +1,25 @@ +DROP TABLE IF EXISTS user; +DROP TABLE IF EXISTS messages; + +CREATE TABLE IF NOT EXISTS user(email VARCHAR(50) NOT NULL PRIMARY KEY, + password VARCHAR(50) NOT NULL, + firstname VARCHAR(50), + familyname VARCHAR(50), + gender VARCHAR(50), + city VARCHAR(50), + country VARCHAR(50) + ); + +CREATE TABLE IF NOT EXISTS messages(email VARCHAR(50), + emailPostedBy VARCHAR(50), + message VARCHAR(50) + ); + +INSERT INTO user (email, password, firstname, familyname, gender, city, country) + VALUES ("o@o", "oo", "o", "o", "male", "o", "o"); + +INSERT INTO user (email, password, firstname, familyname, gender, city, country) + VALUES ("a@a", "aa", "a", "a", "male", "a", "a"); + +INSERT INTO user (email, password, firstname, familyname, gender, city, country) + VALUES ("b@b", "bb", "b", "b", "male", "b", "b"); diff --git a/Lab_4/Twidder/server.py b/Lab_4/Twidder/server.py new file mode 100644 index 0000000000000000000000000000000000000000..d8b132cbeecff3417d820e9a1b25d4e9a0ba1be1 --- /dev/null +++ b/Lab_4/Twidder/server.py @@ -0,0 +1,379 @@ +"""Server""" +from flask import Flask, jsonify, request, make_response +from gevent.pywsgi import WSGIServer +import uuid +import database_helper +import json +from flask_sock import Sock +from gevent import monkey +monkey.patch_all() + + +#Remember: +#PUT for updating data, POST for adding new data +#save token on client and server (lab 3) +# source /Users/psyfax/TDDD97/bin/activate +# source "/Users/lorenzo/OneDrive - Linköpings universitet/Skola/DI3B/TDDD97/virtualenv/bin/activate" +# python3 server.py +# http://127.0.0.1:5000/myServer +# sqlite3 database.db ".read schema.sql" + +#Questions: +#Why does localhost in URL not work? + + + +app = Flask(__name__, static_url_path = '/static')#in case flask does not recognize folder +sock = Sock(app) + +app.debug = True +session = {'token': ("email", "wsObj")} + + + +@app.route('/') +def root(): + return app.send_static_file('client.html') + +@app.route('/myServer') +def myServer(): + return app.send_static_file('client.html') + +def token_has_error(token): + """All token standard error checks""" + if token is None: + # "Server received no token" + return True, 401 + if len(token) > 50: + # "Server received too long token" + return True, 401 + if token not in session: + #"User not signed in or invalid access token" + return True, 401 + return False, 0 + +def input_has_error(input): + """All standard input error checks""" + try: + str = request.get_json()[input] + except: + return jsonify({}), 400, "" + if str is None or str == "": # "Server received no " + str + return True, 400, "" + if len(str) > 50: # "Server received too long " + str + return True, 400, "" + return False, 0, str + + +@sock.route('/myServer/api') +def echo(socket): + while True: + + # Making sure we have a valid socket + if not socket: + return + + # Making sure message format is OK and store email & token in string + data = socket.receive() + try: + myEmail = json.loads(data)["email"] + except: + return + try: + myToken = json.loads(data)["token"] + except: + return + + # sign out if I am logged in somewhere else + print(session) + for token in list(session.keys()): + if session[token][0] == myEmail and token != myToken: + if session[token][1] != "": + session[token][1].send(json.dumps({"action" : "signOut"})) + session[token][1].close() + print("You got kicked out") + session.pop(token) + print(session) + + # Put socket in global dict so server knows my connection is open + session[myToken] = (myEmail, socket) + print(session) + socket.send(json.dumps({"action" : "signIn"})) + + +@app.route("/myServer/sign_in", methods=['POST']) +def sign_in(): + """Sign in user""" + + # Validate Email + tmp = input_has_error('email') + if tmp[0]: + return jsonify({}), tmp[1] + email = tmp[2] + + # Validate Password + tmp = input_has_error('password') + if tmp[0]: + return jsonify({}), tmp[1] + password = tmp[2] + + # Do the user have an account? + rows = database_helper.find_user(email) + if rows is None or rows == []: + return jsonify({}), 404 #"No user found by your email" + + if password != rows[1]: + return jsonify({}), 401 #"Incorrect password") + + # Generate a random token + token = str(uuid.uuid4()) + session[token] = (email, "") + + # return the token in the Authorization header + response = make_response(jsonify({})) #"Server inserted user data into database" + response.headers.add("Access-Control-Allow-Origin", "*") + response.headers["Authorization"] = token + return response, 204 + + +@app.route("/myServer/sign_up", methods=['POST']) +def sign_up(): + """Sign up a user""" + + tmp = input_has_error('email') + if tmp[0]: + print(tmp[1]) + return jsonify({}), tmp[1] + email = tmp[2] + + # Checking that the user does not already exist + if database_helper.find_user(email) is not None: + return jsonify({}), 409 #"Error: User already exists" + + # Går att göra på ett annat sätt med färre function calls + # Error checks & storing in local variables + tmp = input_has_error('password') + if tmp[0]: + return jsonify({}), tmp[1] + password = tmp[2] + tmp = input_has_error('firstname') + if tmp[0]: + return jsonify({}), tmp[1] + firstname = tmp[2] + tmp = input_has_error('familyname') + if tmp[0]: + return jsonify({}), tmp[1] + familyname = tmp[2] + tmp = input_has_error('gender') + if tmp[0]: + return jsonify({}), tmp[1] + gender = tmp[2] + tmp = input_has_error('city') + if tmp[0]: + return jsonify({}), tmp[1] + city = tmp[2] + tmp = input_has_error('country') + if tmp[0]: + return jsonify({}), tmp[1] + country = tmp[2] + + # Attempts to insert the user data to the database + if database_helper.create_user(email, password, firstname, familyname, gender, city, country): + return jsonify({}), 204 #"Server inserted user data into database" + else: + return jsonify({}), 500 #"General Error: Server failed to insert user data into database" + + +@app.route("/myServer/sign_out", methods=['POST']) +def sign_out(): + """Sign out user""" + token = request.headers["Authorization"] + + # Validate Token + tmp = token_has_error(token) + if tmp[0]: + return jsonify({}), tmp[1] + + # Close my socket + print(session) + try: + session[token][1].close() + except: + pass # samma sak som ingenting + print(session) + + # set user to not logged in + session.pop(token) + + return jsonify({}), 204 # "Successfully signed out") + + +@app.route("/myServer/change_password", methods=['PUT']) +def change_password(): + """Change password for the current user""" + token = request.headers["Authorization"] + + # Validate Token + tmp = token_has_error(token) + if tmp[0]: + print("validate token") + return jsonify({}), tmp[1] + + # Validate Old Password + tmp = input_has_error('old_password') + if tmp[0]: + print("validate old password") + return jsonify({}), tmp[1] + old_password = tmp[2] + + # Validate New Password + tmp = input_has_error('new_password') + if tmp[0]: + print("validate new password") + return jsonify({}), tmp[1] + new_password = tmp[2] + + # Extracting theemail of the current user + email = session[token][0] + + # Validation of the old password and attemption to change it to the new one + if old_password == database_helper.find_user(email)[1]: #checks if old_password is correct + status = database_helper.update_user(new_password, email) + if status: + print("Password changed") + return jsonify({}), 204 # "Password has been changed!" + else: + return jsonify({}), 500 # "Password has not been changed" + else: + return jsonify({}), 400 # "Old password is incorrect" + + +@app.route("/myServer/getDataByToken", methods=['GET']) +def get_user_data_by_token(): + """Verify current user through token and attemp to return the data of the user""" + token = request.headers["Authorization"] + + # Validate token + if token not in session: + return jsonify({}), 401 # "User not signed in or invalid access token" + + # Extracting the email of the current user + email = session[token][0] + return get_user_data_by_email(email) + + +@app.route("/myServer/getDataByEmail/<email>", methods=['GET']) +def get_user_data_by_email(email): + """Get user data by email""" + token = request.headers["Authorization"] + + # Validate Token + tmp = token_has_error(token) + if tmp[0]: + return jsonify({}), tmp[1] + + # Validate email + if email is None: + return True, 400 + if len(email) > 50: + return True, 400 + + # Attempting to find the data of the current user in the database + data = database_helper.find_user(email) + if data is None or data == []: + return jsonify({}), 404 #"No user found by your destination email" + + formated_data = {"email": data[0], "firstname": data[2], "familyname": data[3], "gender": data[4], "city": data[5], "country": data[6]} + return jsonify({"data" : formated_data}), 200 # "Data successfully sent to you!" + + +@app.route("/myServer/getUserMessageByToken", methods=['GET']) +def get_user_messages_by_token(): + """Get user's message wall thought the token of the user""" + token = request.headers["Authorization"] + + # Validate Token + tmp = token_has_error(token) + if tmp[0]: + return jsonify({}), tmp[1] + + # Extracting the email of the current user + email = session[token][0] + return get_user_messages_by_email(email) + +@app.route("/myServer/getMessagesByEmail/<req_email>", methods=['GET']) +def get_user_messages_by_email(req_email): + """Get user's message wall thought the email of the user""" + token = request.headers["Authorization"] + + # Validate Token + tmp = token_has_error(token) + if tmp[0]: + return jsonify({}), tmp[1] + + # Validate email + if req_email is None: + return True, 400 + if len(req_email) > 50: + return True, 400 + + # Find requested user in the data base + rows = database_helper.find_user(req_email) + + # Error check + if rows is None or rows == []: + return jsonify({}), 404 #"No user found by your destination email" + + # Insert post-info into array + rows = database_helper.get_post(req_email) + result = [] + for row in rows: + result.append({"email": row[0], "person_who_posted": row[1], "message": row[2]}) + + # Notify user if the wall is empty or not, and if not, return the all messages + if result == []: + return jsonify({}), 204 #"user's wall had no messages to collect" + return jsonify({"data" : result}), 200 # User posts has been displayed" + + +@app.route("/myServer/post", methods=['POST']) +def post_message(): + """Post a message on sombody's wall""" + + # Find out sender's email + token = request.headers["Authorization"] + tmp = token_has_error(token) + if tmp[0]: + return jsonify({}), tmp[1] + + # Extracting the email of the current user + my_email = session[token][0] + + # Find out & check email we are posting to + tmp = input_has_error('email') + if tmp[0]: + return jsonify({}), tmp[1] + destination_email = tmp[2] + + # Finding out if the user exist, who we wanna write a message to + rows = database_helper.find_user(destination_email) + if rows is None or rows == []: + return jsonify({}), 404 #"No user found by your destination email" + + # Verify message that we want to post + tmp = input_has_error('message') + if tmp[0]: + return jsonify({}), tmp[1] + message = tmp[2] + + # Calling and error checking function + if not database_helper.create_post(my_email, destination_email, message): + return jsonify({}), 500 #"Server failed to post message to database" + return jsonify({}), 204 #"Succeeded to post message") + + +if __name__ == '__main__': + # app.run(port=5000, debug=True) + app.debug = True + http_server = WSGIServer(('127.0.0.1', 5000), app) + http_server.serve_forever() diff --git a/Lab_4/Twidder/static/.DS_Store b/Lab_4/Twidder/static/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..36d83147cae8a46f11b3a295805bf360ebe1a510 Binary files /dev/null and b/Lab_4/Twidder/static/.DS_Store differ diff --git a/Lab_4/Twidder/static/client.css b/Lab_4/Twidder/static/client.css new file mode 100644 index 0000000000000000000000000000000000000000..ed4d8f6a197114a38324290aac70379ad5f9ce3c --- /dev/null +++ b/Lab_4/Twidder/static/client.css @@ -0,0 +1,274 @@ +*{ + box-sizing: border-box; + margin: 0; + padding: 0; +} +#windowDiv{ + background-color:rgb(0, 195, 255); + position: absolute; + width: 100%; + height: 100%; +} + +/* - - - - - Profile View - - - - - */ + +#big_div{ + width: 600px; + height: 400px; + margin: auto; + top: 100px; + position: relative; +} + +img { + width:340px; + height:400px; + border:1px solid rgb(5, 6, 7); +} + +#rhs_div{ + float:right; + height:100%; + width:250px; +} + +#login_div { + background-color: white; + text-align:left; + height: 100px; + width:100%; + border:1px solid rgb(5, 6, 7); + padding-top: 20px; + margin-bottom: 10px; +} + +#signup_div { + background-color: white; + padding-top: 20px; + text-align:left; + height: 290px; + width:100%; + border:1px solid rgb(5, 6, 7); +} + +#view_div{ + text-align:center; + height:370px; + width:570px; + border:10px solid rgb(5, 6, 7); + padding:5px; + margin:auto; +} +form{ + padding: 5px; +} +input{ + float: right; +} +select{ + float: right; + width: 60%; +} +label{ + display: inline-block; + height: 26px; +} + +#AccountPage label{ + margin: 10px; +} + +#match_error { + color: rgb(241, 4, 4); + position: absolute; + top: 230px; + left: 10px; + display: none; +} + +#old_error{ + color: rgb(255, 0, 0); + position: absolute; + top: 230px; + display: none; +} + +#AccountPage input{ + margin-top: 10px; + margin-right: 67%; +} + +#AccountPage label{ + margin: 10px; +} + + +h1, h3{ + text-align: center; +} + +#error{ + bottom: 20px; + left: 4px; + color: rgb(252, 6, 170); + position: relative; + font-size: 12px; +} +#signUpError{ + bottom: 36px; + left:31px; + color: rgb(252, 6, 170); + position: relative; + font-size: 12px; +} + +#signup_div h3{ + position:relative; + bottom:10px; +} + +/* - - - - - Profile View - - - - - */ + +.tabcontent button, .reloadButton{ + font-size: 15px; + position: absolute; + padding: 5px; + margin: 30px; +} +#signOutButton{ + right: 0px; + bottom: 0px; +} +#confirmButton{ + right: 60%; + bottom: 50%; +} +.textAreaButton { + left: 0px; + bottom: 0px; +} + +#tabDiv { + top: 100px; + position: relative; + margin: auto; + width: 1000px; + height: 50px; +} +.tab{ + background-color: red; + display: inline-block; + height: 100%; + width: 25%; + border-top-left-radius: 12px; + border-top-right-radius: 12px; + text-align: center; + padding:10px; + font-size: 25px; +} +#Home{ + background-color: lightgreen; +} + +.tabcontent{ + display: none; + top: 100px; + position: relative; + margin: auto; + width: 1000px; + height: 500px; + background-color: lightgreen; +} + +.tabcontent p{ + margin:10px; +} + +#HomePage{ + display: Block; +} + +.tabcontent h1{ + padding: 10px; + position: relative; +} +.tabcontent h3{ + text-align: left; + left: 24px; + position: relative; + display: inline; + width: 50%; +} +.tabcontent h3.nr2{ + left: 50%; + position: absolute; +} +.userInfo{ + margin: 24px; + background-color: white; + width: 40%; +} +.inputTextArea{ + margin: 18px; +} +th, td{ + text-align: left; + padding: 4px; +} +.reloadButton{ + right: 0px; + bottom: 0px; +} + + +.PostedMessagesDiv{ + background-color: white; + position: absolute; + width: calc(50% - 14px); + height: 316px; + right: 24px; + top: 103px; + + /* Get a Schrollbar */ + overflow: auto; +} + +#searchLabel{ + left: 305px; + position: absolute; +} + +#searchInput { + left: 489px; + position: absolute; + width: 240px; +} +#searchButton{ + left: 740px; + position: absolute; +} + +#searchMessage{ + color:red; + left: 478px; + top:420px; + position: absolute; +} + +/* #BrowsePage p{ + color:red; + left: 600px; + top:440px; + position: absolute; +} */ + + +/* #repeat_pass{ + background-color: rgb(197, 4, 235); + text-align:center; + width: 600px; + margin: auto; + height: 60px; + position:relative; top:90px; + border: 1px solid black; +} */ \ No newline at end of file diff --git a/Lab_4/Twidder/static/client.html b/Lab_4/Twidder/static/client.html new file mode 100644 index 0000000000000000000000000000000000000000..7834b2f76a8137d4b6ef69e7ec94a4a722cdac9b --- /dev/null +++ b/Lab_4/Twidder/static/client.html @@ -0,0 +1,178 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <title>Twidder</title> + <meta charset="utf-8"> + <link href="static/client.css" type="text/css" rel="stylesheet"> + <script src="static/client.js"></script> + <!-- <script src="static/serverstub.js"></script> --> + <!-- <script src="server.py"></script> --> + + <script type="text/view" id="welcomeview"> + <div id="repeat_pass"></div> + <div id="big_div"> + <img src="static/wimage.png"> + <div id="rhs_div"> + <div id="login_div"> + <form id="sign_in_form" action ="" method="" onsubmit="return sign_in()"> + <label for="Email_login">Email </label> + <input type="Email" name="name" id="Email_login" size="15" required></br> + <label for="Password_login">Password </label> + <input type="password" name="name" id="Password_login" size="15" required></br> + <input type="submit" value="login"></br> + </form> + <p id="error"> </p> + </div> + + <div id="signup_div"> + <form id="signup_form" action="" method="" onsubmit="return sign_up()"> + <h3>Sign up here</h3> + + <label for="First name">First name</label><input type="text" name="name" id="First name" size = "15" required> </br> + <label for="Family name">Family name</label><input type="text" name="name" id="Family name" size = "15" required> </br> + <label for="Gender">Gender</label> + <select id="Gender" name="Gender" required> + <option value="-" ></option> + <option value="Man" >Man</option> + <option value="Female" >Female</option> + </select><br> + + <label for="City">City </label><input type="text" name="name" id="City" size="15" required> </br> + <label for="Country">Country </label><input type="text" name="name" id="Country" size="15" required> </br> + <label for="Email_sign_up">Email </label><input type="Email" name="name" id="Email_sign_up" size="15" required> </br> + + <label for="Password_sign_up">Password </label><input type="password" name="name" id="Password_sign_up" size="15" required> </br> + + <label for="Repeat PSW">Repeat PSW </label><input type="password" name="name" id="Repeat PSW" size="15" required> </br> + <input type="submit" value="Sign Up"></br></br> + + </form> + <p id="signUpError"> </p> + </div> + </div> + </div> + </script> + + <script type="text/view" id="profileview"> + <div id="tabDiv"> + <div id="Home" class="tab" onclick= "showPage(event, 'HomePage')" >Home</div> + <div class="tab" onclick= "showPage(event, 'BrowsePage')">Browse</div> + <div class="tab"onclick= "showPage(event, 'AccountPage')">Account</div> + </div> + <div id="HomePage" class="tabcontent"> + <h1>Homepage</h1> + <h3>User Details:</h3> + <h3 class="nr2">Posted Messages:</h3> + <table id=homeUserInfo class=userInfo> + <tr> + <th>Email:</th> + <td></td> + </tr> + <tr> + <th>Name:</th> + <td></td> + </tr> + <tr> + <th>Family name:</th> + <td></td> + </tr> + <tr> + <th>Gender:</th> + <td></td> + </tr> + <tr> + <th>City:</th> + <td></td> + </tr> + <tr> + <th>Country:</th> + <td></td> + </tr> + </table> + <form id="homeInputTextArea" class="inputTextArea" onsubmit="return updateWall('home')"> + <label for="PostMessage">Post a message on your wall:</label> <br> + <textarea id="homeTextarea" name="textarea" rows="6" cols="50"></textarea> + <button class="textAreaButton" type="submit" value="Submit">Submit</button> + </form> + <div id="homePostedMessagesDiv" class="PostedMessagesDiv"></div> + <form id="homeReloadForm" class="reloadForm" onsubmit="return reloadWall('home')"> + <input id="homeReloadButton" class="reloadButton" type="submit" value="Reload"> + </form> + + </div> + <div id="BrowsePage" class="tabcontent"> + <h1>Browsepage</h1> + <h3>User Details:</h3> + <h3 class="nr2">Posted Messages:</h3> + <table id=browseUserInfo class=userInfo> + <tr> + <th>Email:</th> + <td></td> + </tr> + <tr> + <th>Name:</th> + <td></td> + </tr> + <tr> + <th>Family name:</th> + <td></td> + </tr> + <tr> + <th>Gender:</th> + <td></td> + </tr> + <tr> + <th>City:</th> + <td></td> + </tr> + <tr> + <th>Country:</th> + <td></td> + </tr> + </table> + + <form id="browseInputTextArea" class="inputTextArea" onsubmit="return updateWall('browse')"> + <label for="PostMessage">Post a message on your wall:</label> <br> + <textarea id="browseTextarea" name="textarea" rows="6" cols="50"></textarea> + <button class="textAreaButton" type="submit" value="Submit">Submit</button> + </form> + + <div id="browsePostedMessagesDiv" class="PostedMessagesDiv"></div> + <form id="browseReloadForm" class="reloadForm" onsubmit="return reloadWall('browse')"> + <input id="browseReloadButton" class="reloadButton" type="submit" value="Reload"> + </form> + + <form id="searchForm" onsubmit="return searchAnotherUser(event)"> + <label id="searchLabel" for="searchUser">Search by user email: </label> + <input id="searchInput" type="searchedEmail" name="searchedEmail"> + <input id="searchButton" type="submit" value="Search!"> + </form> + + <p id = searchMessage> </p> + + </div> + <div id="AccountPage" class="tabcontent"> + <h1>Accountpage</h1> + <label for="Change Password">Old password:</label> + <input type="password" name="name" id="old_password" size="15" required> + <label for="Change Password">New Password:</label> + <input type="password" name="name" id="new_password" size="15" required> + <label for="Confirm new password"> Confirm new password: </label> + <input type="password" name="name" id="confirm_pass" size="15" required> + + <error id=match_error> New password and confirm password does not match </error> + <p id = old_error> Old password is incorrect </p> + + <button id=confirmButton type="submit" name="submit" onclick="change_password(event)">Confirm</button> + <button id="signOutButton" type="submit" name="submit" onclick="sign_out()">Sign Out</button> + </div> + </script> + + </head> + + <body> + <div id="windowDiv"></div> + </body> + +</html> + diff --git a/Lab_4/Twidder/static/client.js b/Lab_4/Twidder/static/client.js new file mode 100644 index 0000000000000000000000000000000000000000..a4995c8c8e36ea8091923a9d74a35ceb0cb90c13 --- /dev/null +++ b/Lab_4/Twidder/static/client.js @@ -0,0 +1,607 @@ +// Global variables +var minPassLength = 2; +var windowDiv; +var welcomeDiv; +var profileDiv; +var url = 'http://' + document.domain + ':5000/myServer/'; +var curr_page = ""; +var socket; + +// source "/Users/lorenzo/OneDrive - Linköpings universitet/Skola/DI3B/TDDD97/virtualenv/bin/activate" + + +function connectWithSocket() { + let token = localStorage.getItem("currentUser"); + + // Changes the view to profile view and loads user info + displayView(); + setUserDetails("home"); + + + // Establish web socket + socket = new WebSocket('ws://' + document.domain + ':5000/myServer/api'); + + socket.onopen = function (event) { + let myEmail = localStorage.getItem("homeEmail"); + + // Todo - ändra så att token skickas i header istället + this.send(JSON.stringify({token: token, email: myEmail})); + console.log("Nu har jag skickat"); + } + + socket.onmessage = function (event) { + let response = JSON.parse(event.data); + + console.log("Nu fick jag svar"); + switch (response["action"]) { + case "signOut": + + // If old socket open, close it. + socket.close(); + console.log(response); + + // Reset token in the localStorage + localStorage.setItem("currentUser", ""); + localStorage.setItem("homeEmail", ""); + localStorage.setItem("browseEmail", ""); + + // Changes the view to welcome view + displayView(); + document.getElementById("error").innerHTML = "Signed Out, you signed in elsewhere"; + break; + case "signIn": + console.log(response); + console.log("ja är signed in"); + break; + } + } +} + + +// - - - - - Init Request Objects - - - - - // + +// Sign In Request Object +var signInRequest = new XMLHttpRequest(); +signInRequest.onreadystatechange = function() { + if (this.readyState == 4) { + + let errorMessage = document.getElementById("error"); + if (this.status == 204) { + let token = this.getResponseHeader("Authorization") + localStorage.setItem("currentUser", token); + connectWithSocket(); + } + else if (this.status == 400) { + errorMessage.innerHTML = "Error 400: Incorrect format"; + } + else if (this.status == 404) { + errorMessage.innerHTML = "Error 404: No user with that email exists"; + } + else if (this.status == 401) { + errorMessage.innerHTML = "Error 401: Incorrect password"; + } + else { + errorMessage.innerHTML = "Unknown error"; + } + } +}; + +// Sign Out Request Object +var signOutRequest = new XMLHttpRequest(); +signOutRequest.onreadystatechange = function() { + if (this.readyState == 4) { + if (this.status == 204) { + + // Reset token in the localStorage + localStorage.setItem("currentUser", ""); + localStorage.setItem("homeEmail", ""); + localStorage.setItem("browseEmail", ""); + + // Changes the view to welcome view + displayView(); + } + else if (this.status == 401) { + console.log("Error 401: You are not logged in"); + displayView(); + } + else { + console.log("Unknown error"); + displayView(); + } + } +}; + +// Sign Up Request Object +var signUpRequest = new XMLHttpRequest(); +signUpRequest.onreadystatechange = function () { + if (this.readyState == 4) { + + let errorMessage = document.getElementById("error"); + if (this.status == 204) { + errorMessage.innerHTML = "You have signed up"; + } + else if (this.status == 400) { + errorMessage.innerHTML = "Error 400: Enter the data in the correct format"; + } + else if (this.status == 409) { + errorMessage.innerHTML = "Error 409: User already exists"; + } + else if (this.status == 500) { + errorMessage.innerHTML = "Error 500: Error at server side"; + } + else { + errorMessage.innerHTML = "Unknown error"; + } + } +}; + +// Change Password Request Object +var ChangePassRequest = new XMLHttpRequest(); +ChangePassRequest.onreadystatechange = function () { + if (this.readyState == 4) { + + let errorMessage = document.getElementById("match_error"); + if (this.status == 204) { + errorMessage.innerHTML = "Password has been changed!"; + } + else if (this.status == 400) { + errorMessage.innerHTML = "Error 400: Old password is incorrect or Old/New password has wrong format" + } + else if (this.status == 401) { + errorMessage.innerHTML = "Error 401: You are not logged in" + } + else if (this.status == 500) { + errorMessage.innerHTML = "Error 500: Error at server side"; + } + else { + errorMessage.innerHTML = "Unknown error" + } + errorMessage.style.display = "block"; + } +}; + +// Get user data by token Request Object +var dataByTokenRequest = new XMLHttpRequest(); +dataByTokenRequest.onreadystatechange = function() { + if (this.readyState == 4) { + if (this.status == 200) { + + let userDataArray = JSON.parse(this.responseText); + + // Putting the user data we retrieved from server to the corresponding html table + let userTable = document.getElementById("homeUserInfo"); + userTable.rows[0].cells[1].innerHTML = userDataArray["data"].email; + userTable.rows[1].cells[1].innerHTML = userDataArray["data"].firstname; + userTable.rows[2].cells[1].innerHTML = userDataArray["data"].familyname; + userTable.rows[3].cells[1].innerHTML = userDataArray["data"].gender; + userTable.rows[4].cells[1].innerHTML = userDataArray["data"].city; + userTable.rows[5].cells[1].innerHTML = userDataArray["data"].country; + + localStorage.setItem("homeEmail", userDataArray["data"].email); + reloadWall("home"); + } + else if (this.status == 401) { + console.log("Error 401: You are not logged in"); + } + else if (this.status == 400) { + console.log("Error 400: Incorrect format"); + } + else if (this.status == 404) { + console.log("Error 404: No user with that email exists"); + } + else { + console.log("Unknown error"); + } + } +}; + +// Get user data by email Request Object +var dataByEmailRequest = new XMLHttpRequest(); +dataByEmailRequest.onreadystatechange = function() { + if (this.readyState == 4) { + + let errorMessage = document.getElementById("searchMessage"); + if (this.status == 200) { + + let userDataArray = JSON.parse(this.responseText); + + // Putting the user data we retrieved from server to the corresponding html table + let userTable = document.getElementById("browseUserInfo"); + userTable.rows[0].cells[1].innerHTML = userDataArray["data"].email; + userTable.rows[1].cells[1].innerHTML = userDataArray["data"].firstname; + userTable.rows[2].cells[1].innerHTML = userDataArray["data"].familyname; + userTable.rows[3].cells[1].innerHTML = userDataArray["data"].gender; + userTable.rows[4].cells[1].innerHTML = userDataArray["data"].city; + userTable.rows[5].cells[1].innerHTML = userDataArray["data"].country; + + localStorage.setItem("browseEmail", userDataArray["data"].email); + errorMessage.iinnerHTML = "" + reloadWall("browse"); + } + else { + if (this.status == 401) { + errorMessage.innerHTML = "Error 401: You are not loged in"; + } + else if (this.status == 400) { + errorMessage.innerHTML = "Error 400: Incorrect format"; + } + else if (this.status == 404) { + errorMessage.innerHTML = "Error 404: No user with that email exists"; + } + else { + errorMessage.innerHTML = "Unknown error"; + } + localStorage.setItem("browseEmail", ""); + } + } +}; + +// Get Messages By Token Request Object +var messagesByTokenRequest = new XMLHttpRequest(); +messagesByTokenRequest.onreadystatechange = function() { + if (this.readyState == 4) { + + if (this.status == 200) { + + let currentWall = JSON.parse(this.responseText); + + // Formating the text before putting to wall + let complete = ""; + for (let i = 0; i < currentWall.data.length; i++) { + complete += currentWall.data[i].person_who_posted + ': ' + currentWall.data[i].message + "</br>"; + } + document.getElementById('homePostedMessagesDiv').innerHTML = complete; + } + else if (this.status == 204) { + console.log("Success, but no messages to receive"); + } + else if (this.status == 401) { + console.log("Error 401: You are not loged in"); + } + else if (this.status == 400) { + console.log("Error 400: Incorrect format"); + } + else if (this.status == 404) { + console.log("Error 404: No user with that email exists"); + } + else { + console.log("Unknown error"); + } + } +}; + +// Get Messages By Email Request Object +var messagesByEmailRequest = new XMLHttpRequest(); +messagesByEmailRequest.onreadystatechange = function() { + if (this.readyState == 4) { + + if (this.status == 200) { + + let currentWall = JSON.parse(this.responseText); + + // Fromating the text before putting to wall + let complete = ""; + for (let i = 0; i < currentWall.data.length; i++) { + complete += currentWall.data[i].person_who_posted + ': ' + currentWall.data[i].message + "</br>"; + } + document.getElementById('browsePostedMessagesDiv').innerHTML = complete; + + } + else if (this.status == 204) { + console.log("Success, but no messages to receive"); + } + else if (this.status == 401) { + console.log("Error 401: You are not loged in"); + } + else if (this.status == 400) { + console.log("Error 400: Incorrect format"); + } + else if (this.status == 404) { + console.log("Error 404: No user with that email exists"); + } + else { + console.log("Unknown error"); + } + } +}; + +// Post Message Request Object +var postMessageRequest = new XMLHttpRequest(); +postMessageRequest.onreadystatechange = function () { + if (this.readyState == 4) { + + let errorMessage = document.getElementById('searchMessage'); + if (this.status == 204) { + console.log('Message posted!') + errorMessage.innerHTML = ""; + if (curr_page != null && curr_page != "") + reloadWall(curr_page); + } + else if (this.status == 400) { + errorMessage.innerHTML = "Error 400: Incorrect format"; + } + else if (this.status == 404) { + errorMessage.innerHTML = "Error 404: No user selected to write to"; + } + else if (this.status == 401) { + errorMessage.innerHTML = "Error 401: You are not loged in"; + } + else if (this.status == 500) { + errorMessage.innerHTML = "Error 500: Error at server side"; + } + else { + errorMessage.innerHTML = "Unknown error"; + } + } +}; + + +// - - - - - Init functions - - - - - // + +// Function for displaying the right view +displayView = function(){ + if (localStorage.getItem("currentUser") == "") + windowDiv.innerHTML = welcomeDiv.innerHTML; + else + windowDiv.innerHTML = profileDiv.innerHTML; +}; + + +// - - - - - The function when page loads - - - - - // + +window.onload = function () { + + // Delete when done - används för att hoppa tillbaka till rtt view under utveckling + // localStorage.setItem("currentUser", ""); + // localStorage.setItem("homeEmail", ""); + // localStorage.setItem("browseEmail", ""); + + // All key/value pairs stored in out localStorage + // If first time? check this: + if (localStorage.getItem("homeEmail") == null) + localStorage.setItem("homeEmail", ""); + if (localStorage.getItem("browseEmail") == null) + localStorage.setItem("browseEmail", ""); + if (localStorage.getItem("currentUser") == null) + localStorage.setItem("currentUser", ""); + + // Initialize div objects (global variables) + welcomeDiv = document.getElementById("welcomeview"); + profileDiv = document.getElementById("profileview"); + windowDiv = document.getElementById("windowDiv"); + + if (localStorage.getItem("currentUser") != "") {//if logged in + connectWithSocket(); + } + else { + // Set correct view depending on if someone is signed in or not + displayView(); + } +}; + + +// Function for setting user details, either for yourself or for some other user +function setUserDetails(who) { + + // "who" could be either home or browse, this way know which info we are displaying and where + let token = localStorage.getItem("currentUser"); + if (token != null && token != "" ){ + let userTable = document.getElementById(who + "UserInfo"); + let email = localStorage.getItem(who + "Email"); + + // Display my own info + if (who == 'home') { + // Send request to server about receiving the info + dataByTokenRequest.open("GET", url + "getDataByToken", true); + dataByTokenRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + dataByTokenRequest.setRequestHeader("Authorization", token) + dataByTokenRequest.send(); + } + + // Display the info about the searched user + else if (who == 'browse' && email != null && email != "") { + // Send request to server about receiving the info + dataByEmailRequest.open("GET", url + "getDataByEmail/" + email, true); + dataByEmailRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + dataByEmailRequest.setRequestHeader("Authorization", token) + dataByEmailRequest.send(); + } + } + return false; +} + +// - - - - - Sign Up/In/Out - - - - - // + +function sign_up() { + + let form = document.getElementById("signup_form"); + let errorMess = document.getElementById("signUpError"); + let user = { + firstname: form[0].value, + familyname: form[1].value, + gender: form[2].value, + city: form[3].value, + country: form[4].value, + email: form[5].value, + password: form[6].value, + repeat_password: form[7].value + }; + + + // Error checks + if (user.password.length < minPassLength) + errorMess.innerHTML = "Password's length is too short"; + else if (user.password != user.repeat_password) + errorMess.innerHTML = "Passwords does not match"; + else { + + // Sending sign_ou request to "server" + signUpRequest.open("POST", url + "sign_up", true); + signUpRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + signUpRequest.send(JSON.stringify(user)); + } + return false; +} + +function sign_in() { + let form = document.getElementById("sign_in_form"); + let email = form[0].value; + let password = form[1].value; + let errorMess = document.getElementById("error"); + + // Error checks + if (password.length < minPassLength) + errorMess.innerHTML = "Password's length is too short"; + else { + + // Sending sign_in request to "server" + signInRequest.open("POST", url + "sign_in", true); + signInRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + signInRequest.send(JSON.stringify({email: email,password: password})); + } + return false; +} + +function sign_out(){ + let token = localStorage.getItem("currentUser"); + + // Sending sign_out request to "server" + signOutRequest.open("POST", url + "sign_out", true); + signOutRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + signOutRequest.setRequestHeader("Authorization", token) + signOutRequest.send(); + + return false; +} + + + +// - - - - - Changing tabs - - - - - // + +function showPage(ourEvent, name) { + + // - - Fixing the tabs - - // + // Unselect all + let tabcontent = document.getElementById("tabDiv"); + for (i = 0; i < tabcontent.children.length; i++) { + tabcontent.children[i].style.backgroundColor = "red"; + } + // Select only the one we want + let div = ourEvent.target; + div.style.backgroundColor = "lightgreen"; + + + // - - Fixing the content - - // + // Unselect all + let allPages = document.getElementsByClassName("tabcontent"); + for (let i = 0; i < allPages.length; i++) { + allPages[i].style.display = "none"; + } + // Select only the one we want + let selected_tab = document.getElementById(name); + selected_tab.style.display = "block"; + + return false; +} + + + +// - - - - - Changing Password - - - - - // + +//Function for changing password +function change_password(ourEvent){ + let old_pass = document.getElementById("old_password").value; + let new_pass = document.getElementById("new_password").value; + let confirm_pass = document.getElementById("confirm_pass").value; + let token = localStorage.getItem("currentUser"); + let error_text = document.getElementById("match_error"); + + // New password have to be entered twice, otherwise throw error + if (new_pass.length < minPassLength) { + error_text.innerHTML = "New password too short"; + } + else if (new_pass != confirm_pass) { + error_text.innerHTML = "New password and confirm password does not match"; + } + else { + ChangePassRequest.open("PUT", url + "change_password", true); + ChangePassRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + ChangePassRequest.setRequestHeader("Authorization", token) + ChangePassRequest.send(JSON.stringify({old_password:old_pass, new_password:new_pass})); + } + return false; +} + +// - - - - - Changing the wall - - - - - // + +// Submit text button +function updateWall(who){ + // "who" could be either home or browse, this way know which wall to write on + let messageToWall = document.getElementById(who + 'Textarea').value; + let errorMessage = document.getElementById('searchMessage'); + let token = localStorage.getItem("currentUser"); + let email = localStorage.getItem(who + "Email"); + curr_page = who; + + if (email != null && email != "" && token != null && token != "") { + + // Send user's message to the server + postMessageRequest.open("POST", url + "post", true); + postMessageRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + postMessageRequest.setRequestHeader("Authorization", token) + postMessageRequest.send(JSON.stringify({ email: email, message: messageToWall })); + + errorMessage.innerHTML = ""; + } + else{ + errorMessage.innerHTML = "No user selected to write to"; + } + + // Clear the text area the user just wrote in + document.getElementById(who + 'Textarea').value = ""; + return false; +} + +// Reload button +function reloadWall(who) { + // "who" could be either home or browse, this way know which wall to load to + let token = localStorage.getItem("currentUser"); + let email = localStorage.getItem(who + "Email"); + + // If wanting messages from my own wall + if (who == 'home') { + // Send request to server about receiving the info + messagesByTokenRequest.open("GET", url + "getUserMessageByToken", true); + messagesByTokenRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + messagesByTokenRequest.setRequestHeader("Authorization", token) + messagesByTokenRequest.send(); + } + + // If wanting messages from another's wall + else if (who == 'browse' && email != null && email != "") { + // Send request to server about receiving the info + messagesByEmailRequest.open("GET", url + "getMessagesByEmail/" + email, true); + messagesByEmailRequest.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + messagesByEmailRequest.setRequestHeader("Authorization", token) + messagesByEmailRequest.send(); + } + + return false; +} + +// Changing another's wall +function searchAnotherUser(event){ + let token = localStorage.getItem("currentUser"); + + // Reseting the error messages + document.getElementById('searchMessage').innerHTML = ""; + + if(token != "") { + + // Store the searched email in localStorage so that it can be reached in "setUserDetails()" + let email = event.target["searchInput"].value; + localStorage.setItem("browseEmail", email); + setUserDetails("browse"); + } + return false; +} \ No newline at end of file diff --git a/Lab_4/Twidder/static/serverstub.js b/Lab_4/Twidder/static/serverstub.js new file mode 100644 index 0000000000000000000000000000000000000000..949405c3b0f3567e1294e4b322b6909e2a322704 --- /dev/null +++ b/Lab_4/Twidder/static/serverstub.js @@ -0,0 +1,188 @@ +/** + * Serverstub.js + * + * Simple dummy server for TDDD97 + * + * If you're a student, you shouldn't need to look through this file, + * the description of how it works is in the lab instructions. + **/ + + +var serverstub = (function() { + 'use strict'; + + var users; + var loggedInUsers; + + var syncStorage = function(){ + if (localStorage.getItem("users") === null) { + users = {}; + } else { + users = JSON.parse(localStorage.getItem("users")); + } + + if (localStorage.getItem("loggedinusers") === null) { + loggedInUsers = {}; + } else { + loggedInUsers = JSON.parse(localStorage.getItem("loggedinusers")); + } + + } + + var persistUsers = function(){ + localStorage.setItem("users", JSON.stringify(users)); + }; + var persistLoggedInUsers = function(){ + localStorage.setItem("loggedinusers", JSON.stringify(loggedInUsers)); + }; + var tokenToEmail = function(token){ + return loggedInUsers[token]; + }; + var copyUser = function(user){ + return JSON.parse(JSON.stringify(user)); + }; + + var serverstub = { + signIn: function(email, password){ + syncStorage(); + if(users[email] != null && users[email].password == password){ + var letters = "abcdefghiklmnopqrstuvwwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + var token = ""; + for (var i = 0 ; i < 36 ; ++i) { + token += letters[Math.floor(Math.random() * letters.length)]; + } + loggedInUsers[token] = email; + persistLoggedInUsers(); + return {"success": true, "message": "Successfully signed in.", "data": token}; + } else { + return {"success": false, "message": "Wrong username or password."}; + } + }, + + postMessage: function(token, content, toEmail){ + syncStorage(); + var fromEmail = tokenToEmail(token); + if (fromEmail != null) { + if (toEmail == null) { + toEmail = fromEmail; + } + if(users[toEmail] != null){ + var recipient = users[toEmail]; + var message = {"writer": fromEmail, "content": content}; + recipient.messages.unshift(message); + persistUsers(); + return {"success": true, "message": "Message posted"}; + } else { + return {"success": false, "message": "No such user."}; + } + } else { + return {"success": false, "message": "You are not signed in."}; + } + }, + + getUserDataByToken: function(token){ + syncStorage(); + var email = tokenToEmail(token); + return serverstub.getUserDataByEmail(token, email); + }, + + getUserDataByEmail: function(token, email){ + syncStorage(); + if (loggedInUsers[token] != null){ + if (users[email] != null) { + var match = copyUser(users[email]); + delete match.messages; + delete match.password; + return {"success": true, "message": "User data retrieved.", "data": match}; + } else { + return {"success": false, "message": "No such user."}; + } + } else { + return {"success": false, "message": "You are not signed in."}; + } + }, + + getUserMessagesByToken: function(token){ + syncStorage(); + var email = tokenToEmail(token); + return serverstub.getUserMessagesByEmail(token,email); + }, + + getUserMessagesByEmail: function(token, email){ + syncStorage(); + if (loggedInUsers[token] != null){ + if (users[email] != null) { + var match = copyUser(users[email]).messages; + return {"success": true, "message": "User messages retrieved.", "data": match}; + } else { + return {"success": false, "message": "No such user."}; + } + } else { + return {"success": false, "message": "You are not signed in."}; + } + }, + + signOut: function(token){ + syncStorage(); + if (loggedInUsers[token] != null){ + delete loggedInUsers[token]; + persistLoggedInUsers(); + return {"success": true, "message": "Successfully signed out."}; + } else { + return {"success": false, "message": "You are not signed in."}; + } + }, + + signUp: function(inputObject){ // {email, password, firstname, familyname, gender, city, country} + syncStorage(); + if (users[inputObject.email] === undefined){ + if( + (typeof(inputObject.email) === 'string') && + (typeof(inputObject.password) === 'string') && + (typeof(inputObject.firstname) === 'string') && + (typeof(inputObject.familyname) === 'string') && + (typeof(inputObject.gender) === 'string') && + (typeof(inputObject.city) === 'string') && + (typeof(inputObject.country) === 'string') + ) { + var user = { + 'email': inputObject.email, + 'password': inputObject.password, + 'firstname': inputObject.firstname, + 'familyname': inputObject.familyname, + 'gender': inputObject.gender, + 'city': inputObject.city, + 'country': inputObject.country, + 'messages': [] + }; + users[inputObject.email] = user; + persistUsers(); + return {"success": true, "message": "Successfully created a new user."}; + } else { + return {"success": false, "message": "Form data missing or incorrect type."}; + } + + } else { + return {"success": false, "message": "User already exists."}; + } + }, + + changePassword: function(token, oldPassword, newPassword){ + syncStorage(); + if (loggedInUsers[token] != null){ + var email = tokenToEmail(token); + if (users[email].password == oldPassword){ + users[email].password = newPassword; + persistUsers(); + return {"success": true, "message": "Password changed."}; + } else { + return {"success": false, "message": "Wrong password."}; + } + } else { + return {"success": false, "message": "You are not logged in."}; + } + } + }; + + return serverstub; +})(); diff --git a/Lab_4/Twidder/static/wimage.png b/Lab_4/Twidder/static/wimage.png new file mode 100644 index 0000000000000000000000000000000000000000..048bdd2fcf666069f57f0aab8521dc49f9914725 Binary files /dev/null and b/Lab_4/Twidder/static/wimage.png differ diff --git a/requirements.txt b/requirements.txt index 0f7b23c1b6d9f4af401e0ea6c6ad4483f32c09d8..5d02793351f023646d3a1a828c711222ff566ebf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,15 +1,18 @@ astroid==2.9.3 -click==8.0.3 -Flask==2.0.3 +distlib==0.3.4 +filelock==3.5.1 +gevent==21.12.0 +gevent-websocket==0.10.1 +greenlet==1.1.2 isort==5.10.1 -itsdangerous==2.0.1 -Jinja2==3.0.3 lazy-object-proxy==1.7.1 -MarkupSafe==2.0.1 mccabe==0.6.1 platformdirs==2.5.0 pylint==2.12.2 +six==1.15.0 toml==0.10.2 typing_extensions==4.1.1 -Werkzeug==2.0.3 +virtualenv==20.13.1 wrapt==1.13.3 +zope.event==4.5.0 +zope.interface==5.4.0