package handlers import ( "fmt" "net/http" "strconv" "attune-heart-therapy/internal/middleware" "attune-heart-therapy/internal/repositories" "attune-heart-therapy/internal/services" "github.com/gin-gonic/gin" ) type MeetingHandler struct { bookingRepo repositories.BookingRepository userRepo repositories.UserRepository jitsiService services.JitsiService } func NewMeetingHandler(bookingRepo repositories.BookingRepository, userRepo repositories.UserRepository, jitsiService services.JitsiService) *MeetingHandler { return &MeetingHandler{ bookingRepo: bookingRepo, userRepo: userRepo, jitsiService: jitsiService, } } // GetMeetingLink handles GET /api/meetings/:id/link - returns personalized meeting link func (h *MeetingHandler) GetMeetingLink(c *gin.Context) { // Get booking ID from URL parameter bookingIDStr := c.Param("id") bookingID, err := strconv.ParseUint(bookingIDStr, 10, 32) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": "Invalid booking ID", }) return } // Get user ID from JWT token userID, exists := middleware.GetUserIDFromContext(c) if !exists { c.JSON(http.StatusUnauthorized, gin.H{ "error": "User not authenticated", }) return } // Get booking details booking, err := h.bookingRepo.GetByID(uint(bookingID)) if err != nil { c.JSON(http.StatusNotFound, gin.H{ "error": "Booking not found", }) return } // Verify booking belongs to user (or user is admin) user, err := h.userRepo.GetByID(userID) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": "Failed to retrieve user information", }) return } // Check authorization: user must own the booking or be an admin if booking.UserID != userID && !user.IsAdmin { c.JSON(http.StatusForbidden, gin.H{ "error": "You don't have permission to access this meeting", }) return } // Check if meeting URL exists if booking.JitsiRoomURL == "" { c.JSON(http.StatusNotFound, gin.H{ "error": "Meeting link not available for this booking", }) return } // Prepare display name displayName := fmt.Sprintf("%s %s", user.FirstName, user.LastName) if displayName == " " || displayName == "" { displayName = user.Email } // Determine if user is admin isAdmin := user.IsAdmin // Generate JWT token for Jitsi authentication token, err := h.jitsiService.GenerateJitsiToken( booking.JitsiRoomID, displayName, user.Email, isAdmin, ) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": "Failed to generate meeting token", "details": err.Error(), }) return } // Build Jitsi URL with JWT token var jitsiURL string if token != "" { // If JWT is configured, append token as query parameter jitsiURL = fmt.Sprintf("%s?jwt=%s", booking.JitsiRoomURL, token) } else { // Fallback to URL parameters if JWT not configured jitsiURL = fmt.Sprintf("%s#userInfo.displayName=\"%s\"", booking.JitsiRoomURL, displayName) if isAdmin { jitsiURL = fmt.Sprintf("%s&config.startWithAudioMuted=false&config.startWithVideoMuted=false", jitsiURL) } } c.JSON(http.StatusOK, gin.H{ "booking_id": booking.ID, "meeting_url": jitsiURL, "display_name": displayName, "is_admin": isAdmin, "scheduled_at": booking.ScheduledAt, "duration": booking.Duration, "status": booking.Status, }) }