Compare commits
4 Commits
68cb9ac73e
...
cbe7ddc51b
| Author | SHA1 | Date | |
|---|---|---|---|
| cbe7ddc51b | |||
| 94440e78de | |||
| 9491495395 | |||
| c4b404e7a9 |
37
admin.go
37
admin.go
@@ -122,7 +122,7 @@ func adminTeamsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
// Fetch all teams with their difficulty levels
|
// Fetch all teams with their difficulty levels
|
||||||
// Teams
|
// Teams
|
||||||
rows, err := db.Query("SELECT name, difficulty_levels.level_name, last_cipher, penalty FROM teams JOIN difficulty_levels ON teams.difficulty_level = difficulty_levels.id ORDER BY teams.difficulty_level, teams.name")
|
rows, err := db.Query("SELECT teams.id, name, difficulty_levels.level_name, last_cipher, last_loaded_cipher, penalty FROM teams JOIN difficulty_levels ON teams.difficulty_level = difficulty_levels.id ORDER BY teams.difficulty_level, teams.name")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Database error", http.StatusInternalServerError)
|
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -131,7 +131,7 @@ func adminTeamsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
var teams []TeamTemplateS
|
var teams []TeamTemplateS
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var team TeamTemplateS
|
var team TeamTemplateS
|
||||||
if err := rows.Scan(&team.TeamName, &team.Difficulty, &team.LastCipher, &team.Penalties); err != nil {
|
if err := rows.Scan(&team.ID, &team.TeamName, &team.Difficulty, &team.LastCipher, &team.LastLoadedCipher, &team.Penalties); err != nil {
|
||||||
http.Error(w, "Database error", http.StatusInternalServerError)
|
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -176,7 +176,7 @@ func AdminStartHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Redirect(w, r, "/admin/login", http.StatusSeeOther)
|
http.Redirect(w, r, "/admin/login", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, err := db.Exec("UPDATE teams SET last_cipher = 1, penalty = 0")
|
_, err := db.Exec("UPDATE teams SET last_cipher = 1, last_loaded_cipher = 0, penalty = 0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Database error", http.StatusInternalServerError)
|
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -631,3 +631,34 @@ func AdminQRHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AdminPenaltiesHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !isAdmin(r) {
|
||||||
|
http.Redirect(w, r, "/admin/login", http.StatusSeeOther)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Fetch all penalties with team names and task orders
|
||||||
|
rows, err := db.Query("SELECT teams.name, tasks.order_num, penalties.minutes FROM penalties JOIN teams ON penalties.team_id = teams.id JOIN tasks ON penalties.task_id = tasks.id ORDER BY teams.name, tasks.order_num")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var penalties []AdminPenaltiesTemplateS
|
||||||
|
for rows.Next() {
|
||||||
|
var penalty AdminPenaltiesTemplateS
|
||||||
|
if err := rows.Scan(&penalty.TeamName, &penalty.TaskOrder, &penalty.Minutes); err != nil {
|
||||||
|
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
penalties = append(penalties, penalty)
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
http.Error(w, "Database error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := AdminPenaltiesTemplate.Execute(w, penalties); err != nil {
|
||||||
|
http.Error(w, "Template error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ CREATE TABLE TEAMS (
|
|||||||
difficulty_level INTEGER NOT NULL,
|
difficulty_level INTEGER NOT NULL,
|
||||||
password VARCHAR(255) NOT NULL,
|
password VARCHAR(255) NOT NULL,
|
||||||
last_cipher INTEGER DEFAULT 0, -- index of cipher which team is solving or searching now
|
last_cipher INTEGER DEFAULT 0, -- index of cipher which team is solving or searching now
|
||||||
|
last_loaded_cipher INTEGER DEFAULT 0, -- index of cipher which team has loaded last time
|
||||||
penalty INTEGER DEFAULT 0,
|
penalty INTEGER DEFAULT 0,
|
||||||
FOREIGN KEY (difficulty_level) REFERENCES DIFFICULTY_LEVELS(id)
|
FOREIGN KEY (difficulty_level) REFERENCES DIFFICULTY_LEVELS(id)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ INSERT INTO DIFFICULTY_LEVELS (id, level_name) VALUES
|
|||||||
(3, 'Těžká');
|
(3, 'Těžká');
|
||||||
|
|
||||||
-- Vložení týmů: heslo1, heslo2, heslo3
|
-- Vložení týmů: heslo1, heslo2, heslo3
|
||||||
INSERT INTO TEAMS (id, name, difficulty_level, password, last_cipher, penalty) VALUES
|
INSERT INTO TEAMS (id, name, difficulty_level, password, last_cipher, last_loaded_cipher, penalty) VALUES
|
||||||
(1, 'Rychlé šípy', 1, '4bc2ef0648cdf275032c83bb1e87dd554d47f4be293670042212c8a01cc2ccbe', 1, 0),
|
(1, 'Rychlé šípy', 1, '4bc2ef0648cdf275032c83bb1e87dd554d47f4be293670042212c8a01cc2ccbe', 1, 0, 0),
|
||||||
(2, 'Vlčí smečka', 2, '274efeaa827a33d7e35be9a82cd6150b7caf98f379a4252aa1afce45664dcbe1', 1, 10),
|
(2, 'Vlčí smečka', 2, '274efeaa827a33d7e35be9a82cd6150b7caf98f379a4252aa1afce45664dcbe1', 1, 0, 10),
|
||||||
(3, 'Orli', 3, '05af533c6614544a704c4cf51a45be5c10ff19bd10b7aa1dfe47efc0fd059ede', 1, 5);
|
(3, 'Orli', 3, '05af533c6614544a704c4cf51a45be5c10ff19bd10b7aa1dfe47efc0fd059ede', 1, 0, 5);
|
||||||
|
|
||||||
-- Vložení pozic
|
-- Vložení pozic
|
||||||
INSERT INTO POSITIONS (id, gps, clue) VALUES
|
INSERT INTO POSITIONS (id, gps, clue) VALUES
|
||||||
|
|||||||
24
klice.go
24
klice.go
@@ -15,6 +15,11 @@ import (
|
|||||||
const domain = "https://klice.h21.cz"
|
const domain = "https://klice.h21.cz"
|
||||||
const dbFile = "./klice.db"
|
const dbFile = "./klice.db"
|
||||||
|
|
||||||
|
const (
|
||||||
|
smallHelpPenalty = 5
|
||||||
|
giveUpPenalty = 30
|
||||||
|
)
|
||||||
|
|
||||||
var db *sql.DB
|
var db *sql.DB
|
||||||
|
|
||||||
func hashPassword(password string) string {
|
func hashPassword(password string) string {
|
||||||
@@ -193,12 +198,12 @@ func qrHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Error(w, "This task is not yet available", http.StatusForbidden)
|
http.Error(w, "This task is not yet available", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
} else if order == last_cipher {
|
} else if order == last_cipher {
|
||||||
last_cipher = order
|
_, err := db.Exec("UPDATE teams SET last_loaded_cipher = ? WHERE id = ?", order, teamID)
|
||||||
_, err = db.Exec("UPDATE teams SET last_cipher = ? WHERE id = ?", order, teamID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Could not update last cipher", http.StatusInternalServerError)
|
http.Error(w, "Could not update last loaded cipher", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if order < last_cipher {
|
} else if order < last_cipher {
|
||||||
help = 2
|
help = 2
|
||||||
}
|
}
|
||||||
@@ -231,9 +236,9 @@ func qrHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// determine help level based on penalties
|
// determine help level based on penalties
|
||||||
if penalty > 0 && penalty < 15 {
|
if penalty > 0 && penalty <= smallHelpPenalty {
|
||||||
help = 1
|
help = 1
|
||||||
} else if penalty >= 15 {
|
} else if penalty > smallHelpPenalty {
|
||||||
help = 2
|
help = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,12 +250,12 @@ func qrHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
if r.FormValue("help") == "1" && help == 0 { // small help
|
if r.FormValue("help") == "1" && help == 0 { // small help
|
||||||
help = 1
|
help = 1
|
||||||
db.Exec("INSERT INTO penalties (team_id, task_id, minutes) VALUES (?, ?, 5)", teamID, taskID)
|
db.Exec("INSERT INTO penalties (team_id, task_id, minutes) VALUES (?, ?, ?)", teamID, taskID, smallHelpPenalty)
|
||||||
db.Exec("UPDATE teams SET penalty = penalty + 5 WHERE id = ?", teamID)
|
db.Exec("UPDATE teams SET penalty = penalty + ? WHERE id = ?", smallHelpPenalty, teamID)
|
||||||
} else if r.FormValue("help") == "2" && help == 1 { // give up
|
} else if r.FormValue("help") == "2" && help == 1 { // give up
|
||||||
help = 2
|
help = 2
|
||||||
db.Exec("UPDATE penalties SET minutes = 35 WHERE team_id = ? AND task_id = ?", teamID, taskID)
|
db.Exec("UPDATE penalties SET minutes = minutes + ? WHERE team_id = ? AND task_id = ?", giveUpPenalty, teamID, taskID)
|
||||||
db.Exec("UPDATE teams SET penalty = penalty + 30, last_cipher = ? WHERE id = ?", order+1, teamID)
|
db.Exec("UPDATE teams SET penalty = penalty + ?, last_cipher = ? WHERE id = ?", giveUpPenalty, order+1, teamID)
|
||||||
} else if answer := r.FormValue("solution"); answer != "" && help < 2 { // answer submission
|
} else if answer := r.FormValue("solution"); answer != "" && help < 2 { // answer submission
|
||||||
var correctAnswer string
|
var correctAnswer string
|
||||||
err = db.QueryRow("SELECT solution FROM CIPHERS WHERE id = ?", cipherID).Scan(&correctAnswer)
|
err = db.QueryRow("SELECT solution FROM CIPHERS WHERE id = ?", cipherID).Scan(&correctAnswer)
|
||||||
@@ -350,6 +355,7 @@ func main() {
|
|||||||
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)
|
http.HandleFunc("/admin/qr", AdminQRHandler)
|
||||||
|
http.HandleFunc("/admin/penalties", AdminPenaltiesHandler)
|
||||||
|
|
||||||
// static files
|
// static files
|
||||||
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ type CipherTemplateS struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TeamTemplateS struct {
|
type TeamTemplateS struct {
|
||||||
|
ID int
|
||||||
TeamName string
|
TeamName string
|
||||||
Difficulty string
|
Difficulty string
|
||||||
LastCipher int
|
LastCipher int
|
||||||
|
LastLoadedCipher int
|
||||||
Penalties int
|
Penalties int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +80,12 @@ type AdminLevelTemplateS struct {
|
|||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AdminPenaltiesTemplateS struct {
|
||||||
|
TeamName string
|
||||||
|
TaskOrder uint
|
||||||
|
Minutes 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"))
|
||||||
@@ -86,3 +94,4 @@ var AdminLevelTemplate = template.Must(template.ParseFiles("templates/adminLevel
|
|||||||
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"))
|
var AdminQRsTemplate = template.Must(template.ParseFiles("templates/adminQR.html"))
|
||||||
|
var AdminPenaltiesTemplate = template.Must(template.ParseFiles("templates/adminPenalties.html"))
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
<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>
|
<a href="/admin/qr">QR Kódy</a> <br>
|
||||||
|
<a href="/admin/penalties">Penalizace týmů</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">
|
||||||
|
|||||||
29
templates/adminPenalties.html
Normal file
29
templates/adminPenalties.html
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="cs">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Penalizace týmů</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Penalizace týmů</h1>
|
||||||
|
<table border="1">
|
||||||
|
<tr>
|
||||||
|
<th>Název týmu</th>
|
||||||
|
<th>Pořadí šifry</th>
|
||||||
|
<th>Minuty</th>
|
||||||
|
</tr>
|
||||||
|
{{range .}}
|
||||||
|
<tr>
|
||||||
|
<td>{{.TeamName}}</td>
|
||||||
|
<td>{{.TaskOrder}}</td>
|
||||||
|
<td>{{.Minutes}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
|
<hr>
|
||||||
|
<a href="/admin">Zpět na admin panel</a>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -10,18 +10,21 @@
|
|||||||
<h1>Týmy</h1>
|
<h1>Týmy</h1>
|
||||||
<table border="1">
|
<table border="1">
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
<th>Název týmu</th>
|
<th>Název týmu</th>
|
||||||
<th>Obtížnost</th>
|
<th>Obtížnost</th>
|
||||||
<th>Poslední šifra</th>
|
<th>Právě řešená šifra</th>
|
||||||
|
<th>Poslední načtená šifra</th>
|
||||||
<th>Penalizace (minuty)</th>
|
<th>Penalizace (minuty)</th>
|
||||||
<th>Smazat tým</th>
|
<th>Smazat tým</th>
|
||||||
</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
{{range .Teams}}
|
{{range .Teams}}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td>{{.ID}}</td>
|
||||||
<td>{{.TeamName}}</td>
|
<td>{{.TeamName}}</td>
|
||||||
<td>{{.Difficulty}}</td>
|
<td>{{.Difficulty}}</td>
|
||||||
<td>{{.LastCipher}}</td>
|
<td>{{.LastCipher}}</td>
|
||||||
|
<td>{{.LastLoadedCipher}}</td>
|
||||||
<td>{{.Penalties}}</td>
|
<td>{{.Penalties}}</td>
|
||||||
<td>
|
<td>
|
||||||
<form action="/admin/teams" method="post">
|
<form action="/admin/teams" method="post">
|
||||||
|
|||||||
Reference in New Issue
Block a user