update 15 mei

This commit is contained in:
[Valentino Heman Budiarto]
2026-05-15 18:48:59 +07:00
parent 94daad0c1f
commit 4970220a24
15 changed files with 1228 additions and 717 deletions
+9 -3
View File
@@ -50,10 +50,16 @@ func main() {
// Bookings
protected.POST("/bookings", controllers.CreateBooking)
protected.GET("/bookings", controllers.GetUserBookings)
protected.PATCH("/bookings/:id", controllers.UpdateBookingStatus)
protected.GET("/bookings", controllers.GetAllBookings)
protected.PUT("/bookings/:id/status", controllers.UpdateBookingStatus) // <-- Cukup tulis satu kali saja
// Admin (Manage Rooms)
protected.PUT("/admin/rooms/:id/status", controllers.UpdateRoomStatus) // <-- Pastikan baris ini ada
}
// 5. Jalur IoT ESP32 (Di luar protected)
r.POST("/api/sensor/energy", controllers.UpdateRoomPower)
r.Run(":8080")
}
@@ -70,4 +76,4 @@ func CORSMiddleware() gin.HandlerFunc {
}
c.Next()
}
}
}
+52 -26
View File
@@ -110,37 +110,44 @@ type UpdateStatusInput struct {
// UPDATE STATUS (ADMIN)
func UpdateBookingStatus(c *gin.Context) {
bookingID := c.Param("id")
bookingID := c.Param("id")
var input UpdateStatusInput
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
}
// 1. Validasi Input JSON
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Format data tidak valid"})
return
}
var input UpdateStatusInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var booking models.Booking
// 2. Gunakan "id = ?" jika primary key di DB adalah 'id'
// Jika di model kamu pakai 'RoomID', pastikan konsisten
if err := config.DB.Where("id = ?", bookingID).First(&booking).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Data booking tidak ditemukan di database"})
return
}
booking.Status = input.Status
// 3. Update Status
booking.Status = input.Status
//REDEEM CODE
if input.Status == "Approved" {
if booking.RedeemCode == "" {
booking.RedeemCode = helpers.GenerateRedeemCode()
}
} else if input.Status == "Rejected" || input.Status == "Cancelled" {
booking.RedeemCode = ""
}
// REVISI CLEAN CODE: Menggunakan Switch
switch input.Status {
case "Approved":
if booking.RedeemCode == "" {
booking.RedeemCode = helpers.GenerateRedeemCode()
}
case "Rejected", "Cancelled":
booking.RedeemCode = ""
}
if err := config.DB.Save(&booking).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Gagal menyimpan perubahan ke database"})
return
}
config.DB.Save(&booking)
c.JSON(http.StatusOK, gin.H{
"message": "Status booking berhasil diperbarui!",
"data": booking,
})
c.JSON(http.StatusOK, gin.H{
"message": "Status berhasil diperbarui!",
"data": booking,
})
}
// INPUT UNTUK ESP3
@@ -174,3 +181,22 @@ func VerifyRedeemCode(c *gin.Context) {
"status": "success",
})
}
// GET ALL BOOKINGS (Untuk Calendar View semua user)
func GetAllBookings(c *gin.Context) {
var bookings []models.Booking
// Preload digunakan untuk mengambil data Relasi (Nama Ruangan & Nama Peminjam)
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
}
// Perhatikan: responsenya menggunakan "data: bookings" agar cocok dengan Frontend React-mu
c.JSON(http.StatusOK, gin.H{
"status": "success",
"data": bookings,
})
}
+66 -1
View File
@@ -30,4 +30,69 @@ func CreateRoom(c *gin.Context) {
return
}
c.JSON(http.StatusOK, gin.H{"message": "Ruangan berhasil ditambahkan!", "data": input})
}
}
// --- STRUKTUR DATA UNTUK MENERIMA JSON ---
type UpdateRoomStatusInput struct {
Status string `json:"status" binding:"required"`
}
type EnergySensorInput struct {
RoomID int `json:"room_id" binding:"required"`
Power float64 `json:"power" binding:"required"`
}
// --- FUNGSI HANDLER ---
// UPDATE ROOM STATUS (Admin: Available <-> Maintenance)
func UpdateRoomStatus(c *gin.Context) {
roomID := c.Param("id")
var input UpdateRoomStatusInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
var room models.Room
// KUNCI PERBAIKANNYA: Cukup masukkan `roomID` langsung.
// GORM akan otomatis mencari berdasarkan Primary Key tanpa peduli nama kolomnya.
if err := config.DB.First(&room, roomID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Ruangan tidak ditemukan di tabel"})
return
}
// Ubah status dan simpan
room.Status = input.Status
if err := config.DB.Save(&room).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Gagal menyimpan perubahan"})
return
}
c.JSON(http.StatusOK, gin.H{
"message": "Status ruangan berhasil diperbarui",
"data": room,
})
}
// UPDATE ROOM POWER (Menerima data Watt dari ESP32 / Tuya)
func UpdateRoomPower(c *gin.Context) {
var input EnergySensorInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Format data sensor salah"})
return
}
var room models.Room
if err := config.DB.First(&room, "room_id = ?", input.RoomID).Error; err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "Ruangan tidak ditemukan"})
return
}
// Pastikan kolom ini sesuai dengan nama di models.Room milikmu (misal: PowerConsumption)
room.PowerConsumption = input.Power
config.DB.Save(&room)
c.JSON(http.StatusOK, gin.H{"message": "Data daya ESP32 berhasil disimpan"})
}
+1
View File
@@ -25,6 +25,7 @@ type Room struct {
Capacity int `gorm:"not null" json:"capacity"`
Floor string `gorm:"not null" json:"floor"`
Status string `gorm:"type:room_status;default:'Available'" json:"status"`
PowerConsumption float64 `json:"power_consumption" gorm:"default:0"`
}
type Booking struct {