import json import logging import time import uuid from models.chat import Chat, ChatUpdate from services.auth import login_required from services.presence import notify_chat from services.rediscache import redis from services.schema import mutation logger = logging.getLogger("[resolvers.chats] ") logger.setLevel(logging.DEBUG) @mutation.field("update_chat") @login_required async def update_chat(_, info, chat_new: ChatUpdate): """ updating chat requires info.context["author_id"] to be in chat["admins"] :param _: not used :param info: GraphQLInfo with request :param chat_new: dict with chat data :return: Result { error chat } """ logger.info("update_chat") author_id = info.context["author_id"] chat_id = chat_new["id"] chat_str = await redis.execute("GET", f"chats/{chat_id}") if not chat_str: return {"error": "chat not exist"} elif isinstance(chat_str, str): chat: Chat = json.loads(chat_str) if author_id in chat["admins"]: chat.update( { "title": chat_new.get("title", chat["title"]), "description": chat_new.get("description", chat["description"]), "updated_at": int(time.time()), "admins": chat_new.get("admins", chat.get("admins") or []), "members": chat_new.get("members", chat["members"]), } ) await redis.execute("SET", f"chats/{chat['id']}", json.dumps(chat)) for member_id in chat["members"]: await notify_chat(chat, member_id, "update") return {"error": None, "chat": chat} @mutation.field("create_chat") @login_required async def create_chat(_, info, title="", members=None): logger.info("create_chat") members = members or [] author_id = info.context["author_id"] chat: Chat if author_id: if author_id not in members: members.append(int(author_id)) # NOTE: private chats has no title # reuse private chat created before if exists if len(members) == 2 and title == "": chatset1 = await redis.execute("SMEMBERS", f"chats_by_author/{members[0]}") chatset2 = await redis.execute("SMEMBERS", f"chats_by_author/{members[1]}") for c in chatset1.intersection(chatset2): chat = await redis.execute("GET", f"chats/{c}") if chat["title"] == "": logger.info("[inbox] createChat found old chat") return {"chat": chat, "error": "existed"} chat_id = str(uuid.uuid4()) chat: Chat = { "id": chat_id, "members": members, "title": title, "description": "", "created_by": author_id, "created_at": int(time.time()), "updated_at": int(time.time()), "admins": members if (len(members) == 2 and title == "") else [], } for member_id in members: await redis.execute("SADD", f"chats_by_author/{member_id}", chat_id) await notify_chat(chat, member_id, "create") print(f"\n\n[resolvers.chats] creating: {chat}\n\n") await redis.execute("SET", f"chats/{chat_id}", json.dumps(chat)) await redis.execute("SET", f"chats/{chat_id}/next_message_id", str(0)) return {"error": None, "chat": chat} return {"error": "no chat was created"} @mutation.field("delete_chat") @login_required async def delete_chat(_, info, chat_id: str): logger.info("delete_chat") author_id = info.context["author_id"] chat_str = await redis.execute("GET", f"chats/{chat_id}") if isinstance(chat_str, str): chat: Chat = json.loads(chat_str) if author_id in chat["admins"]: await redis.execute("DEL", f"chats/{chat_id}") await redis.execute("SREM", f"chats_by_author/{author_id}", chat_id) for member_id in chat["members"]: await notify_chat(chat, member_id, "delete") return {"error": "chat not exist"}