diff --git a/server.go b/server.go index 06f687b..2295408 100644 --- a/server.go +++ b/server.go @@ -3,7 +3,6 @@ package main import ( "database/sql" "encoding/json" - "fmt" "html/template" "log" "net/http" @@ -106,9 +105,100 @@ func handleGetRoot(w http.ResponseWriter, r *http.Request) { } } -func handleGetPing(w http.ResponseWriter, r *http.Request) { - log.Printf("[*] Received request %v %v\n", r.Method, r.URL) - fmt.Fprintf(w, "PONG\n") +func handleGetResult(w http.ResponseWriter, r *http.Request) { + pollId, err := strconv.Atoi(r.PathValue("pollId")) + if err != nil { + log.Printf("[!] Invallid poll id url segment, error: %s\n", err) + http.Error(w, "Poll not found", http.StatusBadRequest) + return + } + + const query = ` + SELECT polls.name, choices.username, choices.choices + FROM choices + JOIN polls ON choices.pollid = polls.id + WHERE choices.pollid = ? + ` + + rows, err := db.Query(query, pollId) + defer rows.Close() + if err != nil { + log.Printf("[!] No poll with id %d was found, error: %s\n", pollId, err) + http.Error(w, "Poll not found", http.StatusBadRequest) + return + } + + var results []struct { + pollName string + username string + choices string + } + for rows.Next() { + var pollName string + var username string + var choices string + if err := rows.Scan(&pollName, &username, &choices); err != nil { + log.Printf("[!] Could not scan result row %v, error: %s\n", rows, err) + } + results = append(results, struct { + pollName string + username string + choices string + }{ + pollName: pollName, + username: username, + choices: choices, + }) + } + + type HourlyVote struct { + Usernames []string `json:"usernames"` + Votes int `json:"votes"` + } + + type PollResult struct { + Id int `json:"id"` + Name string `json:"name"` + Votes [7][24]HourlyVote `json:"votes"` + } + + var pollResult PollResult + + pollResult.Id = pollId + pollResult.Name = results[0].pollName + + for i := 0; i < 7; i++ { + for j := 0; j < 24; j++ { + pollResult.Votes[i][j] = HourlyVote{ + Usernames: []string{}, + Votes: 0, + } + } + } + + for _, result := range results { + var choices [][]bool + err := json.Unmarshal([]byte(result.choices), &choices) + if err != nil { + log.Printf("[!] Could not unmarshal choices %s, error: %s\n", result.choices, err) + continue + } + + for didx, day := range choices { + for hidx, hour := range day { + if hour { + pollResult.Votes[didx][hidx].Usernames = + append(pollResult.Votes[didx][hidx].Usernames, result.username) + pollResult.Votes[didx][hidx].Votes++ + } + } + } + } + + w.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(w).Encode(pollResult); err != nil { + http.Error(w, "Failed to encode JSON", http.StatusInternalServerError) + } } func handlePostSubmit(w http.ResponseWriter, r *http.Request) { @@ -173,11 +263,6 @@ func main() { prepareStaticContent() - http.HandleFunc( - "GET /api/ping", - handleGetPing, - ) - http.HandleFunc( "GET /favicon.ico", func(w http.ResponseWriter, r *http.Request) { @@ -190,6 +275,11 @@ func main() { handleGetRoot, ) + http.HandleFunc( + "GET /{pollId}/result", + handleGetResult, + ) + http.HandleFunc( "POST /api/submit", handlePostSubmit,