package handlers import ( "encoding/json" "fmt" "net/http" "strconv" "strings" "web-giao-ban-go/config" "web-giao-ban-go/db" "web-giao-ban-go/license" "web-giao-ban-go/logger" "web-giao-ban-go/updater" ) // GET /api/admin/config func HandleGetAdminConfig(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") cfg := config.Get() // Mask sensitive fields respCfg := *cfg if respCfg.Server.AdminPassword != "" { respCfg.Server.AdminPassword = "••••••••" } if respCfg.Database.Password != "" { respCfg.Database.Password = "••••••••" } if respCfg.Updater.Token != "" { respCfg.Updater.Token = "••••••••" } _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": true, "data": respCfg, }) } // POST /api/admin/config func HandleSaveAdminConfig(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") var input config.AppConfig if err := json.NewDecoder(r.Body).Decode(&input); err != nil { w.WriteHeader(http.StatusBadRequest) _ = json.NewEncoder(w).Encode(map[string]interface{}{"success": false, "message": "JSON không hợp lệ: " + err.Error()}) return } current := config.Get() // Handle Admin Password if input.Server.AdminPassword == "" || input.Server.AdminPassword == "••••••••" { input.Server.AdminPassword = current.Server.AdminPassword input.DecryptedAdminPassword = current.DecryptedAdminPassword } else { input.DecryptedAdminPassword = input.Server.AdminPassword enc, _ := config.Encrypt(input.Server.AdminPassword) input.Server.AdminPassword = enc } // Handle DB Password if input.Database.Password == "" || input.Database.Password == "••••••••" { input.Database.Password = current.Database.Password input.DecryptedDBPassword = current.DecryptedDBPassword } else { input.DecryptedDBPassword = input.Database.Password enc, _ := config.Encrypt(input.Database.Password) input.Database.Password = enc } // Handle Updater Token if input.Updater.Token == "" || input.Updater.Token == "••••••••" { input.Updater.Token = current.Updater.Token input.DecryptedUpdaterToken = current.DecryptedUpdaterToken } else { input.DecryptedUpdaterToken = input.Updater.Token enc, _ := config.Encrypt(input.Updater.Token) input.Updater.Token = enc } // Handle License Key if input.License.Key == "" { input.License.Key = current.License.Key } if err := config.SaveConfig(&input); err != nil { w.WriteHeader(http.StatusInternalServerError) _ = json.NewEncoder(w).Encode(map[string]interface{}{"success": false, "message": "Lưu file thất bại: " + err.Error()}) return } // Reset DB pool to apply new connection parameters db.CloseAll() logger.Info("Đã lưu cấu hình mới và làm mới kết nối CSDL") _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": true, "message": "Đã lưu cấu hình và mã hóa mật khẩu thành công!", }) } // POST /api/admin/test-db func HandleTestDBConnection(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") var body struct { Host string `json:"host"` Port int `json:"port"` User string `json:"user"` Password string `json:"password"` Database string `json:"database"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { w.WriteHeader(http.StatusBadRequest) _ = json.NewEncoder(w).Encode(map[string]interface{}{"success": false, "message": "Dữ liệu không hợp lệ"}) return } cfg := config.Get() pass := body.Password if pass == "" || pass == "••••••••" { pass = cfg.DecryptedDBPassword } err := db.TestConnection(body.Host, body.Port, body.User, pass, body.Database) if err != nil { w.WriteHeader(http.StatusOK) _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": false, "message": "Kết nối thất bại: " + err.Error(), }) return } _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": true, "message": "Kết nối PostgreSQL thành công!", }) } // GET /api/admin/logs func HandleGetLogs(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") limitStr := r.URL.Query().Get("limit") level := r.URL.Query().Get("level") limit := 100 if l, err := strconv.Atoi(limitStr); err == nil && l > 0 { limit = l } entries := logger.Get().GetEntries(limit, strings.ToUpper(level)) _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": true, "data": entries, }) } // POST /api/admin/logs/clear func HandleClearLogs(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") logger.Get().Clear() _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": true, "message": "Đã làm trống bộ nhớ log!", }) } // GET /api/update/check func HandleCheckUpdate(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") res, err := updater.CheckUpdate() if err != nil { logger.Error("Kiểm tra cập nhật lỗi: %v", err) w.WriteHeader(http.StatusInternalServerError) _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": false, "message": err.Error(), }) return } _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": true, "data": res, }) } // POST /api/update/apply func HandleApplyUpdate(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") var body struct { AssetURL string `json:"asset_url"` Version string `json:"version"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil || body.AssetURL == "" { w.WriteHeader(http.StatusBadRequest) _ = json.NewEncoder(w).Encode(map[string]interface{}{"success": false, "message": "Thiếu thông tin URL bản cập nhật"}) return } err := updater.ApplyUpdate(body.AssetURL) if err != nil { w.WriteHeader(http.StatusInternalServerError) _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": false, "message": "Cập nhật thất bại: " + err.Error(), }) return } // Update current version in config if provided if body.Version != "" { cfg := config.Get() cfg.Updater.CurrentVersion = body.Version _ = config.SaveConfig(cfg) } _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": true, "message": "Đã cập nhật phiên bản mới thành công! Vui lòng khởi động lại phần mềm để áp dụng.", }) } // GET /api/license/status func HandleGetLicenseStatus(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") status := license.GetStatus() _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": true, "data": status, }) } // POST /api/license/activate func HandleActivateLicense(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") var body struct { Key string `json:"key"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { w.WriteHeader(http.StatusBadRequest) _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": false, "message": "Dữ liệu JSON không hợp lệ: " + err.Error(), }) return } key := strings.TrimSpace(body.Key) if key == "" { w.WriteHeader(http.StatusBadRequest) _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": false, "message": "Vui lòng nhập chuỗi key bản quyền (chỉ nhập chuỗi mã hóa DECODE)", }) return } info, err := license.Activate(key) if err != nil { w.WriteHeader(http.StatusBadRequest) _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": false, "message": "Kích hoạt thất bại: " + err.Error(), }) return } _ = json.NewEncoder(w).Encode(map[string]interface{}{ "success": true, "message": fmt.Sprintf("Kích hoạt bản quyền thành công cho đơn vị '%s' (Mã BV: %s)!", info.TenBV, info.Mabvbh), "data": info, }) }