package main import ( "database/sql" "encoding/json" //"errors" "fmt" "log" "net/http" "time" "github.com/gorilla/mux" "github.com/gorilla/sessions" "github.com/swaggo/http-swagger" _ "github.com/mattn/go-sqlite3" _ "games.dcu.ie/hvz/v2/docs" ) var store = sessions.NewCookieStore([]byte("wuhcwe789cui")) var db *sql.DB func get_all_players() []Player { rows, _ := db.Query("SELECT id FROM players") players := []Player{} var t_player Player var id string for rows.Next() { rows.Scan(&id) t_player, _ = get_player(id) players = append(players, t_player) } return players } func get_player(id string) (Player, error) { tmp_player := Player{} var last_tagged string var last_kill string time_format := time.RFC3339 row := db.QueryRow("SELECT * FROM players WHERE id = ?", id) err := row.Scan(&tmp_player.Id, &tmp_player.Name, &tmp_player.password, &tmp_player.State, &last_tagged, &tmp_player.Kills, &last_kill, &tmp_player.Cures, &tmp_player.Revives, &tmp_player.Extensions) tmp_player.Last_tagged, _ = time.Parse(time_format, last_tagged) tmp_player.Last_kill, _ = time.Parse(time_format, last_kill) if err != nil { return Player{}, err } return tmp_player, nil } func save_player(player Player) { tmp_id := "" row := db.QueryRow("SELECT id FROM players WHERE id = ?", player.Id) err := row.Scan(&tmp_id) var statement *sql.Stmt if err != nil { statement, _ = db.Prepare("INSERT INTO players (id, name, password, state, last_tagged, kills, last_kill, cures, revives, extensions) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") last_tagged, _ := player.Last_tagged.MarshalText() last_kill, _ := player.Last_kill.MarshalText() statement.Exec(player.Id, player.Name, player.password, player.State, last_tagged, player.Kills, last_kill, player.Cures, player.Revives, player.Extensions) } else { statement, err = db.Prepare("UPDATE players SET id = ?, name = ?, password = ?, state = ?, last_tagged = ?, kills = ?, last_kill = ?, cures = ?, revives = ?, extensions = ? WHERE id = ?") last_tagged, _ := player.Last_tagged.MarshalText() last_kill, _ := player.Last_kill.MarshalText() statement.Exec(player.Id, player.Name, player.password, player.State, last_tagged, player.Kills, last_kill, player.Cures, player.Revives, player.Extensions, player.Id) } } // @title DCU Games Society Humans Vs Zombies // @version 1.0 // @description This is the Swagger documentation for DCU Games Society's 2022 Humans Vs Zombies event. // @host // @BasePath / func handleRequests() { router := mux.NewRouter().StrictSlash(false) router.Path("/me").Methods(http.MethodGet).HandlerFunc(me) router.Path("/login").Methods(http.MethodPost).HandlerFunc(login) router.Path("/tag/{target}").Methods(http.MethodGet).HandlerFunc(tag) router.Path("/kill/{target}").Methods(http.MethodGet).HandlerFunc(kill) router.Path("/cure/{target}").Methods(http.MethodGet).HandlerFunc(cure) router.Path("/revive/{target}").Methods(http.MethodGet).HandlerFunc(revive) router.PathPrefix("/docs/").Handler(httpSwagger.WrapHandler) log.Fatal(http.ListenAndServe(":8000", router)) } // @Summary Login // @Description Login // @Produce json // @Accept json // @Param info body Login true "Player login" // @Success 200 {object} Player // @Router /login [post] func login(w http.ResponseWriter, r *http.Request) { l := Login{} if err := json.NewDecoder(r.Body).Decode(&l); err != nil { fmt.Println(err) http.Error(w, "Error decoding response object", http.StatusBadRequest) return } players := get_all_players() for _, player := range players { if (player.Name == l.Name && player.login(l.Pass)) { session, _ := store.Get(r, "session") session.Values["userID"] = player.Id session.Save(r, w) http.Redirect(w, r, "/me", http.StatusFound) return } } } // @Summary Tag // @Description Tag a human as a zombie. Gives target the infected state if user is a zombie or core zombie. // @Produce plain // @Param target path string true "Target ID" // @Success 200 // @Router /tag [get] func tag(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) target_id := vars["target"] sess, _ := store.Get(r, "session") id, ok := sess.Values["userID"] if !ok { http.Error(w, "User not logged in", http.StatusUnauthorized) return } player, _ := get_player(id.(string)) if (player.State != CoreZombie && player.State != Zombie) { http.Error(w, "Tagger is not a zombie", http.StatusForbidden) return } target, err := get_player(target_id) if (err != nil) { http.Error(w, "Target not found", http.StatusNotFound) return } if (target.State != Human) { http.Error(w, "Target not human", http.StatusConflict) return } target.State = InfectedHuman target.Last_tagged = time.Now() player.Last_kill = time.Now() player.Kills += 1 save_player(target) save_player(player) fmt.Fprintf(w, "Successfully tagged target") } // @Summary Kill // @Description Kills a zombie if user is authenticated as a human. Gives zombie target the stunned state // @Produce plain // @Param target path string true "Target ID" // @Success 200 // @Router /kill [get] func kill(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) target_id := vars["target"] sess, _ := store.Get(r, "session") id, ok := sess.Values["userID"] if !ok { http.Error(w, "User not logged in", http.StatusUnauthorized) return } tagger, _ := get_player(id.(string)) if (tagger.State != Human) { http.Error(w, "Killer is not a human", http.StatusForbidden) return } target, err := get_player(target_id) if err != nil { http.Error(w, "Target not found", http.StatusNotFound) return } if (target.State != Zombie && target.State != CoreZombie) { http.Error(w, "Target not a zombie", http.StatusConflict) } target.State = StunnedZombie target.Last_tagged = time.Now() tagger.Last_kill = time.Now() tagger.Kills += 1 save_player(target) save_player(tagger) fmt.Fprintln(w, "Successfully killed target") } // @Summary Me // @Description Shows user information // @Produce json // @Success 200 {object} Player // @Router /me [get] func me (w http.ResponseWriter, r *http.Request) { sess, _ := store.Get(r, "session") id, ok := sess.Values["userID"] if !ok { http.Error(w, "User not logged in", http.StatusUnauthorized) return } player, _ := get_player(id.(string)) json.NewEncoder(w).Encode(player) } // @Summary Cure // @Description Cures a zombie or infected human // @Produce plain // @Success 200 // @Param target path string true "Target ID" // @Router /cure [get] func cure(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) target_id := vars["target"] sess, _ := store.Get(r, "session") id, ok := sess.Values["userID"] if !ok { http.Error(w, "User not logged in", http.StatusUnauthorized) return } target, err := get_player(target_id) if err != nil { http.Error(w, "Target does not exist", http.StatusNotFound) return } player, _ := get_player(id.(string)) if player.Cures == 0 { http.Error(w, "Not enough cures", http.StatusForbidden) return } if (target.State != Zombie && target.State != StunnedZombie && target.State != InfectedHuman) { http.Error(w, "Target is not a zombie", http.StatusConflict) return } target.State = Human player.Cures -= 1 save_player(target) save_player(player) } // @Summary Revive // @Description Revives a stunned zombie // @Produce plain // @Success 200 // @Param target path string true "Target ID" // @Router /revive [get] func revive(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) target_id := vars["target"] sess, _ := store.Get(r, "session") id, ok := sess.Values["userID"] if !ok { http.Error(w, "User not logged in", http.StatusUnauthorized) return } target, err := get_player(target_id) if err != nil { http.Error(w, "Target does not exist", http.StatusNotFound) return } player, _ := get_player(id.(string)) if player.Revives == 0 { http.Error(w, "Not enough revives", http.StatusForbidden) return } if (target.State != StunnedZombie) { http.Error(w, "Target is not dead", http.StatusConflict) return } target.State = Zombie player.Revives -= 1 save_player(target) save_player(player) } func main() { db, _ = sql.Open("sqlite3", "players.db") statement, err := db.Prepare("CREATE TABLE IF NOT EXISTS players (id VARCHAR(7) PRIMARY KEY, name VARCHAR(64), password varchar(128), state INTEGER, last_tagged VARCHAR(25), kills INTEGER, last_kill VARCHAR(25), cures INTEGER, revives INTEGER, extensions INTEGER)") if err != nil { fmt.Println(err) } else { fmt.Println("table created successfully") } statement.Exec() player1 := new_player("Kyle", "fakepw", Human) player2 := new_player("Malachy Byrne", "testpw", CoreZombie) save_player(player1) save_player(player2) handleRequests() }