From eb5f473de0d13e3e219ba8ac49550c20c45880c5 Mon Sep 17 00:00:00 2001 From: Jonas Weinz Date: Sun, 24 Mar 2019 16:44:20 +0100 Subject: [PATCH] friends --- README.md | 59 ++++++++++++++++++++++ connection_handler.py | 114 +++++++++++++++++++++++++++++++++++++++++- create_database.py | 4 +- match_manager.py | 4 ++ user_manager.py | 26 ++++++++++ 5 files changed, 205 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c7c619a..82b1743 100644 --- a/README.md +++ b/README.md @@ -287,3 +287,62 @@ client: +**friend request**: + +```json +{ + "type": "friend_request", + "data" : { + "user": "" + } +} +``` + +response: + +```json +{ + "type": "friend_request_response", + "data": { + "success": + "msg": "..." + } +} +``` + +**unfriend**: + +```json +{ + "type": "unfriend_request", + "data" : { + "user": "" + } +} +``` + +response: + +```json +{ + "type": "unfriend_request_response", + "data": { + "success": + "msg": "..." + } +} +``` + + + +**friend update**: + +```json +{ + "type": "friends_update", + "data": { + "friends": "" + } +} +``` + diff --git a/connection_handler.py b/connection_handler.py index 959c7cf..08c257b 100644 --- a/connection_handler.py +++ b/connection_handler.py @@ -131,6 +131,7 @@ class ConnectionHandler(object): "msg": "" } })) + await self.send_friends(conn) await self._on_match_state_req(conn, None) return conn await conn.send(json.dumps({ @@ -231,6 +232,7 @@ class ConnectionHandler(object): })) if success: + await self.send_friends(conn) await self._on_match_state_req(conn, None) return conn @@ -337,6 +339,35 @@ class ConnectionHandler(object): try: if len(opponent) <= 16 and '\'' not in opponent and '"' not in opponent: if len(self.user_manager.get_user(opponent)) > 0: + + if len(self.match_manager.get_matches_for_user(conn.user_name)) >= 5: + await conn.websocket.send( + json.dumps( + { + "type": "match_request_response", + "data": { + "success": False, + "msg": "player " + opponent + " has too many open matches" + } + } + ) + ) + return + + if (self.match_manager.is_match(conn.user_name, opponent)): + await conn.websocket.send( + json.dumps( + { + "type": "match_request_response", + "data": { + "success": False, + "msg": "you are already plaing against " + opponent + } + } + ) + ) + return + await self._start_match(conn.user_name, opponent) await conn.websocket.send( @@ -461,13 +492,88 @@ class ConnectionHandler(object): if match is not None: match_state = match.to_json_state() - conn.send(json.dumps({ + await conn.send(json.dumps({ 'type': 'match_update', 'data': { 'match_state': json.loads(match_state) } })) + async def _on_friend_request(self, conn, data): + msg = "error in handling friend request" + success = False + try: + friend = data['user'].lower() + + # check for user: + if "\"" not in friend and "'" not in friend and ";" not in friend: + if friend in self.user_manager.get_friends_for_user(conn.user_name): + success = False + msg = f"'{friend}' is already your friend" + + elif self.user_manager.add_friend_to_user(conn.user_name, friend): + success = True + msg = f"added '{friend}' as a friend" + + else: + success = False + msg = f"player '{friend}' not found" + + else: + success = False + msg = "misformated friend request" + + finally: + await conn.send(json.dumps({ + 'type': 'friend_request_response', + 'data': { + 'success': success, + 'msg': msg + } + })) + + if success: + await self.send_friends(conn) + + async def _on_unfriend_request(self, conn, data): + success = False + msg = "error in handling unfriend request" + try: + friend = data['user'].lower() + + if "\"" not in friend and "'" not in friend and ";" not in friend: + if friend not in self.user_manager.get_friends_for_user(conn.user_name): + success = False + msg = f"cannot end friendship with '{friend}': it's not one of your friends" + else: + self.user_manager.remove_friend_from_user( + conn.user_name, friend) + + success = True + msg = f"removed '{friend}' from your friend list" + + finally: + await conn.send(json.dumps({ + 'type': 'unfriend_request_response', + 'data': { + 'success': success, + 'msg': msg + } + })) + + if success: + await self.send_friends(conn) + + async def send_friends(self, conn): + friends = list(self.user_manager.get_friends_for_user(conn.user_name)) + + await conn.send(json.dumps({ + 'type': 'friends_update', + 'data': { + 'friends': friends + } + })) + async def disconnect(self, conn): self._del_connection(conn) @@ -494,5 +600,11 @@ class ConnectionHandler(object): elif t == "match_states_request": await self._on_match_state_req(conn, msg['data']) + elif t == "friend_request": + await self._on_friend_request(conn, msg['data']) + + elif t == "unfriend_request": + await self._on_unfriend_request(conn, msg['data']) + else: print("could not interpret message: " + msg_str) diff --git a/create_database.py b/create_database.py index c2adf94..914a4eb 100755 --- a/create_database.py +++ b/create_database.py @@ -18,9 +18,11 @@ def create_tables(): "DROP TABLE IF EXISTS matches", "DROP TABLE IF EXISTS sessions", "DROP TABLE IF EXISTS users", + "DROP TABLE IF EXISTS friends", "CREATE TABLE users (name varchar(16) NOT NULL, pw_hash varchar(128) NOT NULL, pw_salt varchar(32) NOT NULL, last_seen datetime NOT NULL, PRIMARY KEY (name)) CHARACTER SET " + settings.db_charset, "CREATE TABLE matches (id varchar(32) NOT NULL, user_a varchar(16) NOT NULL, user_b varchar(16) NOT NULL, match_state varchar(4096) NOT NULL, active_user varchar(16), last_active datetime NOT NULL, FOREIGN KEY (user_a) REFERENCES users(name), FOREIGN KEY (user_b) REFERENCES users(name), FOREIGN KEY (active_user) REFERENCES users(name)) CHARACTER SET " + settings.db_charset, - "CREATE TABLE sessions (id varchar(32) NOT NULL, registered_user varchar(16), temp_user varchar(16), last_seen datetime NOT NULL, PRIMARY KEY (id), FOREIGN KEY(registered_user) REFERENCES users(name)) CHARACTER SET " + settings.db_charset + "CREATE TABLE sessions (id varchar(32) NOT NULL, registered_user varchar(16), temp_user varchar(16), last_seen datetime NOT NULL, PRIMARY KEY (id), FOREIGN KEY(registered_user) REFERENCES users(name)) CHARACTER SET " + settings.db_charset, + "CREATE TABLE friends (user varchar(16) NOT NULL, friend varchar(16) NOT NULL, FOREIGN KEY(user) REFERENCES users(name), FOREIGN KEY(friend) REFERENCES users(name)) CHARACTER SET " + settings.db_charset ] for query in queries: diff --git a/match_manager.py b/match_manager.py index 4d0c578..438c28c 100644 --- a/match_manager.py +++ b/match_manager.py @@ -54,6 +54,10 @@ class MatchManager(object): print("updated match") return match + def is_match(self, player_a, player_b): + query = f"SELECT * FROM matches WHERE (user_a='{player_a}' AND user_b='{player_b}') OR (user_a='{player_b}' AND user_b='{player_a}')" + return len(DatabaseConnection.global_single_query(query)) + def delete_match(self, match_id): query = f"DELETE FROM matches WHERE id='{match_id}'" DatabaseConnection.global_single_execution(query) diff --git a/user_manager.py b/user_manager.py index ae243b8..da6af5a 100644 --- a/user_manager.py +++ b/user_manager.py @@ -17,6 +17,13 @@ class UserManager(object): query = f"DELETE FROM users where name='{user_name}'" DatabaseConnection.global_single_execution(query) + # remove from friends: + query = f"DELETE FROM friends WHERE user='{user_name}'" + DatabaseConnection.global_single_execution(query) + + query = f"DELETE FROM friends WHERE friend='{user_name}'" + DatabaseConnection.global_single_execution(query) + def verify_user(self, user_name, pw): query = f"SELECT * FROM users where name='{user_name}'" users = DatabaseConnection.global_single_query(query) @@ -42,6 +49,25 @@ class UserManager(object): assert len(matches) == 1 query = f"UPDATE users SET last_seen='{datetime.datetime.now()}' WHERE name='{user_name}'" DatabaseConnection.global_single_execution(query) + + def add_friend_to_user(self, user_name, friend_name): + if len(self.get_user(friend_name)) > 0: + query = f"INSERT INTO friends (user, friend) VALUES ( '{user_name}', '{friend_name}')" + DatabaseConnection.global_single_execution(query) + return True + return False + + def get_friends_for_user(self, user_name): + query = f"SELECT friend FROM friends WHERE user='{user_name}'" + tmp = DatabaseConnection.global_single_query(query) + friends = set() + for entry in tmp: + friends.add(entry['friend']) + return friends + + def remove_friend_from_user(self, user_name, friend_name): + query = f"DELETE FROM friends WHERE user='{user_name}' AND friend='{friend_name}'" + DatabaseConnection.global_single_execution(query) def get_all_users(self): query = "SELECT name, last_seen FROM users"