Вынес список участников чата в отдельную таблицу
This commit is contained in:
parent
2cf18b878a
commit
ef512b060f
|
|
@ -13,6 +13,6 @@ class SQLQueries:
|
||||||
|
|
||||||
INSERT_USER_DATA = """
|
INSERT_USER_DATA = """
|
||||||
INSERT INTO user_data
|
INSERT INTO user_data
|
||||||
(phone, chats, contacts, folders, user_config, chat_config)
|
(phone, contacts, folders, user_config, chat_config)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s, %s)
|
||||||
"""
|
"""
|
||||||
|
|
@ -136,7 +136,7 @@ class Tools:
|
||||||
)
|
)
|
||||||
|
|
||||||
# Формируем список участников с временем последней активности
|
# Формируем список участников с временем последней активности
|
||||||
participant_ids = json.loads(row.get("participants"))
|
participant_ids = await self.get_chat_participants(chatId, db_pool)
|
||||||
participants = await self.get_participant_last_activity(
|
participants = await self.get_participant_last_activity(
|
||||||
chatId, participant_ids, db_pool
|
chatId, participant_ids, db_pool
|
||||||
)
|
)
|
||||||
|
|
@ -171,6 +171,7 @@ class Tools:
|
||||||
|
|
||||||
# Получаем ID предыдущего сообщения для избранного (чат ID = senderId)
|
# Получаем ID предыдущего сообщения для избранного (чат ID = senderId)
|
||||||
prevMessageId = await self.get_previous_message_id(senderId, db_pool)
|
prevMessageId = await self.get_previous_message_id(senderId, db_pool)
|
||||||
|
|
||||||
# Хардкодим в лист чатов избранное
|
# Хардкодим в лист чатов избранное
|
||||||
chats.append(
|
chats.append(
|
||||||
self.generate_chat(
|
self.generate_chat(
|
||||||
|
|
@ -195,17 +196,17 @@ class Tools:
|
||||||
|
|
||||||
row = await cursor.fetchone() or {}
|
row = await cursor.fetchone() or {}
|
||||||
last_message_id = row.get("id") or 0 # последнее id сообщения в чате
|
last_message_id = row.get("id") or 0 # последнее id сообщения в чате
|
||||||
|
message_id = self.generate_id()
|
||||||
|
message_time = int(time.time() * 1000) # время отправки сообщения
|
||||||
|
|
||||||
# Вносим новое сообщение в таблицу
|
# Вносим новое сообщение в таблицу
|
||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
"INSERT INTO `messages` (chat_id, sender, time, text, attaches, cid, elements, type) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)",
|
"INSERT INTO `messages` (id, chat_id, sender, time, text, attaches, cid, elements, type) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)",
|
||||||
(chatId, senderId, int(time.time() * 1000), text, json.dumps(attaches), cid, json.dumps(elements), type)
|
(message_id, chatId, senderId, message_time, text, json.dumps(attaches), cid, json.dumps(elements), type)
|
||||||
)
|
)
|
||||||
|
|
||||||
message_id = cursor.lastrowid # id сообщения
|
|
||||||
|
|
||||||
# Возвращаем айдишки
|
# Возвращаем айдишки
|
||||||
return int(message_id), int(last_message_id)
|
return int(message_id), int(last_message_id), message_time
|
||||||
|
|
||||||
async def get_last_message(self, chatId, db_pool):
|
async def get_last_message(self, chatId, db_pool):
|
||||||
"""Получение последнего сообщения в чате"""
|
"""Получение последнего сообщения в чате"""
|
||||||
|
|
@ -284,11 +285,22 @@ class Tools:
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
async def get_chat_participants(self, chatId, db_pool):
|
||||||
|
"""Возвращает список ID участников чата из таблицы chat_participants."""
|
||||||
|
async with db_pool.acquire() as db_connection:
|
||||||
|
async with db_connection.cursor() as cursor:
|
||||||
|
await cursor.execute(
|
||||||
|
"SELECT user_id FROM chat_participants WHERE chat_id = %s",
|
||||||
|
(chatId,)
|
||||||
|
)
|
||||||
|
rows = await cursor.fetchall()
|
||||||
|
return [row["user_id"] for row in rows]
|
||||||
|
|
||||||
async def auth_required(self, userPhone, coro, *args):
|
async def auth_required(self, userPhone, coro, *args):
|
||||||
if userPhone:
|
if userPhone:
|
||||||
await coro(*args)
|
await coro(*args)
|
||||||
|
|
||||||
def generate_user_id(self):
|
def generate_id(self):
|
||||||
# Получаем время в юниксе
|
# Получаем время в юниксе
|
||||||
timestamp = int(time.time())
|
timestamp = int(time.time())
|
||||||
|
|
||||||
|
|
@ -300,4 +312,4 @@ class Tools:
|
||||||
unique_id = int(hashlib.md5(combined).hexdigest(), 16) % 1000000000
|
unique_id = int(hashlib.md5(combined).hexdigest(), 16) % 1000000000
|
||||||
|
|
||||||
# Возвращаем
|
# Возвращаем
|
||||||
return unique_id
|
return unique_id
|
||||||
|
|
|
||||||
|
|
@ -126,4 +126,8 @@ class AuthConfirmRegisterPayloadModel(pydantic.BaseModel):
|
||||||
|
|
||||||
class ChatHistoryPayloadModel(pydantic.BaseModel):
|
class ChatHistoryPayloadModel(pydantic.BaseModel):
|
||||||
chatId: int
|
chatId: int
|
||||||
backward: int
|
backward: int
|
||||||
|
|
||||||
|
class ChatSubscribePayloadModel(pydantic.BaseModel):
|
||||||
|
chatId: int
|
||||||
|
subscribe: bool
|
||||||
|
|
@ -365,8 +365,8 @@ class Processors:
|
||||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
self.tools.generate_user_id(), phone, None, first_name, last_name, None,
|
self.tools.generate_id(), phone, None, first_name, last_name, None,
|
||||||
json.dumps([]), json.dumps(["ONEME"]),
|
json.dumps([]), json.dumps(["TT", "ONEME"]),
|
||||||
0, str(now_ms), str(now_s),
|
0, str(now_ms), str(now_s),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -377,12 +377,12 @@ class Processors:
|
||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO user_data
|
INSERT INTO user_data
|
||||||
(phone, chats, contacts, folders, user_config, chat_config)
|
(phone, contacts, folders, user_config, chat_config)
|
||||||
VALUES (%s, %s, %s, %s, %s, %s)
|
VALUES (%s %s, %s, %s, %s)
|
||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
phone,
|
phone,
|
||||||
json.dumps([]), json.dumps([]),
|
json.dumps([]),
|
||||||
json.dumps(self.static.USER_FOLDERS),
|
json.dumps(self.static.USER_FOLDERS),
|
||||||
json.dumps(self.static.USER_SETTINGS),
|
json.dumps(self.static.USER_SETTINGS),
|
||||||
json.dumps({}),
|
json.dumps({}),
|
||||||
|
|
@ -442,6 +442,9 @@ class Processors:
|
||||||
await self._send_error(seq, self.opcodes.LOGIN, self.error_types.INVALID_PAYLOAD, writer)
|
await self._send_error(seq, self.opcodes.LOGIN, self.error_types.INVALID_PAYLOAD, writer)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Чаты, где состоит пользователь
|
||||||
|
chats = []
|
||||||
|
|
||||||
# Получаем данные из пакета
|
# Получаем данные из пакета
|
||||||
token = payload.get("token")
|
token = payload.get("token")
|
||||||
|
|
||||||
|
|
@ -467,6 +470,18 @@ class Processors:
|
||||||
await cursor.execute("SELECT * FROM user_data WHERE phone = %s", (token_data.get("phone"),))
|
await cursor.execute("SELECT * FROM user_data WHERE phone = %s", (token_data.get("phone"),))
|
||||||
user_data = await cursor.fetchone()
|
user_data = await cursor.fetchone()
|
||||||
|
|
||||||
|
# Ищем все чаты, где состоит пользователь
|
||||||
|
await cursor.execute(
|
||||||
|
"SELECT * FROM chat_participants WHERE user_id = %s",
|
||||||
|
(user.get('id'))
|
||||||
|
)
|
||||||
|
user_chats = await cursor.fetchall()
|
||||||
|
|
||||||
|
for chat in user_chats:
|
||||||
|
chats.append(
|
||||||
|
chat.get("chat_id")
|
||||||
|
)
|
||||||
|
|
||||||
# Аватарка с биографией
|
# Аватарка с биографией
|
||||||
photoId = None if not user.get("avatar_id") else int(user.get("avatar_id"))
|
photoId = None if not user.get("avatar_id") else int(user.get("avatar_id"))
|
||||||
avatar_url = None if not photoId else self.config.avatar_base_url + photoId
|
avatar_url = None if not photoId else self.config.avatar_base_url + photoId
|
||||||
|
|
@ -490,8 +505,7 @@ class Processors:
|
||||||
)
|
)
|
||||||
|
|
||||||
chats = await self.tools.generate_chats(
|
chats = await self.tools.generate_chats(
|
||||||
json.loads(user_data.get("chats")),
|
chats, self.db_pool, user.get("id")
|
||||||
self.db_pool, user.get("id")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Формируем данные пакета
|
# Формируем данные пакета
|
||||||
|
|
@ -511,6 +525,10 @@ class Processors:
|
||||||
"time": int(time.time() * 1000)
|
"time": int(time.time() * 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print(
|
||||||
|
json.dumps(payload, indent=4)
|
||||||
|
)
|
||||||
|
|
||||||
# Собираем пакет
|
# Собираем пакет
|
||||||
packet = self.proto.pack_packet(
|
packet = self.proto.pack_packet(
|
||||||
cmd=self.proto.CMD_OK, seq=seq, opcode=self.opcodes.LOGIN, payload=payload
|
cmd=self.proto.CMD_OK, seq=seq, opcode=self.opcodes.LOGIN, payload=payload
|
||||||
|
|
@ -609,9 +627,6 @@ class Processors:
|
||||||
cid = message.get("cid") or 0
|
cid = message.get("cid") or 0
|
||||||
text = message.get("text") or ""
|
text = message.get("text") or ""
|
||||||
|
|
||||||
# Время отправки сообщения
|
|
||||||
messageTime = int(time.time() * 1000)
|
|
||||||
|
|
||||||
# Вычисляем ID чата по ID пользователя и ID отправителя,
|
# Вычисляем ID чата по ID пользователя и ID отправителя,
|
||||||
# в случае отсутствия ID чата
|
# в случае отсутствия ID чата
|
||||||
if not chatId:
|
if not chatId:
|
||||||
|
|
@ -637,7 +652,7 @@ class Processors:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Список участников
|
# Список участников
|
||||||
participants = json.loads(chat.get("participants"))
|
participants = await self.tools.get_chat_participants(chatId, db_pool)
|
||||||
|
|
||||||
# Проверяем, является ли отправитель участником чата
|
# Проверяем, является ли отправитель участником чата
|
||||||
if int(senderId) not in participants:
|
if int(senderId) not in participants:
|
||||||
|
|
@ -645,7 +660,7 @@ class Processors:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Добавляем сообщение в историю
|
# Добавляем сообщение в историю
|
||||||
messageId, lastMessageId = await self.tools.insert_message(
|
messageId, lastMessageId, messageTime = await self.tools.insert_message(
|
||||||
chatId=chatId,
|
chatId=chatId,
|
||||||
senderId=senderId,
|
senderId=senderId,
|
||||||
text=text,
|
text=text,
|
||||||
|
|
@ -854,10 +869,10 @@ class Processors:
|
||||||
|
|
||||||
if chat:
|
if chat:
|
||||||
# Проверяем, является ли пользователь участником чата
|
# Проверяем, является ли пользователь участником чата
|
||||||
|
participants = await self.tools.get_chat_participants(chatId, self.db_pool)
|
||||||
# (в max нельзя смотреть и отправлять сообщения в чат, в котором ты не участник, в отличие от tg (например, комментарии в каналах),
|
# (в max нельзя смотреть и отправлять сообщения в чат, в котором ты не участник, в отличие от tg (например, комментарии в каналах),
|
||||||
# так что надо тоже так делать)
|
# так что надо тоже так делать)
|
||||||
if senderId not in json.loads(chat.get("participants")):
|
if int(senderId) not in participants:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Получаем последнее сообщение из чата
|
# Получаем последнее сообщение из чата
|
||||||
|
|
@ -868,8 +883,8 @@ class Processors:
|
||||||
# Добавляем чат в список
|
# Добавляем чат в список
|
||||||
chats.append(
|
chats.append(
|
||||||
self.tools.generate_chat(
|
self.tools.generate_chat(
|
||||||
chatId, chat.get("owner"),
|
chatId, chat.get("owner"),
|
||||||
chat.get("type"), json.loads(chat.get("participants")),
|
chat.get("type"), participants,
|
||||||
message, messageTime
|
message, messageTime
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -935,10 +950,19 @@ class Processors:
|
||||||
# Если диалога нет - создаем
|
# Если диалога нет - создаем
|
||||||
if not chat:
|
if not chat:
|
||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
"INSERT INTO chats (id, owner, type, participants) VALUES (%s, %s, %s, %s)",
|
"INSERT INTO chats (id, owner, type) VALUES (%s, %s, %s)",
|
||||||
(chatId, senderId, "DIALOG", json.dumps([int(senderId), int(user.get("id"))]))
|
(chatId, senderId, "DIALOG")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Добавляем участников в таблицу chat_participants
|
||||||
|
participants = [int(senderId), int(user.get("id"))]
|
||||||
|
|
||||||
|
for user_id in participants:
|
||||||
|
await cursor.execute(
|
||||||
|
"INSERT INTO chat_participants (chat_id, user_id) VALUES (%s, %s)",
|
||||||
|
(chatId, user_id)
|
||||||
|
)
|
||||||
|
|
||||||
# Аватарка с биографией
|
# Аватарка с биографией
|
||||||
photoId = None if not user.get("avatar_id") else int(user.get("avatar_id"))
|
photoId = None if not user.get("avatar_id") else int(user.get("avatar_id"))
|
||||||
avatar_url = None if not photoId else self.config.avatar_base_url + photoId
|
avatar_url = None if not photoId else self.config.avatar_base_url + photoId
|
||||||
|
|
@ -1014,7 +1038,7 @@ class Processors:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Участники чата
|
# Участники чата
|
||||||
participants = json.loads(chat.get("participants"))
|
participants = await self.tools.get_chat_participants(chatId, self.db_pool)
|
||||||
|
|
||||||
# Проверяем, является ли отправитель участником чата
|
# Проверяем, является ли отправитель участником чата
|
||||||
if int(senderId) not in participants:
|
if int(senderId) not in participants:
|
||||||
|
|
@ -1105,7 +1129,7 @@ class Processors:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Проверяем, является ли пользователь участником чата
|
# Проверяем, является ли пользователь участником чата
|
||||||
participants = json.loads(chat.get("participants"))
|
participants = await self.tools.get_chat_participants(chatId, self.db_pool)
|
||||||
if int(senderId) not in participants:
|
if int(senderId) not in participants:
|
||||||
await self._send_error(seq, self.opcodes.CHAT_HISTORY, self.error_types.CHAT_NOT_ACCESS, writer)
|
await self._send_error(seq, self.opcodes.CHAT_HISTORY, self.error_types.CHAT_NOT_ACCESS, writer)
|
||||||
return
|
return
|
||||||
|
|
@ -1241,4 +1265,20 @@ class Processors:
|
||||||
"eventType": "profile_updated",
|
"eventType": "profile_updated",
|
||||||
"profile": profile
|
"profile": profile
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def chat_subscribe(self, payload, seq, writer):
|
||||||
|
# Валидируем входные данные
|
||||||
|
try:
|
||||||
|
ChatSubscribePayloadModel.model_validate(payload)
|
||||||
|
except Exception as e:
|
||||||
|
await self._send_error(seq, self.opcodes.CHAT_SUBSCRIBE, self.error_types.INVALID_PAYLOAD, writer)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Созадаем пакет
|
||||||
|
packet = self.proto.pack_packet(
|
||||||
|
cmd=self.proto.CMD_OK, seq=seq, opcode=self.opcodes.CHAT_SUBSCRIBE, payload=None
|
||||||
|
)
|
||||||
|
|
||||||
|
# Отправялем
|
||||||
|
await self._send(writer, packet)
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,10 @@ class OnemeMobileServer:
|
||||||
await self.processors.profile(
|
await self.processors.profile(
|
||||||
payload, seq, writer, userId=userId, userPhone=userPhone
|
payload, seq, writer, userId=userId, userPhone=userPhone
|
||||||
)
|
)
|
||||||
|
case self.opcodes.CHAT_SUBSCRIBE:
|
||||||
|
await self.auth_required(
|
||||||
|
userPhone, self.processors.chat_subscribe, payload, seq, writer
|
||||||
|
)
|
||||||
case _:
|
case _:
|
||||||
self.logger.warning(f"Неизвестный опкод {opcode}")
|
self.logger.warning(f"Неизвестный опкод {opcode}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ class TelegramBot:
|
||||||
await cursor.execute(
|
await cursor.execute(
|
||||||
self.sql_queries.INSERT_USER,
|
self.sql_queries.INSERT_USER,
|
||||||
(
|
(
|
||||||
self.tools.generate_user_id(),
|
self.tools.generate_id(),
|
||||||
new_phone, # phone
|
new_phone, # phone
|
||||||
tg_id, # telegram_id
|
tg_id, # telegram_id
|
||||||
message.from_user.first_name[:59], # firstname
|
message.from_user.first_name[:59], # firstname
|
||||||
|
|
@ -93,7 +93,6 @@ class TelegramBot:
|
||||||
self.sql_queries.INSERT_USER_DATA,
|
self.sql_queries.INSERT_USER_DATA,
|
||||||
(
|
(
|
||||||
new_phone, # phone
|
new_phone, # phone
|
||||||
json.dumps([]), # chats
|
|
||||||
json.dumps([]), # contacts
|
json.dumps([]), # contacts
|
||||||
json.dumps(self.static.USER_FOLDERS), # folders
|
json.dumps(self.static.USER_FOLDERS), # folders
|
||||||
json.dumps(self.static.USER_SETTINGS), # user settings
|
json.dumps(self.static.USER_SETTINGS), # user settings
|
||||||
|
|
|
||||||
15
tables.sql
15
tables.sql
|
|
@ -34,7 +34,6 @@ CREATE TABLE `auth_tokens` (
|
||||||
|
|
||||||
CREATE TABLE `user_data` (
|
CREATE TABLE `user_data` (
|
||||||
`phone` VARCHAR(20) NOT NULL UNIQUE PRIMARY KEY,
|
`phone` VARCHAR(20) NOT NULL UNIQUE PRIMARY KEY,
|
||||||
`chats` JSON NOT NULL,
|
|
||||||
`contacts` JSON NOT NULL,
|
`contacts` JSON NOT NULL,
|
||||||
`folders` JSON NOT NULL,
|
`folders` JSON NOT NULL,
|
||||||
`user_config` JSON NOT NULL,
|
`user_config` JSON NOT NULL,
|
||||||
|
|
@ -44,12 +43,11 @@ CREATE TABLE `user_data` (
|
||||||
CREATE TABLE `chats` (
|
CREATE TABLE `chats` (
|
||||||
`id` INT NOT NULL PRIMARY KEY,
|
`id` INT NOT NULL PRIMARY KEY,
|
||||||
`owner` INT NOT NULL,
|
`owner` INT NOT NULL,
|
||||||
`type` VARCHAR(16) NOT NULL,
|
`type` VARCHAR(16) NOT NULL
|
||||||
`participants` JSON NOT NULL
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE `messages` (
|
CREATE TABLE `messages` (
|
||||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
`id` INT NOT NULL PRIMARY KEY,
|
||||||
`chat_id` INT NOT NULL,
|
`chat_id` INT NOT NULL,
|
||||||
`sender` INT NOT NULL,
|
`sender` INT NOT NULL,
|
||||||
`time` VARCHAR(32) NOT NULL,
|
`time` VARCHAR(32) NOT NULL,
|
||||||
|
|
@ -58,4 +56,11 @@ CREATE TABLE `messages` (
|
||||||
`cid` VARCHAR(32) NOT NULL,
|
`cid` VARCHAR(32) NOT NULL,
|
||||||
`elements` JSON NOT NULL,
|
`elements` JSON NOT NULL,
|
||||||
`type` VARCHAR(16) NOT NULL
|
`type` VARCHAR(16) NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE `chat_participants` (
|
||||||
|
`chat_id` INT NOT NULL,
|
||||||
|
`user_id` INT NOT NULL,
|
||||||
|
`joined_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`chat_id`, `user_id`)
|
||||||
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue