package controllers import ( "fmt" "net/http" "s-class-backend/config" "s-class-backend/models" "time" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type BookingInput struct { RoomID uint `json:"room_id" binding:"required"` StartTime time.Time `json:"start_time" binding:"required"` EndTime time.Time `json:"end_time" binding:"required"` Purpose string `json:"purpose" binding:"required"` } func CreateBooking(c *gin.Context) { var input BookingInput if err := c.ShouldBindJSON(&input); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // --- PERBAIKAN DI SINI (Handle UUID) --- // Ambil user_id dari context (hasil login) userIDInterface, exists := c.Get("user_id") if !exists { c.JSON(http.StatusUnauthorized, gin.H{"error": "User ID tidak ditemukan"}) return } // Konversi interface{} ke string dulu, baru ke UUID userIDStr, ok := userIDInterface.(string) if !ok { c.JSON(http.StatusInternalServerError, gin.H{"error": "Format User ID token salah"}) return } userID, err := uuid.Parse(userIDStr) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Gagal memproses User ID"}) return } // --------------------------------------- // Validasi Waktu if input.EndTime.Before(input.StartTime) { c.JSON(http.StatusBadRequest, gin.H{"error": "Waktu selesai tidak boleh lebih awal dari waktu mulai!"}) return } // CEK BENTROK (Overlap Check) var count int64 config.DB.Model(&models.Booking{}).Where("room_id = ? AND status != 'Cancelled' AND ((start_time < ? AND end_time > ?) OR (start_time < ? AND end_time > ?) OR (start_time >= ? AND end_time <= ?))", input.RoomID, input.EndTime, input.StartTime, input.EndTime, input.StartTime, input.StartTime, input.EndTime).Count(&count) if count > 0 { c.JSON(http.StatusConflict, gin.H{"error": "Ruangan sudah dibooking pada jam tersebut!"}) return } // Simpan Booking booking := models.Booking{ UserID: userID, RoomID: input.RoomID, StartTime: input.StartTime, EndTime: input.EndTime, Purpose: input.Purpose, Status: "Pending", } // Tampilkan error asli database jika gagal if err := config.DB.Create(&booking).Error; err != nil { fmt.Println("Error DB:", err) // Print error ke terminal c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, gin.H{ "message": "Booking Berhasil diajukan!", "data": booking, }) } func GetUserBookings(c *gin.Context) { var bookings []models.Booking // 1. Ambil User ID dan Role dari token yang sedang login userID, _ := c.Get("user_id") role, _ := c.Get("role") // 2. Cek apakah dia Admin if role == "admin" { // Jika ADMIN: Ambil SEMUA data peminjaman dari semua user, urutkan dari yang terbaru // Kita juga ambil data Room dan User agar detailnya lengkap if err := config.DB.Preload("Room").Preload("User").Order("created_at desc").Find(&bookings).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } } else { // Jika MAHASISWA: Ambil HANYA data peminjaman miliknya sendiri if err := config.DB.Preload("Room").Where("user_id = ?", userID).Order("created_at desc").Find(&bookings).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } } c.JSON(http.StatusOK, gin.H{"data": bookings}) } type UpdateStatusInput struct { Status string `json:"status" binding:"required"` // Isinya: 'Approved', 'Rejected', 'Completed', 'Cancelled' } // --- FUNGSI 3: UPDATE STATUS (ADMIN) --- func UpdateBookingStatus(c *gin.Context) { // 1. Ambil ID Booking dari URL (misal: /bookings/123) bookingID := c.Param("id") // 2. Cek apakah booking ada? var booking models.Booking if err := config.DB.First(&booking, "booking_id = ?", bookingID).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "Booking tidak ditemukan"}) return } // 3. Validasi Input JSON var input UpdateStatusInput if err := c.ShouldBindJSON(&input); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // 4. Update Status ke Database booking.Status = input.Status config.DB.Save(&booking) c.JSON(http.StatusOK, gin.H{ "message": "Status booking berhasil diperbarui!", "data": booking, }) }