This commit is contained in:
2026-06-30 09:31:33 +07:00
parent c736326162
commit bbf8336664
77 changed files with 12601 additions and 556 deletions

View File

@@ -0,0 +1,235 @@
package handlers
import (
"strconv"
"strings"
"time"
"server/internal/models"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
)
func normalizeSSID(ssid string) string {
return strings.TrimSpace(ssid)
}
func ssidKey(ssid string) string {
return strings.ToLower(strings.TrimSpace(ssid))
}
func normalizeBSSID(bssid string) string {
var hex []rune
for _, c := range strings.ToLower(bssid) {
if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') {
hex = append(hex, c)
}
}
if len(hex) != 12 {
return strings.TrimSpace(bssid)
}
s := string(hex)
return s[0:2] + ":" + s[2:4] + ":" + s[4:6] + ":" + s[6:8] + ":" + s[8:10] + ":" + s[10:12]
}
func bssidKey(bssid string) string {
var hex []rune
for _, c := range strings.ToLower(bssid) {
if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') {
hex = append(hex, c)
}
}
return string(hex)
}
type wifiItemPayload struct {
SSID string `json:"ssid"`
BSSID string `json:"bssid"`
}
// POST /api/student/report-wifi — ghi nhận SSID + BSSID vào kho
func ReportWifiHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
var req struct {
StudentRkID int64 `json:"studentRkId"`
SSID string `json:"ssid"`
BSSID string `json:"bssid"`
}
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid payload"})
}
ssid := normalizeSSID(req.SSID)
bssid := normalizeBSSID(req.BSSID)
sKey := ssidKey(ssid)
bKey := bssidKey(bssid)
if sKey == "" || bKey == "" || len(bKey) != 12 {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "ssid and valid bssid are required"})
}
now := time.Now()
var row models.WifiPoolEntry
err := db.Where("bssid_key = ?", bKey).First(&row).Error
if err == gorm.ErrRecordNotFound {
row = models.WifiPoolEntry{
SSID: ssid,
SSIDKey: sKey,
BSSID: bssid,
BSSIDKey: bKey,
HitCount: 1,
LastSeenAt: now,
LastStudentRkID: req.StudentRkID,
}
if err := db.Create(&row).Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
} else if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
} else {
row.HitCount++
row.LastSeenAt = now
row.SSID = ssid
row.SSIDKey = sKey
row.BSSID = bssid
if req.StudentRkID > 0 {
row.LastStudentRkID = req.StudentRkID
}
if err := db.Save(&row).Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
}
return c.JSON(fiber.Map{"ok": true, "data": row})
}
}
// GET /api/student/wifi-policy — danh sách điểm phát được phép (theo BSSID)
func GetStudentWifiPolicyHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
var rows []models.AcceptedWifi
if err := db.Where("bssid_key <> '' AND LENGTH(bssid_key) = 12").Order("ssid asc").Find(&rows).Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
items := make([]wifiItemPayload, 0, len(rows))
for _, r := range rows {
items = append(items, wifiItemPayload{SSID: r.SSID, BSSID: r.BSSID})
}
return c.JSON(fiber.Map{
"enforce": len(items) > 0,
"accepted": items,
"acceptedSsids": nil, // legacy — client mới dùng accepted
})
}
}
// GET /api/wifi-pool?q=&limit=
func ListWifiPoolHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
q := strings.TrimSpace(c.Query("q", ""))
limit := 50
if l, err := strconv.Atoi(c.Query("limit", "50")); err == nil && l > 0 && l <= 200 {
limit = l
}
query := db.Model(&models.WifiPoolEntry{}).Where("bssid_key <> '' AND LENGTH(bssid_key) = 12")
if q != "" {
like := "%" + q + "%"
query = query.Where("ssid LIKE ? OR ssid_key LIKE ? OR bssid LIKE ? OR bssid_key LIKE ?", like, like, like, like)
}
var rows []models.WifiPoolEntry
if err := query.Order("hit_count DESC, last_seen_at DESC").Limit(limit).Find(&rows).Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"data": rows, "q": q, "limit": limit})
}
}
// GET /api/network/accepted-wifis
func ListAcceptedWifisHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
var rows []models.AcceptedWifi
if err := db.Order("ssid asc, bssid asc").Find(&rows).Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"data": rows})
}
}
// POST /api/network/accepted-wifis — thay toàn bộ danh sách (cần SSID + BSSID)
func SaveAcceptedWifisHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
var req struct {
Items []wifiItemPayload `json:"items"`
}
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid payload"})
}
if err := db.Where("1 = 1").Delete(&models.AcceptedWifi{}).Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
now := time.Now()
count := 0
seen := map[string]bool{}
for _, item := range req.Items {
ssid := normalizeSSID(item.SSID)
bssid := normalizeBSSID(item.BSSID)
sKey := ssidKey(ssid)
bKey := bssidKey(bssid)
if sKey == "" || bKey == "" || len(bKey) != 12 || seen[bKey] {
continue
}
seen[bKey] = true
if err := db.Create(&models.AcceptedWifi{
SSID: ssid,
SSIDKey: sKey,
BSSID: bssid,
BSSIDKey: bKey,
CreatedAt: now,
}).Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
count++
}
return c.JSON(fiber.Map{"ok": true, "count": count})
}
}
// POST /api/network/accepted-wifis/add
func AddAcceptedWifiHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
var req wifiItemPayload
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid payload"})
}
ssid := normalizeSSID(req.SSID)
bssid := normalizeBSSID(req.BSSID)
sKey := ssidKey(ssid)
bKey := bssidKey(bssid)
if sKey == "" || bKey == "" || len(bKey) != 12 {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "ssid and valid bssid are required"})
}
row := models.AcceptedWifi{
SSID: ssid,
SSIDKey: sKey,
BSSID: bssid,
BSSIDKey: bKey,
CreatedAt: time.Now(),
}
if err := db.Where("bssid_key = ?", bKey).FirstOrCreate(&row).Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"ok": true, "data": row})
}
}
// DELETE /api/network/accepted-wifis/:id
func DeleteAcceptedWifiHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
if err != nil || id == 0 {
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid id"})
}
if err := db.Delete(&models.AcceptedWifi{}, id).Error; err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
}
return c.JSON(fiber.Map{"ok": true})
}
}