6de2455917
- Added GLOBAL_MARKETS_TITLE to all translation files - Updated footer with 12 markets (4 active + 8 upcoming) - Translated market section to: zh-cn, zh-tw, ja, ko, th, vi, id, ms, hi - Built and deployed to production - CloudFront invalidation: I3RTMXVFDJXWLG3SYX208OP1CC
109 lines
3.0 KiB
Go
109 lines
3.0 KiB
Go
package handlers
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"aamos-admin/models"
|
|
)
|
|
|
|
type DashboardResponse struct {
|
|
UsersCount int `json:"users_count"`
|
|
ModulesHealthy int `json:"modules_healthy"`
|
|
ModulesTotal int `json:"modules_total"`
|
|
RecentAudit []models.AuditLog `json:"recent_audit"`
|
|
SystemMetrics DashboardSystemMetrics `json:"system_metrics"`
|
|
}
|
|
|
|
type DashboardSystemMetrics struct {
|
|
CPU CPUMetrics `json:"cpu"`
|
|
RAM RAMMetrics `json:"ram"`
|
|
Disk DiskMetrics `json:"disk"`
|
|
}
|
|
|
|
func DashboardHandler(db *sql.DB) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
var usersCount int
|
|
if err := db.QueryRowContext(r.Context(), `SELECT COUNT(*) FROM users`).Scan(&usersCount); err != nil {
|
|
http.Error(w, fmt.Sprintf("db error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
var modulesTotal, modulesHealthy int
|
|
if err := db.QueryRowContext(r.Context(), `SELECT COUNT(*) FROM modules`).Scan(&modulesTotal); err != nil {
|
|
http.Error(w, fmt.Sprintf("db error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if err := db.QueryRowContext(r.Context(),
|
|
`SELECT COUNT(*) FROM modules WHERE status = $1`, string(models.ModuleStatusRunning),
|
|
).Scan(&modulesHealthy); err != nil {
|
|
http.Error(w, fmt.Sprintf("db error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
rows, err := db.QueryContext(r.Context(), `
|
|
SELECT id, user_id, action, resource, ip, timestamp, details
|
|
FROM audit_logs
|
|
ORDER BY timestamp DESC
|
|
LIMIT 5
|
|
`)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("db error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
|
|
audit := make([]models.AuditLog, 0, 5)
|
|
for rows.Next() {
|
|
var a models.AuditLog
|
|
if err := rows.Scan(&a.ID, &a.UserID, &a.Action, &a.Resource, &a.IP, &a.Timestamp, &a.Details); err != nil {
|
|
http.Error(w, fmt.Sprintf("scan error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
audit = append(audit, a)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
http.Error(w, fmt.Sprintf("rows error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
cpu, err := readCPU()
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("cpu read error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
ram, err := readRAM()
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("ram read error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
disk, err := readDisk("/")
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("disk read error: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
resp := DashboardResponse{
|
|
UsersCount: usersCount,
|
|
ModulesHealthy: modulesHealthy,
|
|
ModulesTotal: modulesTotal,
|
|
RecentAudit: audit,
|
|
SystemMetrics: DashboardSystemMetrics{
|
|
CPU: cpu,
|
|
RAM: ram,
|
|
Disk: disk,
|
|
},
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(resp)
|
|
}
|
|
}
|