package handlers import ( "net/http" "time" "github.com/breakpilot/consent-service/internal/services/jitsi" "github.com/breakpilot/consent-service/internal/services/matrix" "github.com/gin-gonic/gin" ) // CommunicationHandlers handles Matrix and Jitsi API endpoints type CommunicationHandlers struct { matrixService *matrix.MatrixService jitsiService *jitsi.JitsiService } // NewCommunicationHandlers creates new communication handlers func NewCommunicationHandlers(matrixSvc *matrix.MatrixService, jitsiSvc *jitsi.JitsiService) *CommunicationHandlers { return &CommunicationHandlers{ matrixService: matrixSvc, jitsiService: jitsiSvc, } } // ======================================== // Health & Status Endpoints // ======================================== // GetCommunicationStatus returns status of Matrix and Jitsi services func (h *CommunicationHandlers) GetCommunicationStatus(c *gin.Context) { ctx := c.Request.Context() status := gin.H{ "timestamp": time.Now().UTC().Format(time.RFC3339), } // Check Matrix if h.matrixService != nil { matrixErr := h.matrixService.HealthCheck(ctx) status["matrix"] = gin.H{ "enabled": true, "healthy": matrixErr == nil, "server_name": h.matrixService.GetServerName(), "error": errToString(matrixErr), } } else { status["matrix"] = gin.H{ "enabled": false, "healthy": false, } } // Check Jitsi if h.jitsiService != nil { jitsiErr := h.jitsiService.HealthCheck(ctx) serverInfo := h.jitsiService.GetServerInfo() status["jitsi"] = gin.H{ "enabled": true, "healthy": jitsiErr == nil, "base_url": serverInfo["base_url"], "auth_enabled": serverInfo["auth_enabled"], "error": errToString(jitsiErr), } } else { status["jitsi"] = gin.H{ "enabled": false, "healthy": false, } } c.JSON(http.StatusOK, status) } // ======================================== // Matrix Room Endpoints // ======================================== // CreateRoomRequest for creating Matrix rooms type CreateRoomRequest struct { Type string `json:"type" binding:"required"` // "class_info", "student_dm", "parent_rep" ClassName string `json:"class_name"` SchoolName string `json:"school_name"` StudentName string `json:"student_name,omitempty"` TeacherIDs []string `json:"teacher_ids"` ParentIDs []string `json:"parent_ids,omitempty"` ParentRepIDs []string `json:"parent_rep_ids,omitempty"` } // CreateRoom creates a new Matrix room based on type func (h *CommunicationHandlers) CreateRoom(c *gin.Context) { if h.matrixService == nil { c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Matrix service not configured"}) return } var req CreateRoomRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } ctx := c.Request.Context() var resp *matrix.CreateRoomResponse var err error switch req.Type { case "class_info": resp, err = h.matrixService.CreateClassInfoRoom(ctx, req.ClassName, req.SchoolName, req.TeacherIDs) case "student_dm": resp, err = h.matrixService.CreateStudentDMRoom(ctx, req.StudentName, req.ClassName, req.TeacherIDs, req.ParentIDs) case "parent_rep": resp, err = h.matrixService.CreateParentRepRoom(ctx, req.ClassName, req.TeacherIDs, req.ParentRepIDs) default: c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room type. Use: class_info, student_dm, parent_rep"}) return } if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusCreated, gin.H{ "room_id": resp.RoomID, "type": req.Type, }) } // InviteUserRequest for inviting users to rooms type InviteUserRequest struct { RoomID string `json:"room_id" binding:"required"` UserID string `json:"user_id" binding:"required"` } // InviteUser invites a user to a Matrix room func (h *CommunicationHandlers) InviteUser(c *gin.Context) { if h.matrixService == nil { c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Matrix service not configured"}) return } var req InviteUserRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } ctx := c.Request.Context() if err := h.matrixService.InviteUser(ctx, req.RoomID, req.UserID); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true}) } // SendMessageRequest for sending messages type SendMessageRequest struct { RoomID string `json:"room_id" binding:"required"` Message string `json:"message" binding:"required"` HTML string `json:"html,omitempty"` } // SendMessage sends a message to a Matrix room func (h *CommunicationHandlers) SendMessage(c *gin.Context) { if h.matrixService == nil { c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Matrix service not configured"}) return } var req SendMessageRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } ctx := c.Request.Context() var err error if req.HTML != "" { err = h.matrixService.SendHTMLMessage(ctx, req.RoomID, req.Message, req.HTML) } else { err = h.matrixService.SendMessage(ctx, req.RoomID, req.Message) } if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true}) } // SendNotificationRequest for sending school notifications type SendNotificationRequest struct { RoomID string `json:"room_id" binding:"required"` Type string `json:"type" binding:"required"` // "absence", "grade", "announcement" StudentName string `json:"student_name,omitempty"` Date string `json:"date,omitempty"` Lesson int `json:"lesson,omitempty"` Subject string `json:"subject,omitempty"` GradeType string `json:"grade_type,omitempty"` Grade float64 `json:"grade,omitempty"` Title string `json:"title,omitempty"` Content string `json:"content,omitempty"` TeacherName string `json:"teacher_name,omitempty"` } // SendNotification sends a typed notification (absence, grade, announcement) func (h *CommunicationHandlers) SendNotification(c *gin.Context) { if h.matrixService == nil { c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Matrix service not configured"}) return } var req SendNotificationRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } ctx := c.Request.Context() var err error switch req.Type { case "absence": err = h.matrixService.SendAbsenceNotification(ctx, req.RoomID, req.StudentName, req.Date, req.Lesson) case "grade": err = h.matrixService.SendGradeNotification(ctx, req.RoomID, req.StudentName, req.Subject, req.GradeType, req.Grade) case "announcement": err = h.matrixService.SendClassAnnouncement(ctx, req.RoomID, req.Title, req.Content, req.TeacherName) default: c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid notification type. Use: absence, grade, announcement"}) return } if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{"success": true}) } // RegisterUserRequest for user registration type RegisterUserRequest struct { Username string `json:"username" binding:"required"` DisplayName string `json:"display_name"` } // RegisterMatrixUser registers a new Matrix user func (h *CommunicationHandlers) RegisterMatrixUser(c *gin.Context) { if h.matrixService == nil { c.JSON(http.StatusServiceUnavailable, gin.H{"error": "Matrix service not configured"}) return } var req RegisterUserRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } ctx := c.Request.Context() resp, err := h.matrixService.RegisterUser(ctx, req.Username, req.DisplayName) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusCreated, gin.H{ "user_id": resp.UserID, }) }