diff --git a/backend/db.py b/backend/db.py index 1de3a2111..e5997248f 100644 --- a/backend/db.py +++ b/backend/db.py @@ -198,61 +198,104 @@ def delete_file(self, file_url): DB = DataStorage() -# get rooms for a particular user -def get_rooms(user_id, org_id): - """Get the rooms a user is in +def get_org(org: str): + """This is a helper function + Args: + org: organizational's unique identifier + Returns: + class object referrencing DataStorage + """ + helper = DB + helper.organization_id = org + return helper + +def get_user_rooms(user_id: str, org_id: str): + """ + A utility function that retrieves all the rooms linked to a user from the dm_rooms collection Args: - user_id (str): The user id + collection: dm_rooms + user_id (str): a unique identifier used as a query param to filter the collection + org_id (str): uniquely identifies the organisation the user belongs too in the collection Returns: - [List]: [description] + A List of dicts containing the information of each room associated with the particular user. + example: + [{'_id': '616c0adb240d4baaf0fefd68', + 'bookmark': [], + 'closed': False, + 'created_at': '2021-10-17T11:36:59.385987Z', + 'org_id': '61695d8bb233d46cc8a9af48', + 'pinned': [], + 'private': True, + 'room_name': 'any name', + 'room_user_ids': ['616a8fe2f99355096b2de6a4', '61696f4f09dcfac4133ddaa3'], + 'starred': [] + }] + + Raises: + None: no error handling, function returns an empty list if invalid params are parsed """ + org = get_org(org_id) # initializes the DataStorage class with a unique organization identifier + query = {"room_user_ids": user_id} # matches the room_user_ids field in the room document + options = {"sort": {"created_at": -1}} # query modifier, sorts from the most recent - helper = DataStorage() - helper.organization_id = org_id - query = {"room_user_ids":user_id} - options = {"sort":{"created_at":-1}} - response = helper.read_query("dm_rooms", query=query, options=options) + user_rooms = org.read_query( + "dm_rooms", query=query, options=options + ) - if response and "status_code" not in response: - return response + if user_rooms and "status_code" not in user_rooms: + return user_rooms return [] -# get all the messages in a particular room -def get_room_messages(room_id, org_id): - helper = DataStorage() - helper.organization_id = org_id - options = {"sort":{"created_at":-1}} - response = helper.read_query("dm_messages", query={"room_id": room_id}, options=options) +def get_room_messages(room_id: str, org_id: str): + """ + get all the messages in a particular room + Args: + room_id: room's unique identifier + org_id: organization's unique identifier + Returns: + return: returns list of rooms if true else returns empty list if false + + """ + response = get_org(org_id).read_query( + "dm_messages", query={"room_id": room_id}, options={"sort": {"created_at": -1}} + ) if response and "status_code" not in response: return response return [] -# get all the messages in a particular room filtered by date -def get_messages(room_id,org_id, date): - helper = DataStorage() - helper.organization_id = org_id - req_date = datetime.strptime(date, '%d-%m-%Y') +def get_messages(room_id: str, org_id: str, date): + """ + get all the messages in a particular room filtered by date + Args: + room_id: room's unique identifier + org_id: organization's unique identifier + date: date to filter the messages + + Returns: + return: list of messages ordered by date + + + """ + + req_date = datetime.strptime(date, "%d-%m-%Y") next_day = req_date + timedelta(days=1) - options = {"sort":{"created_at":-1}} query = { - "$and":[ - {"room_id":room_id}, - {"created_at":{ - "$gte":str(req_date), - "$lt": str(next_day) - }} + "$and": [ + {"room_id": room_id}, + {"created_at": {"$gte": str(req_date), "$lt": str(next_day)}}, ] } - - response = helper.read_query("dm_messages", query=query, options=options) + + response = get_org(org_id).read_query( + "dm_messages", query=query, options={"sort": {"created_at": -1}} + ) if response and "status_code" not in response: return response return [] - def get_user_profile(org_id=None, user_id=None): @@ -264,9 +307,7 @@ def get_user_profile(org_id=None, user_id=None): def get_all_organization_members(org_id: str): - response = requests.get( - f"https://api.zuri.chat/organizations/{org_id}/members/" - ) + response = requests.get(f"https://api.zuri.chat/organizations/{org_id}/members/") if response.status_code == 200: return response.json()["data"] return None @@ -279,79 +320,115 @@ def get_member(members: list, member_id: str): return {} -def sidebar_emitter( - org_id, member_id, group_room_name=None -): # group_room_name = None or a String of Names +def sidebar_emitter(org_id:str, member_id:str, group_room_name:str = None) -> dict: + """Function structures data for the sidebar + + Args: + org_id(str): org used to extract data + member_id(str): id of user logged in + + Returns: + A dict mapping keys to the data fetched. Example + { + "event":"event title", + "plugin_id":"dm.zuri.chat", + "data":{dict of custom data} + } + """ rooms = [] starred_rooms = [] - user_rooms = get_rooms(user_id=member_id, org_id=org_id) + user_rooms = get_user_rooms(user_id=member_id, org_id=org_id) members = get_all_organization_members(org_id) - + if user_rooms != None: for room in user_rooms: - room_profile = {} - if len(room['room_user_ids']) == 2: - room_profile["room_id"] = room["_id"] - room_profile["room_url"] = f"/dm/{room['_id']}" - user_id_set = set(room['room_user_ids']).difference({member_id}) - partner_id = list(user_id_set)[0] - - profile = get_member(members,partner_id) - - if "user_name" in profile and profile['user_name'] != "": - if profile["user_name"]: - room_profile["room_name"] = profile["user_name"] - else: - room_profile["room_name"] = "no user name" - if profile["image_url"]: - room_profile["room_image"] = profile["image_url"] - else: - room_profile[ - "room_image" - ] = "https://cdn.iconscout.com/icon/free/png-256/account-avatar-profile-human-man-user-30448.png" - - else: - room_profile["room_name"] = "no user name" - room_profile[ - "room_image" - ] = "https://cdn.iconscout.com/icon/free/png-256/account-avatar-profile-human-man-user-30448.png" - else: - room_profile["room_name"] = room["room_name"] - room_profile["room_id"] = room["_id"] - room_profile["room_url"] = f"/dm/{room['_id']}" - + room_profile = get_user_sidebar_room_data(room, member_id, members) rooms.append(room_profile) if member_id in room["starred"]: starred_rooms.append(room_profile) - - side_bar = { - "event":"sidebar_update", - "plugin_id":"dm.zuri.chat", - "data":{ - "name": "DM Plugin", - "description": "Sends messages between users", + + return { + "event": "sidebar_update", "plugin_id": "dm.zuri.chat", - "organisation_id": f"{org_id}", - "user_id": f"{member_id}", - "group_name": "DM", - "category": "direct messages", - "show_group": False, - "button_url": f"/dm", - "public_rooms": [], - "starred_rooms": starred_rooms, - "joined_rooms": rooms, - } - # List of rooms/collections created whenever a user starts a DM chat with another user - # This is what will be displayed by Zuri Main + "data": { + "name": "DM Plugin", + "description": "Sends messages between users", + "plugin_id": "dm.zuri.chat", + "organisation_id": f"{org_id}", + "user_id": f"{member_id}", + "group_name": "DM", + "category": "direct messages", + "show_group": False, + "button_url": "/dm", + "public_rooms": [], + "starred_rooms": starred_rooms, + "joined_rooms": rooms, + }, } - return side_bar + + +def get_user_sidebar_room_data(room: dict, member_id: str, members: list) -> dict: + """Produces data needed to be rendered on the sidebar + + Args: + room(dict): chat room user is present in + member_id(str): id of user in the room + members(list): list of all members in the org + + Returns: + room_profile(dict): data of room including group rooms + """ + + room_profile = {} + if len(room["room_user_ids"]) == 2: + room_profile = extract_user_room_data(room, member_id, members) + else: + room_profile["room_name"] = room["room_name"] + room_profile["room_id"] = room["_id"] + room_profile["room_url"] = f"/dm/{room['_id']}" + + return room_profile + + +def extract_user_room_data(room: dict, member_id: str, members: list) -> dict: + """Extracts room data for other users in a room with a user + + Args: + room(dict): chat room user is present in + member_id(str): id of user in the room + members(list): list of all members in the org + + Returns: + room_profile(dict): the data of the room including other user excluding user logged in + """ + room_profile = {"room_id": room["_id"], "room_url": f"/dm/{room['_id']}"} + user_id_set = set(room["room_user_ids"]).difference({member_id}) + partner_id = list(user_id_set)[0] + + profile = get_member(members, partner_id) + + if "user_name" in profile and profile["user_name"] != "": + room_profile["room_name"] = profile["user_name"] or "no user name" + room_profile["room_image"] = ( + profile["image_url"] + or "https://cdn.iconscout.com/icon/free/png-256/account-avatar-profile-human-man-user-30448.png" + ) + + else: + room_profile["room_name"] = "no user name" + room_profile[ + "room_image" + ] = "https://cdn.iconscout.com/icon/free/png-256/account-avatar-profile-human-man-user-30448.png" + + return room_profile + # gets starred rooms def get_starred_rooms(member_id, org_id): """goes through database and returns starred rooms""" - response = get_rooms(member_id, org_id) + response = get_user_rooms(member_id, org_id) if response: data = [] for room in response: @@ -403,5 +480,3 @@ def update_queue_sync(queue_id: int): return response.json() else: return None - - diff --git a/backend/rooms.py b/backend/rooms.py index ba5f91cc3..687560dd4 100644 --- a/backend/rooms.py +++ b/backend/rooms.py @@ -54,7 +54,7 @@ def create_room(request, member_id): else: # print(" --------FAE------- \n\r") user_ids = serializer.data["room_member_ids"] - user_rooms = get_rooms(user_ids[0], DB.organization_id) + user_rooms = get_user_rooms(user_ids[0], DB.organization_id) if isinstance(user_rooms, list): for room in user_rooms: room_users = room["room_user_ids"] @@ -129,8 +129,8 @@ def user_rooms(request, user_id): if there is no room for the user_id it returns a 204 status response. """ if request.method == "GET": - res = get_rooms(user_id, DB.organization_id) - if res == None: + res = get_user_rooms(user_id, DB.organization_id) + if res is None: return Response( data="No rooms available", status=status.HTTP_204_NO_CONTENT ) @@ -162,7 +162,7 @@ def room_info(request, room_id): room_collection = "dm_rooms" current_room = DB.read(room_collection, {"_id": room_id}) - if current_room and current_room.get("status_code", None) == None: + if current_room and current_room.get("status_code", None) is None: if "room_user_ids" in current_room: room_user_ids = current_room["room_user_ids"] @@ -170,33 +170,14 @@ def room_info(request, room_id): room_user_ids = current_room["room_member_ids"] else: room_user_ids = "" - if "starred" in current_room: - starred = current_room["starred"] - else: - starred = "" - if "pinned" in current_room: - pinned = current_room["pinned"] - else: - pinned = "" - if "bookmark" in current_room: - bookmark = current_room["bookmark"] - else: - bookmark = "" - if "private" in current_room: - private = current_room["private"] - else: - private = "" - if "created_at" in current_room: - created_at = current_room["created_at"] - else: - created_at = "" + starred = current_room.get("starred","") + pinned = current_room.get("pinned","") + bookmark = current_room.get("bookmark","") + private = current_room.get("private","") + created_at = current_room.get("created_at","") if "org_id" in current_room: org_id = current_room["org_id"] - if "room_name" in current_room: - room_name = current_room["room_name"] - else: - room_name = "" - + room_name = current_room.get("room_name","") if len(room_user_ids) > 3: text = f" and {len(room_user_ids)-2} others" elif len(room_user_ids) == 3: @@ -301,9 +282,9 @@ def star_room(request, room_id, member_id): response = DB.update("dm_rooms", room_id,{"starred":data}) - if response and response.get("status_code",None) == None: + if response and response.get("status_code", None) is None: response_output = sidebar_emitter(org_id=DB.organization_id, member_id=member_id) - + try: centrifugo_data = centrifugo_client.publish ( room=f"{DB.organization_id}_{member_id}_sidebar", data=response_output ) # publish data to centrifugo @@ -396,7 +377,7 @@ def group_member_add(request, room_id, member_id): # ===================================================== # ===================================================== - user_rooms = get_rooms(room_creator, DB.organization_id) + user_rooms = get_user_rooms(room_creator, DB.organization_id) if user_rooms and isinstance(user_rooms, list): for room in user_rooms: room_users = room["room_user_ids"] @@ -483,7 +464,6 @@ def group_member_add(request, room_id, member_id): }, ) @api_view(["PUT"]) -#@db_init_with_credentials def close_conversation(request, org_id, room_id, member_id): """ This function allows for the Closing of a DM room on the sidebar diff --git a/backend/threads.py b/backend/threads.py index c9ed4334d..65f952d80 100644 --- a/backend/threads.py +++ b/backend/threads.py @@ -575,7 +575,7 @@ def get_all_threads(request, member_id: str): threads_list = LifoQueue() # org_id = request.GET.get("") - rooms = get_rooms(user_id=member_id, org_id=DB.organization_id) + rooms = get_user_rooms(user_id=member_id, org_id=DB.organization_id) if rooms: # print(f"the room ", rooms) for room in rooms: diff --git a/backend/urls.py b/backend/urls.py index 64d31e0d6..187170c39 100644 --- a/backend/urls.py +++ b/backend/urls.py @@ -19,7 +19,7 @@ path("api/v1/ping", views.PING, name="ping"), path("api/v1/info", views.info, name="plugin_info"), path("api/v1/install", views.dm_install, name="install"), - path("api/v1/sidebar", views.side_bar, name="sidebar"), + path("api/v1/sidebar", views.sidebar, name="sidebar"), path( "api/v1/org//users//room", rooms.create_room, diff --git a/backend/views.py b/backend/views.py index 9c35376ca..179df4c2f 100644 --- a/backend/views.py +++ b/backend/views.py @@ -116,74 +116,16 @@ def verify_user(token): # user_id will be gotten from the logged in user # All data in the message_rooms will be automatically generated from zuri core -@sync_to_async + + @api_view(['GET']) -def side_bar(request): +def sidebar(request): org_id = request.GET.get("org", None) DB.organization_id = org_id user_id = request.GET.get("user", None) - rooms = [] - starred_rooms = [] - user_rooms = get_rooms(user_id, org_id) - members = get_all_organization_members(org_id) - - if user_rooms != None: - for room in user_rooms: - room_profile = {} - if len(room['room_user_ids']) == 2: - room_profile["room_id"] = room["_id"] - room_profile["room_url"] = f"/dm/{room['_id']}" - user_id_set = set(room['room_user_ids']).difference({user_id}) - partner_id = list(user_id_set)[0] - - profile = get_member(members,partner_id) - - if "user_name" in profile and profile['user_name'] != "": - if profile["user_name"]: - room_profile["room_name"] = profile["user_name"] - else: - room_profile["room_name"] = "no user name" - if profile["image_url"]: - room_profile["room_image"] = profile["image_url"] - else: - room_profile[ - "room_image" - ] = "https://cdn.iconscout.com/icon/free/png-256/account-avatar-profile-human-man-user-30448.png" - - else: - room_profile["room_name"] = "no user name" - room_profile[ - "room_image" - ] = "https://cdn.iconscout.com/icon/free/png-256/account-avatar-profile-human-man-user-30448.png" - else: - room_profile["room_name"] = room["room_name"] - room_profile["room_id"] = room["_id"] - room_profile["room_url"] = f"/dm/{room['_id']}" - room_profile[ - "room_image" - ] = "https://cdn.iconscout.com/icon/free/png-256/account-avatar-profile-human-man-user-30448.png" - - rooms.append(room_profile) - if user_id in room["starred"]: - starred_rooms.append(room_profile) - - side_bar = { - "name": "DM Plugin", - "description": "Sends messages between users", - "plugin_id": "dm.zuri.chat", - "organisation_id": f"{org_id}", - "user_id": f"{user_id}", - "group_name": "DM", - "category": "direct messages", - "show_group": False, - "button_url": f"/dm", - "public_rooms": [], - "starred_rooms": starred_rooms, - "joined_rooms": rooms, - # List of rooms/collections created whenever a user starts a DM chat with another user - # This is what will be displayed by Zuri Main - } - return Response(side_bar, status=status.HTTP_200_OK) + + sidebar = sidebar_emitter(org_id, user_id) + return Response(sidebar, status=status.HTTP_200_OK) @swagger_auto_schema( @@ -345,7 +287,7 @@ def send_reply(request, room_id, message_id): print(request) serializer = MessageSerializer(data=request.data) reply_response = DB.read("dm_messages", {"_id": message_id}) - if reply_response and reply_response.get("status_code", None) == None: + if reply_response and reply_response.get("status_code", None) is None: replied_message = reply_response else: return Response( @@ -359,7 +301,7 @@ def send_reply(request, room_id, message_id): room_id = data["room_id"] # room id gotten from client request room = DB.read("dm_rooms", {"_id": room_id}) - if room and room.get("status_code", None) == None: + if room and room.get("status_code", None) is None: if data["sender_id"] in room.get("room_user_ids", []): data["replied_message"] = replied_message response = DB.write("dm_messages", data=data) diff --git a/dmspa/src/index.ejs b/dmspa/src/index.ejs index 46a19cd38..3e9377f88 100644 --- a/dmspa/src/index.ejs +++ b/dmspa/src/index.ejs @@ -38,10 +38,10 @@ "single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/system/single-spa.min.js", "@zuri/zuri-plugin-dm": "//dm.zuri.chat/static/zuri-zuri-plugin-dm.js", "@zuri/root-config": "//dm.zuri.chat/static/zuri-root-config.js", - "@zuri/utilities": "https://zuri.chat/zuri-utilities.js", + "@zuri/utilities": "https://staging.zuri.chat/zuri-utilities.js", "react": "https://cdn.jsdelivr.net/npm/react@16.13.1/umd/react.production.min.js", "react-dom": "https://cdn.jsdelivr.net/npm/react-dom@16.13.1/umd/react-dom.production.min.js", - "@zuri/plugin-header": "https://zuri.chat/zuri-plugin-header.js" + "@zuri/plugin-header": "https://staging.zuri.chat/zuri-plugin-header.js" } } @@ -61,11 +61,11 @@ "single-spa": "https://cdn.jsdelivr.net/npm/single-spa@5.9.0/lib/system/single-spa.min.js", "@zuri/zuri-plugin-dm": "//localhost:8080/zuri-zuri-plugin-dm.js", "@zuri/root-config": "//localhost:9000/zuri-root-config.js", - "@zuri/utilities": "https://zuri.chat/zuri-utilities.js", + "@zuri/utilities": "https://staging.zuri.chat/zuri-utilities.js", "react": "https://cdn.jsdelivr.net/npm/react@16.13.1/umd/react.development.js", "react-dom": "https://cdn.jsdelivr.net/npm/react-dom@16.13.1/umd/react-dom.development.js", - "@zuri/plugin-header": "https://zuri.chat/zuri-plugin-header.js", - "@zuri/zuri-ui": "https://zuri.chat/zuri-zuri-ui.js" + "@zuri/plugin-header": "https://staging.zuri.chat/zuri-plugin-header.js", + "@zuri/zuri-ui": "https://staging.zuri.chat/zuri-zuri-ui.js" } } diff --git a/requirements.txt b/requirements.txt index 5ddde85b5..b24066f68 100644 Binary files a/requirements.txt and b/requirements.txt differ