import json import time import uuid from models.chat import Chat, ChatUpdate from services.auth import login_required from services.core import get_all_authors from services.presence import notify_chat from services.rediscache import redis from services.schema import mutation @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 } """ 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"} else: 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): members = members or [] user_id = info.context["user_id"] authors_by_user, authors_by_id = get_all_authors() author = authors_by_user[user_id] author_id = author["id"] chat = None 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 = set((await redis.execute("SMEMBERS", f"chats_by_author/{members[0]}")) or []) chatset2 = set((await redis.execute("SMEMBERS", f"chats_by_author/{members[1]}")) or []) for c in chatset1.intersection(chatset2): chat_data = await redis.execute("GET", f"chats/{c}") if chat_data: chat = json.loads(chat_data) if chat["title"] == "": print("[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} @mutation.field("delete_chat") @login_required async def delete_chat(_, info, chat_id: str): author_id = info.context["author_id"] chat_str = await redis.execute("GET", f"chats/{chat_id}") if chat_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") else: return {"error": "chat not exist"}