admin: qr kody

This commit is contained in:
2025-10-09 19:08:44 +02:00
parent a343f14f1e
commit 3ca41ec9da
5 changed files with 145 additions and 0 deletions

View File

@@ -425,3 +425,86 @@ func AdminPositionsHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
} }
func AdminQRHandler(w http.ResponseWriter, r *http.Request) {
if !isAdmin(r) {
http.Redirect(w, r, "/admin/login", http.StatusSeeOther)
return
}
if r.Method == http.MethodPost {
if err := r.ParseForm(); err != nil {
http.Error(w, "Error parsing form", http.StatusBadRequest)
return
}
// Deleting an existing QR code
if r.PostForm.Has("delete") {
qrID := r.FormValue("delete")
_, err := db.Exec("DELETE FROM qr_codes WHERE id = ?", qrID)
if err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/admin/qr", http.StatusSeeOther)
return
}
// Adding a new QR code
positionID := r.FormValue("position")
uid := r.FormValue("uid")
if positionID == "" || uid == "" {
http.Error(w, "All fields are required", http.StatusBadRequest)
return
}
_, err := db.Exec("INSERT INTO qr_codes (position_id, uid) VALUES (?, ?)", positionID, uid)
if err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
http.Redirect(w, r, "/admin/qr", http.StatusSeeOther)
return
}
// Fetch all QR codes with their associated positions
rows, err := db.Query("SELECT qr_codes.id, qr_codes.uid, COALESCE(position_id, ''), COALESCE(gps, '') FROM qr_codes LEFT JOIN positions ON qr_codes.position_id = positions.id ORDER BY qr_codes.id")
if err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
defer rows.Close()
var qrs []AdminQRsTemplateS
for rows.Next() {
var qr AdminQRsTemplateS
if err := rows.Scan(&qr.ID, &qr.URL, &qr.Position, &qr.GPS); err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
qr.URL = domain + "/qr/" + qr.URL
qrs = append(qrs, qr)
}
if err := rows.Err(); err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
// Fetch all positions for the dropdown
rows, err = db.Query("SELECT id FROM positions ORDER BY id")
if err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
defer rows.Close()
var positions []int
for rows.Next() {
var position int
if err := rows.Scan(&position); err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
positions = append(positions, position)
}
if err := rows.Err(); err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
if err := AdminQRsTemplate.Execute(w, AdminQRTemplateS{QRs: qrs, Positions: positions}); err != nil {
http.Error(w, "Template error", http.StatusInternalServerError)
return
}
}

View File

@@ -344,6 +344,7 @@ func main() {
http.HandleFunc("/admin/levels", AdminLevelHandler) http.HandleFunc("/admin/levels", AdminLevelHandler)
http.HandleFunc("/admin/cipher", AdminCipherHandler) http.HandleFunc("/admin/cipher", AdminCipherHandler)
http.HandleFunc("/admin/positions", AdminPositionsHandler) http.HandleFunc("/admin/positions", AdminPositionsHandler)
http.HandleFunc("/admin/qr", AdminQRHandler)
fmt.Println("Server started at :8080") fmt.Println("Server started at :8080")
http.ListenAndServe(":8080", nil) http.ListenAndServe(":8080", nil)

View File

@@ -52,6 +52,18 @@ type AdminPositionsTemplateS struct {
URL string URL string
} }
type AdminQRsTemplateS struct {
URL string
Position string
GPS string
ID int
}
type AdminQRTemplateS struct {
QRs []AdminQRsTemplateS
Positions []int
}
var CipherTemplate = template.Must(template.ParseFiles("templates/assignment.html")) var CipherTemplate = template.Must(template.ParseFiles("templates/assignment.html"))
var TeamTemplate = template.Must(template.ParseFiles("templates/team.html")) var TeamTemplate = template.Must(template.ParseFiles("templates/team.html"))
var AdminTeamsTemplate = template.Must(template.ParseFiles("templates/adminTeams.html")) var AdminTeamsTemplate = template.Must(template.ParseFiles("templates/adminTeams.html"))
@@ -59,3 +71,4 @@ var AdminRoutesTemplate = template.Must(template.ParseFiles("templates/adminRout
var AdminLevelTemplate = template.Must(template.ParseFiles("templates/adminLevels.html")) var AdminLevelTemplate = template.Must(template.ParseFiles("templates/adminLevels.html"))
var AdminCipherTemplate = template.Must(template.ParseFiles("templates/adminCiphers.html")) var AdminCipherTemplate = template.Must(template.ParseFiles("templates/adminCiphers.html"))
var AdminPositionsTemplate = template.Must(template.ParseFiles("templates/adminPositions.html")) var AdminPositionsTemplate = template.Must(template.ParseFiles("templates/adminPositions.html"))
var AdminQRsTemplate = template.Must(template.ParseFiles("templates/adminQR.html"))

View File

@@ -13,6 +13,7 @@
<a href="/admin/levels">Úrovně</a> <br> <a href="/admin/levels">Úrovně</a> <br>
<a href="/admin/cipher">Šifry</a> <br> <a href="/admin/cipher">Šifry</a> <br>
<a href="/admin/positions">Pozice</a> <br> <a href="/admin/positions">Pozice</a> <br>
<a href="/admin/qr">QR Kódy</a> <br>
<hr> <hr>
<form method="post" action="/admin/logout"> <form method="post" action="/admin/logout">
<input type="submit" value="Logout"> <input type="submit" value="Logout">

47
templates/adminQR.html Normal file
View File

@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<title>QR</title>
</head>
<body>
<h1>QR</h1>
<table border="1">
<tr>
<th>URL</th>
<th>Pozice</th>
<th>GPS</th>
<th>Smazat</th>
</tr>
{{range .QRs}}
<tr>
<td>{{.URL}}</td>
<td>{{.Position}}</td>
<td>{{.GPS}}</td>
<td>
<form action="/admin/qr" method="post">
<input type="hidden" name="delete" value="{{.ID}}">
<button type="submit">Smazat</button>
</form>
</td>
</tr>
{{end}}
</table>
<hr>
<h2>Přidat nový QR kód</h2>
<form action="/admin/qr" method="post">
URL - jenom poslední část: <input type="text" name="uid" required>
Pozice: <select name="position" required>
{{range .Positions}}
<option value="{{.}}">{{.}}</option>
{{end}}
</select>
<button type="submit">Přidat QR kód</button>
</form>
<hr>
<a href="/admin">Zpět na admin panel</a>
</body>
</html>