update 17 mei

This commit is contained in:
[Valentino Heman Budiarto]
2026-05-17 21:34:19 +07:00
parent e6f5c4df06
commit 8d35ec81d8
7 changed files with 448 additions and 46 deletions
+13 -6
View File
@@ -14,8 +14,8 @@ func main() {
// 1. Konek Database
config.ConnectDatabase()
// 2. AutoMigrate (Membuat tabel jika belum ada)
config.DB.AutoMigrate(&models.User{}, &models.Room{}, &models.Booking{})
// 2. AutoMigrate (Tambahkan ClassSchedule di sini agar dikenali GORM)
config.DB.AutoMigrate(&models.User{}, &models.Room{}, &models.Booking{}, &models.ClassSchedule{})
r := gin.Default()
@@ -35,6 +35,7 @@ func main() {
r.POST("/api/verify-code", controllers.VerifyRedeemCode)
// --- RUTE YANG DILINDUNGI TOKEN (UNTUK WEB) ---
protected := r.Group("/api")
protected.Use(middleware.AuthMiddleware())
{
@@ -51,14 +52,20 @@ func main() {
// Bookings
protected.POST("/bookings", controllers.CreateBooking)
protected.GET("/bookings", controllers.GetAllBookings)
protected.PUT("/bookings/:id/status", controllers.UpdateBookingStatus) // <-- Cukup tulis satu kali saja
protected.PUT("/bookings/:id/status", controllers.UpdateBookingStatus)
// Admin (Manage Rooms)
protected.PUT("/admin/rooms/:id/status", controllers.UpdateRoomStatus) // <-- Pastikan baris ini ada
protected.PUT("/admin/rooms/:id/status", controllers.UpdateRoomStatus)
// 🌟 RUTE BARU: Jadwal Kuliah (Untuk Halaman Web Admin)
protected.GET("/schedules", controllers.GetSchedules)
}
// 5. Jalur IoT ESP32 (Di luar protected)
// 5. Jalur IoT ESP32 (Di luar protected karena ESP32 tidak pakai sistem Login Token)
r.POST("/api/sensor/energy", controllers.UpdateRoomPower)
// 🌟 RUTE BARU: Untuk menerima ketukan pintu dari Hardware ESP32
r.POST("/api/hardware/verify", controllers.VerifyHardwareCode)
r.Run(":8080")
}
@@ -76,4 +83,4 @@ func CORSMiddleware() gin.HandlerFunc {
}
c.Next()
}
}
}
+120
View File
@@ -0,0 +1,120 @@
package controllers
import (
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
"s-class-backend/config"
"s-class-backend/models"
)
// Struct untuk menerima data dari ESP32
type VerifyRequest struct {
RoomID int `json:"room_id"`
KodeMK string `json:"kode_mk"`
}
// Helper untuk mengubah nama hari ke bahasa Indonesia
func getHariIndonesia(d time.Weekday) string {
days := []string{"Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"}
return days[d]
}
func VerifyHardwareCode(c *gin.Context) {
var req VerifyRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Format data tidak valid"})
return
}
// 1. Dapatkan waktu sekarang di zona waktu Surabaya (WIB / GMT+7)
loc, _ := time.LoadLocation("Asia/Jakarta")
now := time.Now().In(loc)
hariIni := getHariIndonesia(now.Weekday())
jamSekarangStr := now.Format("15:04:05")
// =========================================================================
// SKENARIO A: Dosen masuk sesuai jadwal perkuliahan
// =========================================================================
var schedule models.ClassSchedule
err := config.DB.Where(
"room_id = ? AND kode_mk = ? AND hari = ? AND jam_mulai <= ? AND jam_selesai >= ?",
req.RoomID, req.KodeMK, hariIni, jamSekarangStr, jamSekarangStr,
).First(&schedule).Error
if err == nil {
// Ditemukan jadwal yang cocok! Izinkan relay menyala.
c.JSON(http.StatusOK, gin.H{
"status": "success",
"relay": "ON",
"message": fmt.Sprintf("Akses diterima. Jadwal %s sedang berlangsung.", schedule.NamaMK),
})
return
}
// =========================================================================
// SKENARIO B: Akses Dadakan (Di luar jadwal / Kode MK tidak cocok jam ini)
// =========================================================================
// CEK 1: Apakah ada jadwal KULIAH LAIN yang sedang berlangsung saat ini?
var activeSchedule models.ClassSchedule
errActive := config.DB.Where(
"room_id = ? AND hari = ? AND jam_mulai <= ? AND jam_selesai >= ?",
req.RoomID, hariIni, jamSekarangStr, jamSekarangStr,
).First(&activeSchedule).Error
if errActive == nil {
c.JSON(http.StatusForbidden, gin.H{
"error": fmt.Sprintf("Akses ditolak. Ruangan sedang digunakan untuk jadwal: %s", activeSchedule.NamaMK),
})
return
}
// CEK 2: Apakah ada BOOKING MAHASISWA (Approved) yang sedang berlangsung?
// Asumsi tabel booking memiliki status 'Approved', 'Pending', dll.
var activeBooking models.Booking
errBooking := config.DB.Where(
"room_id = ? AND status = 'Approved' AND start_time <= ? AND end_time >= ?",
req.RoomID, now, now, // Sesuaikan jika format DB menggunakan timestamp ISO
).First(&activeBooking).Error
if errBooking == nil {
c.JSON(http.StatusForbidden, gin.H{
"error": "Akses ditolak. Ruangan sedang dipinjam oleh mahasiswa.",
})
return
}
// CEK 3: Pengecekan Aturan 10 Menit untuk Jadwal Berikutnya
var nextSchedule models.ClassSchedule
errNext := config.DB.Where(
"room_id = ? AND hari = ? AND jam_mulai > ?",
req.RoomID, hariIni, jamSekarangStr,
).Order("jam_mulai asc").First(&nextSchedule).Error
if errNext == nil {
// Parse jam mulai jadwal berikutnya
nextTime, _ := time.Parse("15:04:05", nextSchedule.JamMulai)
currentTime, _ := time.Parse("15:04:05", jamSekarangStr)
// Hitung selisih dalam menit
diffMinutes := nextTime.Sub(currentTime).Minutes()
if diffMinutes <= 10 {
c.JSON(http.StatusForbidden, gin.H{
"error": fmt.Sprintf("Akses ditolak. Kelas %s akan segera dimulai dalam %.0f menit. Ruangan harus dikosongkan.", nextSchedule.NamaMK, diffMinutes),
})
return
}
}
// Jika lolos semua rintangan di atas, ruangan dipastikan KOSONG dan AMAN.
// Akses dadakan diizinkan!
c.JSON(http.StatusOK, gin.H{
"status": "success",
"relay": "ON",
"message": "Akses dadakan diizinkan. Tidak ada tabrakan jadwal terdekat.",
})
}
+27
View File
@@ -0,0 +1,27 @@
package controllers
import (
"net/http"
"github.com/gin-gonic/gin"
// UBAH DUA BARIS INI MENJADI s-class-backend
"s-class-backend/config"
"s-class-backend/models"
)
// Fungsi untuk mengambil semua jadwal dari database
func GetSchedules(c *gin.Context) {
var schedules []models.ClassSchedule
// Mengambil semua data jadwal dan diurutkan berdasarkan Hari dan Jam Mulai
if err := config.DB.Order("hari, jam_mulai").Find(&schedules).Error; err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Gagal mengambil data jadwal kuliah"})
return
}
// Kirim data ke frontend (React)
c.JSON(http.StatusOK, gin.H{
"data": schedules,
})
}
+15
View File
@@ -46,3 +46,18 @@ type Booking struct {
CreatedAt time.Time `json:"created_at"`
}
func (ClassSchedule) TableName() string {
return "class_schedules"
}
type ClassSchedule struct {
ScheduleID int `gorm:"primaryKey;autoIncrement;column:schedule_id" json:"schedule_id"`
KodeMK string `gorm:"type:varchar(50);not null;column:kode_mk" json:"kode_mk"`
NamaMK string `gorm:"type:varchar(100);not null;column:nama_mk" json:"nama_mk"`
RoomID int `gorm:"not null;column:room_id" json:"room_id"`
Room Room `gorm:"foreignKey:RoomID" json:"room"`
Hari string `gorm:"type:varchar(20);not null;column:hari" json:"hari"`
JamMulai string `gorm:"type:time;not null;column:jam_mulai" json:"jam_mulai"`
JamSelesai string `gorm:"type:time;not null;column:jam_selesai" json:"jam_selesai"`
}