diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/battle.go | 177 | ||||
-rw-r--r-- | src/db.go | 6 | ||||
-rw-r--r-- | src/main.go | 4 | ||||
-rw-r--r-- | src/user.go | 16 |
4 files changed, 182 insertions, 21 deletions
diff --git a/src/battle.go b/src/battle.go index e30cebd..01e9f8d 100644 --- a/src/battle.go +++ b/src/battle.go @@ -23,6 +23,7 @@ type Battle struct { Archs []Arch Bits []Bit RawOutput string + MaxRounds int } ////////////////////////////////////////////////////////////////////////////// @@ -32,8 +33,8 @@ func BattleGetAll() ([]Battle, error) { return globalState.GetAllBattles() } -func BattleCreate(name string, public bool) (int, error) { - return globalState.InsertBattle(Battle{Name: name, Public: public}) +func BattleCreate(name string, public bool, owner User) (int, error) { + return globalState.InsertBattle(Battle{Name: name, Public: public}, owner) } func BattleLinkBot(botid int, battleid int) error { @@ -64,10 +65,15 @@ func BattleSaveRawOutput(battleid int, rawOutput string) error { return globalState.UpdateBattleRawOutput(battleid, rawOutput) } +func BattleDeleteID(battleid int) error { + return globalState.DeleteBattleByID(battleid) +} + ////////////////////////////////////////////////////////////////////////////// // DATABASE -func (s *State) InsertBattle(battle Battle) (int, error) { +func (s *State) InsertBattle(battle Battle, owner User) (int, error) { + // create the battle res, err := s.db.Exec("INSERT INTO battles VALUES(NULL,?,?,?);", time.Now(), battle.Name, battle.Public) if err != nil { log.Println(err) @@ -79,6 +85,14 @@ func (s *State) InsertBattle(battle Battle) (int, error) { log.Println(err) return -1, err } + + // insert the owner into the battle_owner rel + _, err = s.db.Exec("INSERT INTO owner_battle_rel VALUES (?, ?)", owner.ID, battle.ID) + if err != nil { + log.Println(err) + return -1, err + } + return int(id), nil } @@ -219,6 +233,7 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) { var battlename string var battlepublic bool var battlerawoutput string + var battlemaxrounds int var botids string var botnames string @@ -239,10 +254,15 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) { // TODO(emile): go deeper! we could fetch battle -> bot -> arch (so fetching the linked arch // for the given bot) + // COALESCE is used to set default values + // TODO(emile): do fancy migrations instead of the COALESCE stuff for setting defaults if + // no value is set beforehand + err := s.db.QueryRow(` SELECT DISTINCT ba.id, ba.name, ba.public, COALESCE(ba.raw_output, ""), + COALESCE(ba.max_rounds, 100), COALESCE(group_concat(DISTINCT bb.bot_id), ""), COALESCE(group_concat(DISTINCT bo.name), ""), COALESCE(group_concat(DISTINCT ub.user_id), ""), @@ -267,7 +287,7 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) { WHERE ba.id=? GROUP BY ba.id; - `, id).Scan(&battleid, &battlename, &battlepublic, &battlerawoutput, &botids, &botnames, &userids, &usernames, &archids, &archnames, &bitids, &bitnames) + `, id).Scan(&battleid, &battlename, &battlepublic, &battlerawoutput, &battlemaxrounds, &botids, &botnames, &userids, &usernames, &archids, &archnames, &bitids, &bitnames) if err != nil { log.Println(err) return Battle{}, err @@ -361,6 +381,7 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) { Archs: archs, Bits: bits, RawOutput: battlerawoutput, + MaxRounds: battlemaxrounds, }, nil } @@ -373,6 +394,35 @@ func (s *State) UpdateBattleRawOutput(battleid int, rawOutput string) error { return nil } +// This deletes a battle and all links to users, bots, architectures and bits +func (s *State) DeleteBattleByID(battleid int) error { + _, err := s.db.Exec(` + DELETE FROM battles WHERE battleid = ?; + + DELETE FROM user_battle_rel WHERE battleid = ?; + DELETE FROM bot_battle_rel WHERE battleid = ?; + DELETE FROM arch_battle_rel WHERE battleid = ?; + DELETE FROM bit_battle_rel WHERE battleid = ?; + `, battleid, battleid, battleid, battleid, battleid) + + if err != nil { + log.Println(err) + return err + } + + _, err = s.db.Exec(` + DELETE FROM battles + WHERE battleid = ? + `, battleid) + + if err != nil { + log.Println(err) + return err + } + + return nil +} + ////////////////////////////////////////////////////////////////////////////// // HTTP @@ -498,6 +548,20 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) { t.ExecuteTemplate(w, "battleNew", data) case "POST": + data := map[string]interface{}{} + + session, _ := globalState.sessions.Get(r, "session") + username := session.Values["username"].(string) + + // get data needed + user, err := UserGetUserFromUsername(username) + if err != nil { + log.Println(err) + data["err"] = "Could not fetch the user" + } else { + data["user"] = user + } + // parse the post parameters r.ParseForm() name := r.Form.Get("name") @@ -538,7 +602,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) { if name != "" { // create the battle itself log.Println("Creating battle") - battleid, err := BattleCreate(name, public) + battleid, err := BattleCreate(name, public, user) if err != nil { log.Println(err) msg := "ERROR: Could not create due to internal reasons" @@ -631,6 +695,20 @@ func battleQuickHandler(w http.ResponseWriter, r *http.Request) { t.ExecuteTemplate(w, "battleQuick", data) case "POST": + data := map[string]interface{}{} + + session, _ := globalState.sessions.Get(r, "session") + username := session.Values["username"].(string) + + // get data needed + user, err := UserGetUserFromUsername(username) + if err != nil { + log.Println(err) + data["err"] = "Could not fetch the user" + } else { + data["user"] = user + } + // parse the post parameters r.ParseForm() @@ -658,7 +736,7 @@ func battleQuickHandler(w http.ResponseWriter, r *http.Request) { // create the battle itself log.Println("Creating battle") - battleid, err := BattleCreate("quick", public) + battleid, err := BattleCreate("quick", public, user) if err != nil { log.Println(err) msg := "ERROR: Could not create due to internal reasons" @@ -872,6 +950,20 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) { // at this point, we're sure the user is allowed to edit the battle + data := map[string]interface{}{} + + session, _ := globalState.sessions.Get(r, "session") + username := session.Values["username"].(string) + + // get data needed + user, err := UserGetUserFromUsername(username) + if err != nil { + log.Println(err) + data["err"] = "Could not fetch the user" + } else { + data["user"] = user + } + r.ParseForm() log.Println("r.Form: ", r.Form) @@ -919,7 +1011,7 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) { return } - new_battle := Battle{int(battleid), form_name, []Bot{}, []User{}, public, []Arch{}, []Bit{}, ""} + new_battle := Battle{int(battleid), form_name, []Bot{}, []User{user}, public, []Arch{}, []Bit{}, "", 100} log.Println("Updating battle...") err = BattleUpdate(new_battle) @@ -1220,12 +1312,65 @@ func battleRunHandler(w http.ResponseWriter, r *http.Request) { // delete a battle // TODO(emile): finish implementing the deletion of battles -// func battleDeleteHandler(w http.ResponseWriter, r *http.Request) { -// switch r.Method { -// case "DELETE": - -// http.Redirect(w, r, fmt.Sprintf("/battle?res=%s", battleid, msg), http.StatusSeeOther) -// default: -// http.Redirect(w, r, "/", http.StatusMethodNotAllowed) -// } -// } +func battleDeleteHandler(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + battleid, err := strconv.Atoi(vars["id"]) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("500 - Invalid battle id")) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + redir_target := fmt.Sprintf("/battle/%d?res=%%s", battleid) + + switch r.Method { + case "POST": // can't send a DELETE with pure HTML... + + // get the current user + session, _ := globalState.sessions.Get(r, "session") + username := session.Values["username"] + if username == nil { + http.Redirect(w, r, "/login", http.StatusSeeOther) + return + } + viewer, err := UserGetUserFromUsername(username.(string)) + if err != nil { + log_and_redir_with_msg(w, r, err, redir_target, "Could not get the id for your username") + return + } + + // get the battle + battle, err := BattleGetByIdDeep(int(battleid)) + if err != nil { + log_and_redir_with_msg(w, r, err, redir_target, "Could not get the battle given the id provided") + return + } + + battle_owned_by_requesting_user := false + for _, owner := range battle.Owners { + + // if the requesting users id is equal to an owners id, we're allowed to delete + // the battle + if viewer.ID == owner.ID { + battle_owned_by_requesting_user = true + break + } + } + + // check that the user that created the battle is the current user, if not, return + if battle_owned_by_requesting_user == false { + msg := "You aren't in the owners list of the battle, so you can't delete this battle" + log_and_redir_with_msg(w, r, err, redir_target, msg) + return + } + + BattleDeleteID(battleid) + + msg := "Successfully deleted the battle" + http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s", battleid, msg), http.StatusSeeOther) + default: + log.Println("expected POST, got ", r.Method) + http.Redirect(w, r, "/", http.StatusMethodNotAllowed) + } +} diff --git a/src/db.go b/src/db.go index 426ac52..42dc2d4 100644 --- a/src/db.go +++ b/src/db.go @@ -24,6 +24,7 @@ CREATE TABLE IF NOT EXISTS battles ( name TEXT, public BOOLEAN, raw_output TEXT + max_rounds INTEGER ); CREATE TABLE IF NOT EXISTS archs ( id INTEGER NOT NULL PRIMARY KEY, @@ -90,6 +91,11 @@ CREATE TABLE IF NOT EXISTS user_battle_rel ( battle_id INTEGER, PRIMARY KEY(user_id, battle_id) ); +CREATE TABLE IF NOT EXISTS owner_battle_rel ( + user_id INTEGER, + battle_id INTEGER, + PRIMARY KEY(user_id, battle_id) +); CREATE TABLE IF NOT EXISTS bot_battle_rel ( bot_id INTEGER, battle_id INTEGER, diff --git a/src/main.go b/src/main.go index 20c245a..c789cf8 100644 --- a/src/main.go +++ b/src/main.go @@ -30,7 +30,7 @@ func initFlags() { flag.StringVar(&logFilePath, "logfilepath", "./server.log", "The path to the log file") flag.StringVar(&databasePath, "databasepath", "./main.db", "The path to the main database") - flag.StringVar(&sessiondbPath, "sessiondbpath", "./sesions.db", "The path to the session database") + flag.StringVar(&sessiondbPath, "sessiondbpath", "./sessions.db", "The path to the session database") flag.StringVar(&templatesPath, "templates", "./templates", "The path to the templates used") } @@ -92,7 +92,7 @@ func main() { auth_needed.HandleFunc("/battle/quick", battleQuickHandler) auth_needed.HandleFunc("/battle/{id}/submit", battleSubmitHandler) auth_needed.HandleFunc("/battle/{id}/run", battleRunHandler) - // auth_needed.HandleFunc("/battle/{id}/delete", battleDeleteHandler) + auth_needed.HandleFunc("/battle/{id}/delete", battleDeleteHandler) log.Printf("[i] HTTP Server running on %s:%d\n", host, port) log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", host, port), r)) diff --git a/src/user.go b/src/user.go index d55c9d8..1fd9358 100644 --- a/src/user.go +++ b/src/user.go @@ -119,7 +119,9 @@ func (s *State) UpdateUserUsername(id int, new_username string) error { // Links the given bot to the given user in the user_bot_rel table func (s *State) LinkUserBot(username string, botid int) error { - _, err := s.db.Exec("INSERT INTO user_bot_rel VALUES ((SELECT id FROM users WHERE name=?), ?)", username, botid) + _, err := s.db.Exec(` + INSERT INTO user_bot_rel + VALUES ((SELECT id FROM users WHERE name=?), ?)`, username, botid) if err != nil { return err } else { @@ -153,7 +155,11 @@ func (s *State) GetUserFromUsername(username string) (User, error) { // Returns the bots belonging to the given user // TODO(emile): Also fetch the bits and the archs for displaying in the single battle page. In order to do so, join in both those tables func (s *State) GetUserBotsUsername(username string) ([]Bot, error) { - rows, err := s.db.Query("SELECT id, name, source FROM bots b LEFT JOIN user_bot_rel ub ON ub.bot_id = b.id WHERE ub.user_id=(SELECT id FROM users WHERE name=?)", username) + rows, err := s.db.Query(` + SELECT id, name, source + FROM bots b + LEFT JOIN user_bot_rel ub ON ub.bot_id = b.id + WHERE ub.user_id=(SELECT id FROM users WHERE name=?)`, username) defer rows.Close() if err != nil { return nil, err @@ -175,7 +181,11 @@ func (s *State) GetUserBotsUsername(username string) ([]Bot, error) { // Returns the bots belonging to the given user func (s *State) GetUserBotsId(id int) ([]Bot, error) { - rows, err := s.db.Query("SELECT id, name, source FROM bots b LEFT JOIN user_bot_rel ub ON ub.bot_id = b.id WHERE ub.user_id=?", id) + rows, err := s.db.Query(` + SELECT id, name, source + FROM bots b + LEFT JOIN user_bot_rel ub ON ub.bot_id = b.id + WHERE ub.user_id=?`, id) defer rows.Close() if err != nil { return nil, err |