from flask import Blueprint, request, jsonify, g from db.model import User, Enrollment, Chat, db import uuid from sqlalchemy import select, and_, desc from datetime import datetime chat = Blueprint('chat', __name__) @chat.route('//messages', methods=['GET']) def get_course_messages(course_id: uuid.UUID): """ Fetch chat messages for a specific course with optional pagination. Only enrolled users can access the messages. Query Parameters: - before: UUID of the message to get older entries - after: UUID of the message to get newer entries - limit: Number of messages to return (default: 10) """ try: current_user: User = g.current_user limit = int(request.args.get('limit', 10)) before_id = request.args.get('before') after_id = request.args.get('after') # Verify user's enrollment enrollment = db.session.execute( select(Enrollment).where( and_( Enrollment.courseID == course_id, Enrollment.userID == current_user.id ) ) ).scalar() if not enrollment: return jsonify({'message': 'You are not enrolled in this course'}), 401 # Base query query = select(Chat).where(Chat.courseID == course_id) # Handle pagination if before_id: try: reference_message = db.session.execute( select(Chat).where(Chat.id == uuid.UUID(before_id)) ).scalar() if not reference_message: return jsonify({'message': 'Reference message not found'}), 404 query = query.where(Chat.chatDate < reference_message.chatDate) except ValueError: return jsonify({'message': 'Invalid message ID format'}), 400 elif after_id: try: reference_message = db.session.execute( select(Chat).where(Chat.id == uuid.UUID(after_id)) ).scalar() if not reference_message: return jsonify({'message': 'Reference message not found'}), 404 query = query.where(Chat.chatDate > reference_message.chatDate) # For after queries, reverse the order later query = query.order_by(Chat.chatDate) except ValueError: return jsonify({'message': 'Invalid message ID format'}), 400 else: # Default ordering query = query.order_by(desc(Chat.chatDate)) # Apply limit and execute query query = query.limit(limit) messages = list(db.session.execute(query).scalars()) # Reverse the order for 'after' queries to maintain consistency if after_id: messages.reverse() # Format messages chat_messages = [{ 'id': str(msg.id), 'text': msg.textContent, 'userId': str(msg.userID), 'username': msg.user.username, 'timestamp': msg.chatDate.isoformat() } for msg in messages] return jsonify({ 'messages': chat_messages, 'count': len(chat_messages), 'hasMore': len(chat_messages) == limit }), 200 except Exception as e: return jsonify({'message': f'An error occurred: {str(e)}'}), 500 @chat.route('//send', methods=['POST']) def send_message(course_id: uuid.UUID): """ Send a new chat message in a course. Only enrolled users can send messages. """ try: current_user: User = g.current_user message_text = request.json.get('message') if not message_text or not message_text.strip(): return jsonify({'message': 'Message content is required'}), 400 # Verify user's enrollment enrollment = db.session.execute( select(Enrollment).where( and_( Enrollment.courseID == course_id, Enrollment.userID == current_user.id ) ) ).scalar() if not enrollment: return jsonify({'message': 'You are not enrolled in this course'}), 401 # Create new chat message new_message = Chat( textContent=message_text, userID=current_user.id, courseID=course_id, chatDate=datetime.now() ) db.session.add(new_message) # Update last activity in enrollment enrollment.lastActivity = datetime.now() db.session.commit() return jsonify({ 'message': 'Message sent successfully', 'messageId': str(new_message.id), 'timestamp': new_message.chatDate.isoformat() }), 201 except Exception as e: db.session.rollback() return jsonify({'message': f'An error occurred: {str(e)}'}), 500