2026-02-19 18:09:15 +07:00

146 lines
4.2 KiB
Go

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,
})
}