175 lines
6.4 KiB
Python
175 lines
6.4 KiB
Python
"""Chat routes (messages, channels, servers, DMs)."""
|
|
import json
|
|
from flask import Blueprint, g, jsonify, request, current_app
|
|
from database import get_db
|
|
from decorators import token_required, get_user_badge
|
|
|
|
chat_bp = Blueprint('chat', __name__, url_prefix='/api')
|
|
|
|
|
|
def get_socketio():
|
|
"""Get SocketIO instance from current app context."""
|
|
return current_app.extensions.get('socketio')
|
|
|
|
|
|
@chat_bp.route('/messages', methods=['GET'])
|
|
@token_required
|
|
def get_messages():
|
|
"""Get messages from a channel or global chat."""
|
|
channel_id = request.args.get('channel_id', type=int)
|
|
db = get_db(current_app)
|
|
base_query = '''
|
|
SELECT m.id, m.sender_id, u.username, u.avatar_url, u.pronouns, m.content,
|
|
m.timestamp, m.channel_id, m.receiver_id, m.is_global, m.reply_to
|
|
FROM messages m
|
|
JOIN users u ON m.sender_id = u.id
|
|
'''
|
|
if channel_id:
|
|
query = base_query + ' WHERE m.channel_id = ? ORDER BY m.timestamp DESC LIMIT 50'
|
|
messages = db.execute(query, (channel_id,)).fetchall()
|
|
else:
|
|
query = base_query + ' WHERE m.is_global = 1 ORDER BY m.timestamp DESC LIMIT 50'
|
|
messages = db.execute(query).fetchall()
|
|
result = []
|
|
for m in messages:
|
|
msg_dict = dict(m)
|
|
msg_dict['badge'] = get_user_badge(m['username'])
|
|
result.append(msg_dict)
|
|
return jsonify([dict(m) for m in reversed(result)]), 200
|
|
|
|
|
|
@chat_bp.route('/messages', methods=['POST'])
|
|
@token_required
|
|
def post_message():
|
|
"""Post a message to global chat, channel, or DM."""
|
|
content = None
|
|
receiver_id = None
|
|
channel_id = None
|
|
reply_to = None
|
|
file_info = None
|
|
|
|
if request.content_type and request.content_type.startswith('multipart/form-data'):
|
|
content = request.form.get('content')
|
|
receiver_id = request.form.get('receiver_id', type=int)
|
|
channel_id = request.form.get('channel_id', type=int)
|
|
reply_to = request.form.get('reply_to', type=int)
|
|
if 'file' in request.files and request.files['file'].filename:
|
|
try:
|
|
from blueprints.files import process_file_upload
|
|
file_info = process_file_upload(request.files['file'], current_app)
|
|
except ValueError:
|
|
return jsonify({'error': "You can't upload big files, if you need more files, contact dev and buy your own disk space on server"}), 400
|
|
else:
|
|
data = request.json or {}
|
|
content = data.get('content')
|
|
receiver_id = data.get('receiver_id')
|
|
channel_id = data.get('channel_id')
|
|
reply_to = data.get('reply_to')
|
|
|
|
if file_info:
|
|
content = json.dumps({'file': file_info, 'text': content or ''})
|
|
if not content:
|
|
return jsonify({'error': 'Content required'}), 400
|
|
|
|
db = get_db(current_app)
|
|
is_global = 1 if (receiver_id is None and not channel_id) else 0
|
|
cur = db.execute(
|
|
'INSERT INTO messages (sender_id, receiver_id, channel_id, content, is_global, reply_to) VALUES (?, ?, ?, ?, ?, ?)',
|
|
(g.user['id'], receiver_id, channel_id, content, is_global, reply_to)
|
|
)
|
|
db.commit()
|
|
message_id = cur.lastrowid
|
|
message = db.execute('''
|
|
SELECT m.id, m.sender_id, u.username, u.avatar_url, u.pronouns, m.content,
|
|
m.timestamp, m.channel_id, m.receiver_id, m.is_global, m.reply_to
|
|
FROM messages m
|
|
JOIN users u ON m.sender_id = u.id
|
|
WHERE m.id = ?
|
|
''', (message_id,)).fetchone()
|
|
message_dict = dict(message)
|
|
message_dict['badge'] = get_user_badge(message['username'])
|
|
|
|
socketio = get_socketio()
|
|
if socketio:
|
|
socketio.emit('new_message', message_dict)
|
|
|
|
return jsonify({'id': message_id, 'status': 'sent'}), 201
|
|
|
|
|
|
@chat_bp.route('/servers', methods=['GET'])
|
|
@token_required
|
|
def get_servers():
|
|
"""Get all servers and their channels."""
|
|
db = get_db(current_app)
|
|
servers = db.execute('SELECT id, name FROM servers').fetchall()
|
|
result = []
|
|
for s in servers:
|
|
channels = db.execute('SELECT id, name FROM channels WHERE server_id = ?', (s['id'],)).fetchall()
|
|
result.append({
|
|
'id': s['id'],
|
|
'name': s['name'],
|
|
'channels': [{'id': c['id'], 'name': c['name']} for c in channels]
|
|
})
|
|
return jsonify(result), 200
|
|
|
|
|
|
@chat_bp.route('/servers', methods=['POST'])
|
|
@token_required
|
|
def create_server():
|
|
"""Create a new server."""
|
|
data = request.json
|
|
name = data.get('name')
|
|
if not name:
|
|
return jsonify({'error': 'Server name required'}), 400
|
|
db = get_db(current_app)
|
|
try:
|
|
cur = db.execute('INSERT INTO servers (name) VALUES (?)', (name,))
|
|
server_id = cur.lastrowid
|
|
db.execute('INSERT INTO channels (server_id, name) VALUES (?, ?)', (server_id, 'general'))
|
|
db.commit()
|
|
return jsonify({'id': server_id, 'name': name}), 201
|
|
except Exception:
|
|
return jsonify({'error': 'Server already exists'}), 409
|
|
|
|
|
|
@chat_bp.route('/servers/<int:server_id>/channels', methods=['POST'])
|
|
@token_required
|
|
def create_channel(server_id):
|
|
"""Create a new channel in a server."""
|
|
data = request.json
|
|
name = data.get('name')
|
|
if not name:
|
|
return jsonify({'error': 'Channel name required'}), 400
|
|
db = get_db(current_app)
|
|
cur = db.execute('INSERT INTO channels (server_id, name) VALUES (?, ?)', (server_id, name))
|
|
db.commit()
|
|
return jsonify({'id': cur.lastrowid, 'name': name}), 201
|
|
|
|
|
|
@chat_bp.route('/dm/<int:user_id>', methods=['GET'])
|
|
@token_required
|
|
def get_dm(user_id):
|
|
"""Get direct messages with a specific user."""
|
|
since = request.args.get('since')
|
|
db = get_db(current_app)
|
|
query = '''
|
|
SELECT m.id, m.sender_id, u.username, u.avatar_url, u.pronouns, m.content,
|
|
m.timestamp, m.channel_id, m.receiver_id, m.is_global, m.reply_to
|
|
FROM messages m
|
|
JOIN users u ON m.sender_id = u.id
|
|
WHERE m.is_global = 0 AND (
|
|
(m.sender_id = ? AND m.receiver_id = ?) OR
|
|
(m.sender_id = ? AND m.receiver_id = ?)
|
|
)
|
|
'''
|
|
params = [g.user['id'], user_id, user_id, g.user['id']]
|
|
if since:
|
|
query += ' AND m.timestamp > ?'
|
|
params.append(since)
|
|
query += ' ORDER BY m.timestamp DESC LIMIT 50'
|
|
messages = db.execute(query, tuple(params)).fetchall()
|
|
result = [dict(m) for m in messages]
|
|
for m in result:
|
|
m['badge'] = get_user_badge(m['username'])
|
|
return jsonify(list(reversed(result))), 200
|