Update files
This commit is contained in:
parent
d278329ba6
commit
4f0f7bc3b7
|
|
@ -92,3 +92,7 @@ def admin_confirmations_collection():
|
|||
def notifications_collection():
|
||||
return get_collection('notifications')
|
||||
|
||||
|
||||
def moderation_chat_messages_collection():
|
||||
return get_collection('moderationchatmessages')
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,19 @@ async def get_users(
|
|||
query = {}
|
||||
|
||||
if filter == 'active':
|
||||
# Активные пользователи: не забанены И активны за последние 7 дней
|
||||
seven_days_ago = datetime.utcnow() - timedelta(days=7)
|
||||
query['banned'] = {'$ne': True}
|
||||
query['lastActiveAt'] = {'$gte': seven_days_ago}
|
||||
elif filter == 'inactive':
|
||||
# Неактивные пользователи: не забанены И не активны более 7 дней
|
||||
seven_days_ago = datetime.utcnow() - timedelta(days=7)
|
||||
query['banned'] = {'$ne': True}
|
||||
query['$or'] = [
|
||||
{'lastActiveAt': {'$lt': seven_days_ago}},
|
||||
{'lastActiveAt': None},
|
||||
{'lastActiveAt': {'$exists': False}}
|
||||
]
|
||||
elif filter == 'banned':
|
||||
query['banned'] = True
|
||||
# 'all' - no filter
|
||||
|
|
@ -49,18 +61,50 @@ async def get_users(
|
|||
# Serialize users
|
||||
serialized_users = []
|
||||
for u in users:
|
||||
# Проверяем, является ли пользователь админом модерации
|
||||
is_admin = False
|
||||
if u.get('telegramId'):
|
||||
admin = await moderation_admins_collection().find_one({
|
||||
'telegramId': str(u.get('telegramId'))
|
||||
})
|
||||
is_admin = admin is not None
|
||||
|
||||
# Обработка дат
|
||||
banned_until = None
|
||||
if u.get('bannedUntil'):
|
||||
if isinstance(u.get('bannedUntil'), datetime):
|
||||
banned_until = u.get('bannedUntil').isoformat()
|
||||
else:
|
||||
banned_until = str(u.get('bannedUntil'))
|
||||
|
||||
created_at = datetime.utcnow().isoformat()
|
||||
if u.get('createdAt'):
|
||||
if isinstance(u.get('createdAt'), datetime):
|
||||
created_at = u.get('createdAt').isoformat()
|
||||
else:
|
||||
created_at = str(u.get('createdAt'))
|
||||
|
||||
last_active_at = None
|
||||
if u.get('lastActiveAt'):
|
||||
if isinstance(u.get('lastActiveAt'), datetime):
|
||||
last_active_at = u.get('lastActiveAt').isoformat()
|
||||
else:
|
||||
last_active_at = str(u.get('lastActiveAt'))
|
||||
|
||||
serialized_users.append({
|
||||
'id': str(u['_id']),
|
||||
'telegramId': u.get('telegramId'),
|
||||
'username': u.get('username'),
|
||||
'firstName': u.get('firstName'),
|
||||
'lastName': u.get('lastName'),
|
||||
'photoUrl': u.get('photoUrl'),
|
||||
'telegramId': str(u.get('telegramId')) if u.get('telegramId') else None,
|
||||
'username': u.get('username', ''),
|
||||
'firstName': u.get('firstName', ''),
|
||||
'lastName': u.get('lastName', ''),
|
||||
'photoUrl': u.get('photoUrl', ''),
|
||||
'role': u.get('role', 'user'),
|
||||
'banned': u.get('banned', False),
|
||||
'bannedUntil': u.get('bannedUntil').isoformat() if u.get('bannedUntil') else None,
|
||||
'createdAt': u.get('createdAt', datetime.utcnow()).isoformat(),
|
||||
'lastActiveAt': u.get('lastActiveAt').isoformat() if u.get('lastActiveAt') else None
|
||||
'banned': bool(u.get('banned', False)),
|
||||
'bannedUntil': banned_until,
|
||||
'createdAt': created_at,
|
||||
'lastActiveAt': last_active_at,
|
||||
'referralsCount': int(u.get('referralsCount', 0)),
|
||||
'isAdmin': is_admin
|
||||
})
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from typing import Dict, Set, Optional
|
|||
from datetime import datetime
|
||||
|
||||
from config import settings
|
||||
from database import moderation_admins_collection
|
||||
from database import moderation_admins_collection, moderation_chat_messages_collection
|
||||
from utils.auth import normalize_username
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -37,6 +37,9 @@ def broadcast_online():
|
|||
unique[username] = data
|
||||
|
||||
online_list = list(unique.values())
|
||||
# Broadcast в корневой namespace (так как клиенты подключаются туда)
|
||||
sio.emit('online', online_list)
|
||||
# Также broadcast в /mod-chat на случай, если кто-то подключится туда
|
||||
sio.emit('online', online_list, namespace='/mod-chat')
|
||||
|
||||
|
||||
|
|
@ -103,6 +106,31 @@ async def on_auth_root(sid, data):
|
|||
}
|
||||
|
||||
print(f"[WebSocket] ✅ Auth success в ROOT namespace: {username} (owner: {is_owner}, admin: {is_admin})")
|
||||
|
||||
# Загружаем историю сообщений (последние 100)
|
||||
try:
|
||||
history = await moderation_chat_messages_collection().find().sort('createdAt', -1).limit(100).to_list(length=100)
|
||||
# Переворачиваем, чтобы старые сообщения были первыми
|
||||
history.reverse()
|
||||
|
||||
# Форматируем сообщения для отправки
|
||||
history_messages = []
|
||||
for msg in history:
|
||||
history_messages.append({
|
||||
'id': str(msg.get('_id', '')),
|
||||
'username': msg.get('username', ''),
|
||||
'telegramId': msg.get('telegramId', ''),
|
||||
'text': msg.get('text', ''),
|
||||
'createdAt': msg.get('createdAt').isoformat() if isinstance(msg.get('createdAt'), datetime) else msg.get('createdAt', '')
|
||||
})
|
||||
|
||||
# Отправляем историю клиенту
|
||||
await sio.emit('history', history_messages, room=sid)
|
||||
print(f"[WebSocket] 📜 Sent {len(history_messages)} messages from history to {sid}")
|
||||
except Exception as e:
|
||||
print(f"[WebSocket] ⚠️ Failed to load message history: {e}")
|
||||
logger.error(f"[WebSocket] Failed to load message history: {e}")
|
||||
|
||||
await sio.emit('ready', room=sid)
|
||||
broadcast_online()
|
||||
|
||||
|
|
@ -113,6 +141,60 @@ async def on_auth_root(sid, data):
|
|||
await sio.emit('unauthorized', room=sid)
|
||||
await sio.disconnect(sid)
|
||||
|
||||
# Обработчик сообщений в корневом namespace
|
||||
@sio.on('message')
|
||||
async def on_message_root(sid, data):
|
||||
"""Handle moderation chat message in root namespace"""
|
||||
print(f"[WebSocket] 📨 Message в ROOT namespace от {sid}: {data}")
|
||||
try:
|
||||
if sid not in connected_moderators:
|
||||
print(f"[WebSocket] ⚠️ Message from unauthorized client: {sid}")
|
||||
logger.warning(f"[WebSocket] Message from unauthorized client: {sid}")
|
||||
return
|
||||
|
||||
user_data = connected_moderators[sid]
|
||||
text = (data.get('text') or '').strip()
|
||||
|
||||
if not text:
|
||||
return
|
||||
|
||||
message_id = f"{int(datetime.utcnow().timestamp() * 1000)}-{sid[:8]}"
|
||||
created_at = datetime.utcnow()
|
||||
|
||||
message = {
|
||||
'id': message_id,
|
||||
'username': user_data['username'],
|
||||
'telegramId': user_data['telegramId'],
|
||||
'text': text,
|
||||
'createdAt': created_at.isoformat()
|
||||
}
|
||||
|
||||
# Сохраняем сообщение в MongoDB
|
||||
try:
|
||||
await moderation_chat_messages_collection().insert_one({
|
||||
'_id': message_id,
|
||||
'username': user_data['username'],
|
||||
'telegramId': user_data['telegramId'],
|
||||
'text': text,
|
||||
'createdAt': created_at,
|
||||
'isOwner': user_data.get('isOwner', False)
|
||||
})
|
||||
print(f"[WebSocket] 💾 Message saved to DB: {message_id}")
|
||||
except Exception as e:
|
||||
print(f"[WebSocket] ⚠️ Failed to save message to DB: {e}")
|
||||
logger.error(f"[WebSocket] Failed to save message to DB: {e}")
|
||||
|
||||
# Broadcast to all in root namespace (без указания room - broadcast всем в namespace)
|
||||
await sio.emit('message', message)
|
||||
print(f"[WebSocket] ✅ Message broadcasted в ROOT namespace: {user_data['username']}: {text[:50]}...")
|
||||
logger.info(f"[WebSocket] Message from {user_data['username']} (ROOT): {text[:50]}...")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[WebSocket] ❌ Error handling message (ROOT): {e}")
|
||||
logger.error(f"[WebSocket] Error handling message (ROOT): {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
# Namespace handlers for /mod-chat
|
||||
@sio.on('connect', namespace='/mod-chat')
|
||||
async def on_connect(sid, environ):
|
||||
|
|
|
|||
|
|
@ -694,6 +694,15 @@ export default function App() {
|
|||
setChatState((prev) => ({ ...prev, connected: true }));
|
||||
});
|
||||
|
||||
socket.on('history', (messages) => {
|
||||
console.log(`[Chat] 📜 Получена история: ${messages.length} сообщений`);
|
||||
// Загружаем историю сообщений при подключении
|
||||
setChatState((prev) => ({
|
||||
...prev,
|
||||
messages: messages || []
|
||||
}));
|
||||
});
|
||||
|
||||
socket.on('unauthorized', () => {
|
||||
console.error('Unauthorized в чате');
|
||||
setChatState((prev) => ({ ...prev, connected: false }));
|
||||
|
|
|
|||
Loading…
Reference in New Issue