about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/battle.go1043
-rw-r--r--src/bot.go21
-rw-r--r--src/db.go10
-rw-r--r--src/main.go25
-rw-r--r--src/r2.go3
-rw-r--r--src/user.go60
6 files changed, 1026 insertions, 136 deletions
diff --git a/src/battle.go b/src/battle.go
index 7aa949a..af7043b 100644
--- a/src/battle.go
+++ b/src/battle.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"html/template"
 	"log"
+	"math/rand"
 	"net/http"
 	"os"
 	"strconv"
@@ -11,16 +12,20 @@ import (
 	"time"
 
 	"github.com/gorilla/mux"
+	"github.com/radareorg/r2pipe-go"
 )
 
 type Battle struct {
-	ID     int
-	Name   string
-	Bots   []Bot
-	Owners []User
-	Public bool
-	Archs  []Arch
-	Bits   []Bit
+	ID        int
+	Name      string
+	Bots      []Bot
+	Owners    []User
+	Public    bool
+	Archs     []Arch
+	Bits      []Bit
+	RawOutput string
+	MaxRounds int
+	ArenaSize int
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -30,14 +35,18 @@ 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(battle Battle, owner User) (int, error) {
+	return globalState.InsertBattle(battle, owner)
 }
 
 func BattleLinkBot(botid int, battleid int) error {
 	return globalState.LinkBotBattle(botid, battleid)
 }
 
+func BattleUnlinkAllBotsForUser(userid int, battleid int) error {
+	return globalState.UnlinkAllBotsForUserFromBattle(userid, battleid)
+}
+
 func BattleGetByIdDeep(id int) (Battle, error) {
 	return globalState.GetBattleByIdDeep(id)
 }
@@ -54,44 +63,130 @@ func BattleLinkBitIDs(battleid int, bitIDs []int) error {
 	return globalState.LinkBitIDsToBattle(battleid, bitIDs)
 }
 
+func BattleLinkOwnerIDs(battleid int, ownerIDs []int) error {
+	return globalState.LinkOwnerIDsToBattle(battleid, ownerIDs)
+}
+
+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) {
-	res, err := s.db.Exec("INSERT INTO battles VALUES(NULL,?,?,?);", time.Now(), battle.Name, battle.Public)
+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,
+		battle.RawOutput,
+		battle.MaxRounds,
+		battle.ArenaSize)
+
 	if err != nil {
+		log.Println(err)
 		return -1, err
 	}
 
 	var id int64
 	if id, err = res.LastInsertId(); err != nil {
+		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
 }
 
 func (s *State) UpdateBattle(battle Battle) error {
-	_, err := s.db.Exec("UPDATE battles SET name=?, public=? WHERE id=?", battle.Name, battle.Public, battle.ID)
+	log.Println("Updating battle:")
+	log.Println(battle.ArenaSize)
+	_, err := s.db.Exec(`
+		UPDATE battles
+		SET name=?, public=?, arena_size=?, max_rounds=?
+		WHERE id=?`,
+		battle.Name,
+		battle.Public,
+		battle.ArenaSize,
+		battle.MaxRounds,
+		battle.ID)
 	if err != nil {
+		log.Println(err)
 		return err
 	}
+	log.Println("Done updating")
 	return nil
 }
 
 func (s *State) LinkBotBattle(botid int, battleid int) error {
 	_, err := s.db.Exec("INSERT INTO bot_battle_rel VALUES (?, ?)", botid, battleid)
 	if err != nil {
-		log.Println("Error linking bot to battle: ", err)
+		log.Println(err)
+		return err
+	} else {
+		return nil
+	}
+}
+
+func (s *State) LinkOwnerBattle(battleid int, ownerid int) error {
+	_, err := s.db.Exec("INSERT INTO owner_battle_rel VALUES (?, ?)", ownerid, battleid)
+	if err != nil {
+		log.Println(err)
 		return err
 	} else {
 		return nil
 	}
 }
 
+func (s *State) UnlinkAllBotsForUserFromBattle(userid int, battleid int) error {
+	// get a user with the given id
+	// for all of their bots
+	// delete the bots from the bot_battle relation
+
+	// there are some joins to get through the following links:
+	// bot_battle_rel.bot_id
+	//   -> bot.id
+	//   -> user_bot_rel.bot_id
+	//   -> user_bot_rel.user_id
+	//   -> user.id
+
+	// delete preexisting links
+	_, err := s.db.Exec(`
+	DELETE FROM bot_battle_rel
+	WHERE bot_id IN
+		(SELECT b.id
+		 FROM bot_battle_rel bb_rel
+		 JOIN bots b ON b.id = bb_rel.bot_id
+		 JOIN user_bot_rel ub_rel ON ub_rel.bot_id = b.id
+		 JOIN users u ON u.id = ub_rel.user_id
+		 WHERE u.id=?)`, userid)
+
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+
+	return nil
+}
+
 func (s *State) LinkArchIDsToBattle(battleid int, archIDs []int) error {
 	// delete preexisting links
-	_, err := s.db.Exec("DELETE FROM arch_battle_rel WHERE battle_id=?;", battleid)
+	_, err := s.db.Exec("DELETE FROM arch_battle_rel WHERE battle_id=?", battleid)
 	if err != nil {
+		log.Println(err)
 		return err
 	}
 
@@ -109,7 +204,7 @@ func (s *State) LinkArchIDsToBattle(battleid int, archIDs []int) error {
 
 	_, err = s.db.Exec(query)
 	if err != nil {
-		log.Println("LinkArchIDsToBattle err: ", err)
+		log.Println(err)
 		return err
 	} else {
 		return nil
@@ -118,8 +213,9 @@ func (s *State) LinkArchIDsToBattle(battleid int, archIDs []int) error {
 
 func (s *State) LinkBitIDsToBattle(battleid int, bitIDs []int) error {
 	// delete preexisting links
-	_, err := s.db.Exec("DELETE FROM bit_battle_rel WHERE battle_id=?;", battleid)
+	_, err := s.db.Exec("DELETE FROM bit_battle_rel WHERE battle_id=?", battleid)
 	if err != nil {
+		log.Println(err)
 		return err
 	}
 
@@ -137,7 +233,36 @@ func (s *State) LinkBitIDsToBattle(battleid int, bitIDs []int) error {
 
 	_, err = s.db.Exec(query)
 	if err != nil {
-		log.Println("LinkBitIDsToBattle err: ", err)
+		log.Println(err)
+		return err
+	} else {
+		return nil
+	}
+}
+
+func (s *State) LinkOwnerIDsToBattle(battleid int, ownerIDs []int) error {
+	// delete preexisting links
+	_, err := s.db.Exec("DELETE FROM owner_battle_rel WHERE battle_id=?", battleid)
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+
+	// yes, we're building this by hand, but as we only insert int's I'm just confident that whoever
+	// gets some sqli here just deserves it :D
+	query := "INSERT INTO owner_battle_rel (user_id, battle_id) VALUES"
+	for idx, id := range ownerIDs {
+		query += fmt.Sprintf("(%d, %d)", id, battleid)
+		if idx != len(ownerIDs)-1 {
+			query += ", "
+		}
+	}
+	query += ";"
+	log.Println(query)
+
+	_, err = s.db.Exec(query)
+	if err != nil {
+		log.Println(err)
 		return err
 	} else {
 		return nil
@@ -148,6 +273,7 @@ func (s *State) GetAllBattles() ([]Battle, error) {
 	rows, err := s.db.Query("SELECT id, name FROM battles;")
 	defer rows.Close()
 	if err != nil {
+		log.Println(err)
 		return nil, err
 	}
 
@@ -171,6 +297,9 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 	var battleid int
 	var battlename string
 	var battlepublic bool
+	var battlerawoutput string
+	var battlemaxrounds int
+	var battlearenasize int
 
 	var botids string
 	var botnames string
@@ -184,21 +313,41 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 	var bitids string
 	var bitnames string
 
+	var ownerids string
+	var ownernames string
+
 	// battles have associated bots and users, we're fetching 'em all!
 
 	// This fetches the battles and relates the associated bots, users, archs and bits
 
+	// 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,
+		ba.id, ba.name, ba.public, 
+		COALESCE(ba.raw_output, ""),
+		COALESCE(ba.max_rounds, 100),
+		COALESCE(ba.arena_size, 4096),
+
 		COALESCE(group_concat(DISTINCT bb.bot_id), ""),
 		COALESCE(group_concat(DISTINCT bo.name), ""),
+
 		COALESCE(group_concat(DISTINCT ub.user_id), ""),
 		COALESCE(group_concat(DISTINCT us.name), ""),
+
 		COALESCE(group_concat(DISTINCT ab.arch_id), ""),
 		COALESCE(group_concat(DISTINCT ar.name), ""),
+
 		COALESCE(group_concat(DISTINCT bitbat.bit_id), ""),
-		COALESCE(group_concat(DISTINCT bi.name), "")
+		COALESCE(group_concat(DISTINCT bi.name), ""),
+
+		COALESCE(group_concat(DISTINCT ownerbat.user_id), ""),
+		COALESCE(group_concat(DISTINCT owner.name), "")
 	FROM battles ba
 
 	LEFT JOIN bot_battle_rel bb ON bb.battle_id = ba.id
@@ -213,26 +362,17 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 	LEFT JOIN bit_battle_rel bitbat ON bitbat.battle_id = ba.id
 	LEFT JOIN bits bi ON bi.id = bitbat.bit_id
 
+	LEFT JOIN owner_battle_rel ownerbat ON ownerbat.battle_id = ba.id
+	LEFT JOIN users owner ON owner.id = ownerbat.user_id
+
 	WHERE ba.id=?
 	GROUP BY ba.id;
-	`, id).Scan(&battleid, &battlename, &battlepublic, &botids, &botnames, &userids, &usernames, &archids, &archnames, &bitids, &bitnames)
+	`, id).Scan(&battleid, &battlename, &battlepublic, &battlerawoutput, &battlemaxrounds, &battlearenasize, &botids, &botnames, &userids, &usernames, &archids, &archnames, &bitids, &bitnames, &ownerids, &ownernames)
 	if err != nil {
-		log.Println("Err making GetBattleByID query: ", err)
+		log.Println(err)
 		return Battle{}, err
 	}
 
-	log.Println("battleid: ", battleid)
-	log.Println("battlename: ", battlename)
-	log.Println("battlepublic: ", battlepublic)
-	log.Println("botids: ", botids)
-	log.Println("botnames: ", botnames)
-	log.Println("userids: ", userids)
-	log.Println("usernames: ", usernames)
-	log.Println("archids: ", archids)
-	log.Println("archnames: ", archnames)
-	log.Println("bitids: ", bitids)
-	log.Println("bitnames: ", bitnames)
-
 	// The below is a wonderful examle of how golang could profit from macros
 	// I should just have done this all in common lisp tbh.
 
@@ -246,10 +386,10 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 
 	var bots []Bot
 	if botIDList[0] != "" {
-		for i, _ := range botIDList {
+		for i := range botIDList {
 			id, err := strconv.Atoi(botIDList[i])
 			if err != nil {
-				log.Println("Err handling bots: ", err)
+				log.Println(err)
 				return Battle{}, err
 			}
 			bots = append(bots, Bot{id, botNameList[i], "", []User{}, []Arch{}, []Bit{}})
@@ -264,10 +404,10 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 
 	var users []User
 	if userIDList[0] != "" {
-		for i, _ := range userIDList {
+		for i := range userIDList {
 			id, err := strconv.Atoi(userIDList[i])
 			if err != nil {
-				log.Println("Err handling users: ", err)
+				log.Println(err)
 				return Battle{}, err
 			}
 			users = append(users, User{id, userNameList[i], []byte{}})
@@ -282,10 +422,10 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 
 	var archs []Arch
 	if archIDList[0] != "" {
-		for i, _ := range archIDList {
+		for i := range archIDList {
 			id, err := strconv.Atoi(archIDList[i])
 			if err != nil {
-				log.Println("Err handling archs: ", err)
+				log.Println(err)
 				return Battle{}, err
 			}
 			archs = append(archs, Arch{id, archNameList[i], true})
@@ -300,10 +440,10 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 
 	var bits []Bit
 	if bitIDList[0] != "" {
-		for i, _ := range bitIDList {
+		for i := range bitIDList {
 			id, err := strconv.Atoi(bitIDList[i])
 			if err != nil {
-				log.Println("Err handling bits: ", err)
+				log.Println(err)
 				return Battle{}, err
 			}
 			bits = append(bits, Bit{id, bitNameList[i], true})
@@ -312,22 +452,74 @@ func (s *State) GetBattleByIdDeep(id int) (Battle, error) {
 		bits = []Bit{}
 	}
 
-	// return it all!
-	switch {
-	case err != nil:
-		log.Println("Overall err in the GetBattleByID func: ", err)
-		return Battle{}, err
-	default:
-		return Battle{
-			ID:     battleid,
-			Name:   battlename,
-			Bots:   bots,
-			Owners: users,
-			Public: battlepublic,
-			Archs:  archs,
-			Bits:   bits,
-		}, nil
+	// assemble the owners
+	ownerIDList := strings.Split(ownerids, ",")
+	ownerNameList := strings.Split(ownernames, ",")
+
+	var owners []User
+	if ownerIDList[0] != "" {
+		for i := range ownerIDList {
+			id, err := strconv.Atoi(ownerIDList[i])
+			if err != nil {
+				log.Println(err)
+				return Battle{}, err
+			}
+			owners = append(owners, User{id, ownerNameList[i], nil})
+		}
+	} else {
+		owners = []User{}
+	}
+
+	return Battle{
+		ID:        battleid,
+		Name:      battlename,
+		Bots:      bots,
+		Owners:    owners,
+		Public:    battlepublic,
+		Archs:     archs,
+		Bits:      bits,
+		RawOutput: battlerawoutput,
+		MaxRounds: battlemaxrounds,
+		ArenaSize: battlearenasize,
+	}, nil
+}
+
+func (s *State) UpdateBattleRawOutput(battleid int, rawOutput string) error {
+	_, err := s.db.Exec("UPDATE battles SET raw_output=? WHERE id=?", rawOutput, battleid)
+	if err != nil {
+		log.Println(err)
+		return err
+	}
+	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
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -346,18 +538,25 @@ func battlesHandler(w http.ResponseWriter, r *http.Request) {
 		}
 		data["pagelinknext"] = []Link{
 			{Name: "new", Target: "/new"},
+			{Name: "quick", Target: "/quick"},
 		}
 
 		// sessions
 		session, _ := globalState.sessions.Get(r, "session")
-		username := session.Values["username"].(string)
+		username := session.Values["username"]
 
-		// get the user
-		user, err := UserGetUserFromUsername(username)
-		if err != nil {
+		if username == nil {
 			http.Redirect(w, r, "/login", http.StatusSeeOther)
 			return
 		} else {
+			// get the user
+			user, err := UserGetUserFromUsername(username.(string))
+			if err != nil {
+				log.Println(err)
+				http.Redirect(w, r, "/login", http.StatusSeeOther)
+				return
+			}
+
 			data["user"] = user
 		}
 
@@ -368,7 +567,7 @@ func battlesHandler(w http.ResponseWriter, r *http.Request) {
 		// get the template
 		t, err := template.ParseGlob(fmt.Sprintf("%s/*.html", templatesPath))
 		if err != nil {
-			log.Printf("Error reading the template Path: %s/*.html", templatesPath)
+			log.Println(err)
 			w.WriteHeader(http.StatusInternalServerError)
 			w.Write([]byte("500 - Error reading template file"))
 			http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -400,6 +599,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 		data["pagelink2"] = Link{Name: "new", Target: "/new"}
 		data["pagelink2options"] = []Link{
 			{Name: "list", Target: ""},
+			{Name: "quick", Target: "/quick"},
 		}
 
 		// display errors passed via query parameters
@@ -411,6 +611,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 		// get data needed
 		user, err := UserGetUserFromUsername(username)
 		if err != nil {
+			log.Println(err)
 			data["err"] = "Could not fetch the user"
 		} else {
 			data["user"] = user
@@ -418,6 +619,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 
 		archs, err := ArchGetAll()
 		if err != nil {
+			log.Println(err)
 			data["err"] = "Could not fetch the archs"
 		} else {
 			data["archs"] = archs
@@ -425,15 +627,24 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 
 		bits, err := BitGetAll()
 		if err != nil {
+			log.Println(err)
 			data["err"] = "Could not fetch the bits"
 		} else {
 			data["bits"] = bits
 		}
 
+		users, err := UserGetAll()
+		if err != nil {
+			log.Println(err)
+			data["err"] = "Could not fetch all users"
+		} else {
+			data["users"] = users
+		}
+
 		// get the template
 		t, err := template.ParseGlob(fmt.Sprintf("%s/*.html", templatesPath))
 		if err != nil {
-			log.Printf("Error reading the template Path: %s/*.html", templatesPath)
+			log.Println(err)
 			w.WriteHeader(http.StatusInternalServerError)
 			w.Write([]byte("500 - Error reading template file"))
 			http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -441,12 +652,47 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		// exec!
-		t.ExecuteTemplate(w, "battleNew", data)
+		err = t.ExecuteTemplate(w, "battleNew", data)
+		if err != nil {
+			log.Println(err)
+		}
 
 	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")
+		arenasize, err := strconv.Atoi(r.Form.Get("arena-size"))
+		if err != nil {
+			// TODO(emile): use the log_and_redir function in here (and the surrounding code)
+
+			log.Println(err)
+			msg := "ERROR: Invalid arch id"
+			http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+		maxrounds, err := strconv.Atoi(r.Form.Get("max-rounds"))
+		if err != nil {
+			// TODO(emile): use the log_and_redir function in here (and the surrounding code)
+
+			log.Println(err)
+			msg := "ERROR: Invalid arch id"
+			http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
 
 		var public bool
 		query_public := r.Form.Get("public")
@@ -458,10 +704,11 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 		var archIDs []int
 		var bitIDs []int
 
-		for k, _ := range r.Form {
+		for k := range r.Form {
 			if strings.HasPrefix(k, "arch-") {
 				id, err := strconv.Atoi(strings.TrimPrefix(k, "arch-"))
 				if err != nil {
+					log.Println(err)
 					msg := "ERROR: Invalid arch id"
 					http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
 					return
@@ -471,6 +718,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 			if strings.HasPrefix(k, "bit-") {
 				id, err := strconv.Atoi(strings.TrimPrefix(k, "bit-"))
 				if err != nil {
+					log.Println(err)
 					msg := "ERROR: Invalid bit id"
 					http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
 					return
@@ -482,9 +730,21 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 		if name != "" {
 			// create the battle itself
 			log.Println("Creating battle")
-			battleid, err := BattleCreate(name, public)
+			newbattle := Battle{
+				0,
+				name,
+				nil,
+				nil,
+				public,
+				nil,
+				nil,
+				"",
+				maxrounds,
+				arenasize,
+			}
+			battleid, err := BattleCreate(newbattle, user)
 			if err != nil {
-				log.Println("Error creating the battle using BattleCreate(): ", err)
+				log.Println(err)
 				msg := "ERROR: Could not create due to internal reasons"
 				http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
 				return
@@ -493,7 +753,7 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 			// link archs to battle
 			err = BattleLinkArchIDs(battleid, archIDs)
 			if err != nil {
-				log.Println("Error linking the arch ids to the battle: ", err)
+				log.Println(err)
 				msg := "ERROR: Could not create due to internal reasons"
 				http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
 				return
@@ -502,7 +762,16 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 			// link bits to battle
 			err = BattleLinkBitIDs(battleid, bitIDs)
 			if err != nil {
-				log.Println("Error linking the bit ids to the battle: ", err)
+				log.Println(err)
+				msg := "ERROR: Could not create due to internal reasons"
+				http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
+				return
+			}
+
+			// link owner to battle
+			err = BattleLinkOwnerIDs(battleid, []int{user.ID})
+			if err != nil {
+				log.Println(err)
 				msg := "ERROR: Could not create due to internal reasons"
 				http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
 				return
@@ -520,14 +789,171 @@ func battleNewHandler(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
-// TODO(emile): add user creating battle as default owner
-// TODO(emile): allow adding other users as owners to battles
-// TODO(emile): implement submitting bots
-// TODO(emile): implement running the battle
-// TODO(emile): add a "start battle now" button
-// TODO(emile): add a "battle starts at this time" field into the battle
-// TODO(emile): figure out how time is stored and restored with the db
-// TODO(emile): do some magic to display the current fight backlog with all info
+func battleQuickHandler(w http.ResponseWriter, r *http.Request) {
+	switch r.Method {
+	case "GET":
+		// define data
+		data := map[string]interface{}{}
+		data["version"] = os.Getenv("VERSION")
+
+		// breadcrumb foo
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"].(string)
+		data["pagelink1"] = Link{Name: "battle", Target: "/battle"}
+		data["pagelink1options"] = []Link{
+			{Name: "user", Target: "/user"},
+			{Name: "bot", Target: "/bot"},
+		}
+		data["pagelink2"] = Link{Name: "quick", Target: "/quick"}
+		data["pagelink2options"] = []Link{
+			{Name: "new", Target: "/new"},
+			{Name: "list", Target: ""},
+		}
+
+		// display errors passed via query parameters
+		queryres := r.URL.Query().Get("err")
+		if queryres != "" {
+			data["res"] = queryres
+		}
+
+		// get data needed
+		user, err := UserGetUserFromUsername(username)
+		if err != nil {
+			log.Println(err)
+			data["err"] = "Could not fetch the user"
+		} else {
+			data["user"] = user
+		}
+
+		// essentiall... ...the list of all bots from which the user can select two that shall
+		// battle!
+		bots, err := globalState.GetAllBotsWithUsers()
+		data["bots"] = bots
+
+		// get the template
+		t, err := template.ParseGlob(fmt.Sprintf("%s/*.html", templatesPath))
+		if err != nil {
+			log.Println(err)
+			w.WriteHeader(http.StatusInternalServerError)
+			w.Write([]byte("500 - Error reading template file"))
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
+
+		// exec!
+		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()
+
+		var public bool
+		query_public := r.Form.Get("public")
+		if query_public == "on" {
+			public = true
+		}
+
+		arenasize, err := strconv.Atoi(r.Form.Get("arena-size"))
+		if err != nil {
+			// TODO(emile): use the log_and_redir function in here (and the surrounding code)
+
+			log.Println(err)
+			msg := "ERROR: Invalid arch id"
+			http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+		maxrounds, err := strconv.Atoi(r.Form.Get("max-rounds"))
+		if err != nil {
+			// TODO(emile): use the log_and_redir function in here (and the surrounding code)
+
+			log.Println(err)
+			msg := "ERROR: Invalid arch id"
+			http.Redirect(w, r, fmt.Sprintf("/battle/new?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		// gather the information from the arch and bit selection
+		var botIDs []int
+
+		for k := range r.Form {
+			if strings.HasPrefix(k, "bot-") {
+				id, err := strconv.Atoi(strings.TrimPrefix(k, "bot-"))
+				if err != nil {
+					log.Println(err)
+					msg := "ERROR: Invalid bot id"
+					http.Redirect(w, r, fmt.Sprintf("/battle/quick?res=%s", msg), http.StatusSeeOther)
+					return
+				}
+				botIDs = append(botIDs, id)
+			}
+		}
+
+		// create the battle itself
+		log.Println("Creating battle")
+		newbattle := Battle{
+			0,
+			fmt.Sprintf("quick-%d", rand.Intn(10000)),
+			nil,
+			nil,
+			public,
+			nil,
+			nil,
+			"",
+			maxrounds,
+			arenasize,
+		}
+		battleid, err := BattleCreate(newbattle, user)
+		if err != nil {
+			log.Println(err)
+			msg := "ERROR: Could not create due to internal reasons"
+			http.Redirect(w, r, fmt.Sprintf("/battle/quick?res=%s", msg), http.StatusSeeOther)
+			return
+		}
+
+		// allow all archs and all bits
+
+		// link bots to battle
+
+		http.Redirect(w, r, fmt.Sprintf("/battle/%d", battleid), http.StatusSeeOther)
+
+		//  // link archs to battle
+		//  err = BattleLinkArchIDs(battleid, archIDs)
+		//  if err != nil {
+		//  	log.Println(err)
+		//  	msg := "ERROR: Could not create due to internal reasons"
+		//  	http.Redirect(w, r, fmt.Sprintf("/battle/quick?res=%s", msg), http.StatusSeeOther)
+		//  	return
+		//  }
+
+		//  // link bits to battle
+		//  err = BattleLinkBitIDs(battleid, bitIDs)
+		//  if err != nil {
+		//  	log.Println(err)
+		//  	msg := "ERROR: Could not create due to internal reasons"
+		//  	http.Redirect(w, r, fmt.Sprintf("/battle/quick?res=%s", msg), http.StatusSeeOther)
+		//  	return
+		//  }
+
+		//  http.Redirect(w, r, "/battle", http.StatusSeeOther)
+		return
+	default:
+		http.Redirect(w, r, "/", http.StatusMethodNotAllowed)
+	}
+}
 
 func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 	vars := mux.Vars(r)
@@ -539,6 +965,9 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	// A partially filled format string (the reason for the redirect is still to be filled later)
+	redir_target := fmt.Sprintf("/battle/%d?res=%%s", battleid)
+
 	switch r.Method {
 	case "GET":
 		// define data
@@ -557,16 +986,33 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		session, _ := globalState.sessions.Get(r, "session")
-		username := session.Values["username"].(string)
+		username := session.Values["username"]
 
-		viewer, err := UserGetUserFromUsername(username)
+		if username == nil {
+			http.Redirect(w, r, "/login", http.StatusSeeOther)
+			return
+		}
+
+		viewer, err := UserGetUserFromUsername(username.(string))
 		if err != nil {
-			data["err"] = "Could not get the id four your username... Please contact an admin"
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get the id for your username")
+			return
 		}
 		data["user"] = viewer
 
+		users, err := UserGetAll()
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get the users")
+			return
+		}
+		data["users"] = users
+
 		// get the battle including it's users, bots, archs, bits
 		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
+		}
 		data["battle"] = battle
 		data["botAmount"] = len(battle.Bots)
 		data["battleCount"] = (len(battle.Bots) * len(battle.Bots)) * 2
@@ -582,10 +1028,9 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		data["pagelink2options"] = opts
 
 		// get the bots of the user viewing the page, as they might want to submit them
-		myBots, err := UserGetBotsUsingUsername(username)
+		myBots, err := UserGetBotsUsingUsername(username.(string))
 		if err != nil {
-			log.Println("err: ", err)
-			http.Redirect(w, r, fmt.Sprintf("/battle/%d", battleid), http.StatusSeeOther)
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get your bots")
 			return
 		}
 		data["myBots"] = myBots
@@ -593,7 +1038,8 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		// get all architectures and set the enable flag on the ones that are enabled in the battle
 		archs, err := ArchGetAll()
 		if err != nil {
-			data["err"] = "Could not fetch the archs"
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not get your bots")
+			return
 		} else {
 			data["archs"] = archs
 		}
@@ -609,7 +1055,8 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		// get all bits and set the enable flag on the ones that are enabled in the battle
 		bits, err := BitGetAll()
 		if err != nil {
-			data["err"] = "Could not fetch the bits"
+			log_and_redir_with_msg(w, r, err, redir_target, "Could not fetch the bits")
+			return
 		} else {
 			data["bits"] = bits
 		}
@@ -644,7 +1091,10 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		// exec!
-		t.ExecuteTemplate(w, "battleSingle", data)
+		err = t.ExecuteTemplate(w, "battleSingle", data)
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "err rendering template")
+		}
 
 	case "POST":
 		log.Println("POST!")
@@ -687,10 +1137,29 @@ 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)
 		form_name := r.Form.Get("name")
+		arenasize, err := strconv.Atoi(r.Form.Get("arena-size"))
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target, "Invalid Arena size")
+			return
+		}
 
 		var public bool
 		if r.Form.Get("public") == "on" {
@@ -700,13 +1169,15 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 		// gather the information from the arch and bit selection
 		var archIDs []int
 		var bitIDs []int
+		var ownerIDs []int
 
-		for k, _ := range r.Form {
+		log.Println(r.Form)
+
+		for k := range r.Form {
 			if strings.HasPrefix(k, "arch-") {
 				id, err := strconv.Atoi(strings.TrimPrefix(k, "arch-"))
 				if err != nil {
-					msg := "ERROR: Invalid arch id"
-					http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s#settings", battleid, msg), http.StatusSeeOther)
+					log_and_redir_with_msg(w, r, err, redir_target, "Invalid Arch ID")
 					return
 				}
 				archIDs = append(archIDs, id)
@@ -714,41 +1185,62 @@ func battleSingleHandler(w http.ResponseWriter, r *http.Request) {
 			if strings.HasPrefix(k, "bit-") {
 				id, err := strconv.Atoi(strings.TrimPrefix(k, "bit-"))
 				if err != nil {
-					msg := "ERROR: Invalid bit id"
-					http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s#settings", battleid, msg), http.StatusSeeOther)
+					log_and_redir_with_msg(w, r, err, redir_target, "Invalid Bit ID")
 					return
 				}
 				bitIDs = append(bitIDs, id)
 			}
+			if strings.HasPrefix(k, "owner-") {
+				id, err := strconv.Atoi(strings.TrimPrefix(k, "owner-"))
+				if err != nil {
+					log_and_redir_with_msg(w, r, err, redir_target, "Invalid Owner ID")
+					return
+				}
+				ownerIDs = append(ownerIDs, id)
+			}
+		}
+
+		// CHECK THAT THE USER REQUESTING CHANGES IS ALREADY PART OF THE OWNERS
+		allowedToEdit := false
+		for _, ownerID := range ownerIDs {
+			if user.ID == ownerID {
+				allowedToEdit = true
+			}
 		}
+		if allowedToEdit == false {
+			log_and_redir_with_msg(w, r, err, redir_target+"#settings", "You aren't an owner and aren't allowed to edit the settings")
+			return
+		}
+
+		// DATABASE MANIPUTLATION BELOW
 
 		// link archs to battle
 		err = BattleLinkArchIDs(battleid, archIDs)
 		if err != nil {
-			log.Println("Error linking the arch ids to the battle: ", err)
-			msg := "ERROR: Could not create due to internal reasons"
-			http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s#settings", battleid, msg), http.StatusSeeOther)
+			log_and_redir_with_msg(w, r, err, redir_target+"#settings", "Could not link arch id to battle")
 			return
 		}
 
 		// link bits to battle
 		err = BattleLinkBitIDs(battleid, bitIDs)
 		if err != nil {
-			log.Println("Error linking the bit ids to the battle: ", err)
-			msg := "ERROR: Could not create due to internal reasons"
-			http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s#settings", battleid, msg), http.StatusSeeOther)
+			log_and_redir_with_msg(w, r, err, redir_target+"#settings", "Could not link bit id to battle")
+			return
+		}
+
+		// link bits to battle
+		err = BattleLinkOwnerIDs(battleid, ownerIDs)
+		if err != nil {
+			log_and_redir_with_msg(w, r, err, redir_target+"#settings", "Could not link owner id to battle")
 			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, arenasize}
 
 		log.Println("Updating battle...")
 		err = BattleUpdate(new_battle)
 		if err != nil {
-			log.Println("err: ", err)
-			w.WriteHeader(http.StatusInternalServerError)
-			w.Write([]byte("500 - Error inserting battle into db"))
-			http.Error(w, err.Error(), http.StatusInternalServerError)
+			log_and_redir_with_msg(w, r, err, redir_target+"#settings", "Could not insert battle into db")
 			return
 		}
 
@@ -769,16 +1261,32 @@ func battleSubmitHandler(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	redir_target := fmt.Sprintf("/battle/%d?res=%%s", battleid)
+
 	switch r.Method {
 	case "POST":
 		r.ParseForm()
 
-		log.Println("Adding bot to battle", battleid)
+		log.Println("Someone submitted the following form:")
 		log.Println(r.Form)
 
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"]
+
+		if username == nil {
+			http.Redirect(w, r, "/login", http.StatusSeeOther)
+			return
+		}
+
+		user, 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 all the form values that contain the bot that shall be submitted
 		var botIDs []int
-		for k, _ := range r.Form {
+		for k := range r.Form {
 			if strings.HasPrefix(k, "bot-") {
 				id, err := strconv.Atoi(strings.TrimPrefix(k, "bot-"))
 				if err != nil {
@@ -790,15 +1298,15 @@ func battleSubmitHandler(w http.ResponseWriter, r *http.Request) {
 			}
 		}
 
-		log.Println(botIDs)
-
 		battle, err := BattleGetByIdDeep(battleid)
 		if err != nil {
 			msg := "ERROR: Couln't get the battle with the given id"
 			http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s", battleid, msg), http.StatusSeeOther)
 			return
 		}
-		log.Println(battle)
+
+		// clear all bots from that user for that battle before readding them here
+		BattleUnlinkAllBotsForUser(user.ID, battleid)
 
 		// for all bots, get their bits and arch and compare them to the one of the battle
 		for _, id := range botIDs {
@@ -851,3 +1359,326 @@ func battleSubmitHandler(w http.ResponseWriter, r *http.Request) {
 		http.Redirect(w, r, "/", http.StatusMethodNotAllowed)
 	}
 }
+
+// actually run the battle
+func battleRunHandler(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":
+		r.ParseForm()
+
+		log.Printf("running the battle with the id %d", battleid)
+		log.Println("Someone submitted the following form:")
+		log.Println(r.Form)
+
+		// fetch the session and get the user
+		session, _ := globalState.sessions.Get(r, "session")
+		username := session.Values["username"]
+		if username == nil {
+			http.Redirect(w, r, "/login", http.StatusSeeOther)
+			return
+		}
+		user, 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
+		}
+
+		// Fetch the battle information
+		// This includes all bots linked to the battle
+		log.Printf("user %+v wants to run the battle", user)
+		fullDeepBattle, err := BattleGetByIdDeep(battleid)
+
+		// open radare without input for building the bot
+		// TODO(emile): configure a variable memsize for the arena
+		cmd := fmt.Sprintf("malloc://%d", fullDeepBattle.ArenaSize)
+		r2p1, err := r2pipe.NewPipe(cmd)
+		if err != nil {
+			panic(err)
+		}
+		defer r2p1.Close()
+
+		var botSources []string
+		var rawOutput string
+
+		cmd = fmt.Sprintf("pxc %d @ 0x0", fullDeepBattle.ArenaSize)
+		output, _ := r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s\n", cmd, output)
+
+		// TODO(emile): currently hardcoded to two bots, extract this anonymous struct into a named struct and make this work with > 2 bots
+		runtimeBots := []struct {
+			Name     string
+			Regs     string
+			BaseAddr int
+			ArchName string
+			BitsName string
+		}{
+			{Name: "", Regs: "", BaseAddr: 0, ArchName: "", BitsName: ""},
+			{Name: "", Regs: "", BaseAddr: 0, ArchName: "", BitsName: ""},
+		}
+
+		rawOutput += "[0x00000000]> # Assembling the bots\n"
+
+		// for each bot involved within the battle, we need to fetch it again, as the deep battle
+		// fech doesn't fetch that deep (it fetches the batle and the corresponding bots, but only
+		// their ids and names and not the archs and bits associated)
+		for i, b := range fullDeepBattle.Bots {
+			bot, err := BotGetById(b.ID)
+			if err != nil {
+				log.Println(err)
+			}
+
+			runtimeBots[i].Name = bot.Name
+
+			// TODO(emile): a bot can have multiple archs/bits, figure out what to do then
+			// I've just gone and used the first one, as a bot alwas has at least one...
+			// ...it has right?
+			runtimeBots[i].ArchName = bot.Archs[0].Name
+			runtimeBots[i].BitsName = bot.Bits[0].Name
+
+			// define the command used to assemble the bot
+			src := strings.ReplaceAll(bot.Source, "\r\n", "; ")
+			radareCommand := fmt.Sprintf("rasm2 -a %s -b %s \"%+v\"", bot.Archs[0].Name, bot.Bits[0].Name, src)
+			rawOutput += fmt.Sprintf("; %s\n", radareCommand)
+
+			// assemble the bot
+			bytecode, err := r2cmd(r2p1, radareCommand)
+			if err != nil {
+				http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s", battleid, "err building bot"), http.StatusSeeOther)
+				return
+			}
+
+			botSources = append(botSources, bytecode)
+		}
+
+		// TODO(emile): [L] implement some kind of queue
+
+		rawOutput += "[0x00000000]> # initializing the vm and the stack\n"
+		cmd = "aei"
+		output, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s", cmd, output)
+
+		cmd = "aeim"
+		output, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s", cmd, output)
+
+		// TODO(emile): random offsets
+		// place bots
+		for i, s := range botSources {
+
+			// the address to write the bot to
+			addr := 50 * (i + 1)
+
+			// store it
+			runtimeBots[i].BaseAddr = addr
+
+			msg := fmt.Sprintf("# writing bot %d to 0x%d", i, addr)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", msg)
+			cmd := fmt.Sprintf("wx %s @ 0x%d", s, addr)
+			_, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+			// define the instruction point and the stack pointer
+			rawOutput += "[0x00000000]> # Setting the program counter and the stack pointer\n"
+			cmd = fmt.Sprintf("aer PC=0x%d", addr)
+			_, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+			cmd = fmt.Sprintf("aer SP=SP+0x%d", addr)
+			_, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+			// dump the registers of the bot for being able to switch inbetween them
+			// This is done in order to be able to play one step of each bot at a time,
+			// but sort of in parallel
+			rawOutput += "[0x00000000]> # Storing registers\n"
+			cmd = "aerR"
+			regs, _ := r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+			initialRegisers := strings.Replace(regs, "\n", ";", -1)
+			runtimeBots[i].Regs = initialRegisers
+		}
+
+		for i := range botSources {
+			// print the memory for some pleasing visuals
+			cmd = fmt.Sprintf("pxc 100 @ 0x%d", runtimeBots[i].BaseAddr)
+			output, _ = r2cmd(r2p1, cmd) // print
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s\n", cmd, output)
+		}
+
+		output, _ = r2cmd(r2p1, "pxc 100 @ 0x50") // print
+		fmt.Println(output)
+
+		// define end conditions
+		rawOutput += "[0x00000000]> # Defining the end conditions\n"
+		cmd = "e cmd.esil.todo=t theend=1"
+		_, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+		cmd = "e cmd.esil.trap=t theend=1"
+		_, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+		cmd = "e cmd.esil.intr=t theend=1"
+		_, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+		cmd = "e cmd.esil.ioer=t theend=1"
+		_, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+		// set the end condition to 0 initially
+		rawOutput += "[0x00000000]> # Initializing the end condition variable\n"
+		cmd = "f theend=0"
+		_, _ = r2cmd(r2p1, cmd)
+		rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+		currentBotId := 0
+
+		// TODO(emile): find a sensible default for the max amount of rounds
+		for i := 0; i < fullDeepBattle.MaxRounds; i++ {
+
+			currentBotId = i % 2
+
+			rawOutput += fmt.Sprintf("[0x00000000]> ########################################################################\n")
+
+			rawOutput += "[0x00000000]> # Loading the registers\n"
+			r2cmd(r2p1, runtimeBots[currentBotId].Regs)
+
+			// this is architecture agnostic and just gets the program counter
+			pc, _ := r2cmd(r2p1, "aer~$(arn PC)~[1]")
+
+			arch, _ := r2cmd(r2p1, "e asm.arch")
+			bits, _ := r2cmd(r2p1, "e asm.bits")
+			rawOutput += fmt.Sprintf("[0x00000000]> # ROUND %d, BOT %d (%s), PC=%s, arch=%s, bits=%s\n", i, currentBotId, runtimeBots[currentBotId].Name, pc, arch, bits)
+
+			rawOutput += "[0x00000000]> # setting the architecture accordingly\n"
+			cmd = fmt.Sprintf("e asm.arch=%s", runtimeBots[currentBotId].ArchName)
+			output, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s", cmd, output)
+
+			cmd = fmt.Sprintf("e asm.bits=%s", runtimeBots[currentBotId].BitsName)
+			output, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s", cmd, output)
+
+			// load registers
+			//  rawOutput += fmt.Sprintf("%+v\n", runtimeBots[currentBotId].Regs)
+
+			//  cmd = "dr"
+			//  output, _ = r2cmd(r2p1, cmd)
+			//  rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s\n", cmd, output)
+
+			//  _, _ = r2cmd(r2p1, "aes") // step
+			rawOutput += "[0x00000000]> # Stepping\n"
+			cmd = "aes"
+			_, _ = r2cmd(r2p1, cmd)
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n", cmd)
+
+			// store the regisers
+			rawOutput += "[0x00000000]> # Storing the registers\n"
+			registers, _ := r2cmd(r2p1, "aerR")
+			registersStripped := strings.Replace(registers, "\n", ";", -1)
+			runtimeBots[currentBotId].Regs = registersStripped
+
+			// print the arena
+			rawOutput += "[0x00000000]> # Printing the arena\n"
+			cmd := fmt.Sprintf("pxc 100 @ 0x%d", runtimeBots[currentBotId].BaseAddr)
+			output, _ := r2cmd(r2p1, cmd) // print
+			rawOutput += fmt.Sprintf("[0x00000000]> %s\n%s\n", cmd, output)
+			//  fmt.Println(output)
+
+			// predicate - the end?
+			rawOutput += "[0x00000000]> # Checking if we've won\n"
+			pend, _ := r2cmd(r2p1, "?v theend")
+			status := strings.TrimSpace(pend)
+			// fixme: on Windows, we sometimes get output *from other calls to r2*
+
+			if status == "0x1" {
+				log.Printf("[!] Bot %d has died", currentBotId)
+			}
+			if status != "0x0" {
+				log.Printf("[!] Got invalid status '%s' for bot %d", status, currentBotId)
+			}
+		}
+
+		BattleSaveRawOutput(battleid, rawOutput)
+
+		msg := "Success!"
+		http.Redirect(w, r, fmt.Sprintf("/battle/%d?res=%s#output", battleid, msg), http.StatusSeeOther)
+	default:
+		http.Redirect(w, r, "/", http.StatusMethodNotAllowed)
+	}
+}
+
+// delete a battle
+// TODO(emile): finish implementing the deletion of battles
+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/bot.go b/src/bot.go
index a2e8c99..65c1c29 100644
--- a/src/bot.go
+++ b/src/bot.go
@@ -111,22 +111,15 @@ func (s *State) GetBotById(id int) (Bot, error) {
 
 	WHERE bo.id=?
 	GROUP BY bo.id;
-	`, id).Scan(&botid, &botname, &botsource, &ownerids, &ownernames, &archids, &archnames, &bitids, &bitnames)
+	`, id).Scan(&botid, &botname, &botsource,
+		&ownerids, &ownernames,
+		&archids, &archnames,
+		&bitids, &bitnames)
 	if err != nil {
 		log.Println(err)
 		return Bot{}, err
 	}
 
-	// log.Println("botid: ", botid)
-	// log.Println("botname: ", botname)
-	// log.Println("botsource: ", botsource)
-	// log.Println("ownerids: ", ownerids)
-	// log.Println("ownernames: ", ownernames)
-	// log.Println("archid: ", archids)
-	// log.Println("archname: ", archnames)
-	// log.Println("bitid: ", bitids)
-	// log.Println("bitname: ", bitnames)
-
 	ownerIDList := strings.Split(ownerids, ",")
 	ownerNameList := strings.Split(ownernames, ",")
 
@@ -181,6 +174,7 @@ func (s *State) GetBotById(id int) (Bot, error) {
 		log.Println("ERR4: ", err)
 		return Bot{}, err
 	default:
+		//  log.Printf("returning bot with archs %+v and bits %+v", archs, bits)
 		return Bot{botid, botname, botsource, users, archs, bits}, nil
 	}
 }
@@ -430,6 +424,7 @@ func botSingleHandler(w http.ResponseWriter, r *http.Request) {
 			data["res"] = queryres
 		}
 
+		// fetch the session and get the user that made the request
 		session, _ := globalState.sessions.Get(r, "session")
 		username := session.Values["username"].(string)
 
@@ -438,6 +433,7 @@ func botSingleHandler(w http.ResponseWriter, r *http.Request) {
 			data["err"] = "Could not get the id four your username... Please contact an admin"
 		}
 
+		// get the bot that was requested
 		bot, err := BotGetById(int(botid))
 		data["bot"] = bot
 		data["user"] = viewer
@@ -449,6 +445,9 @@ func botSingleHandler(w http.ResponseWriter, r *http.Request) {
 		}
 		defer r2p1.Close()
 
+		// TODO(emile): improve the archs and bit handling here. I'll use the first one for now,
+		// but it would be nice to loop over all of them (would be a matrix with archs and bits
+		// on the axes)
 		src := strings.ReplaceAll(bot.Source, "\r\n", "; ")
 		radareCommand := fmt.Sprintf("rasm2 -a %s -b %s \"%+v\"", bot.Archs[0].Name, bot.Bits[0].Name, src)
 		bytecode, err := r2cmd(r2p1, radareCommand)
diff --git a/src/db.go b/src/db.go
index 47d8158..8983df9 100644
--- a/src/db.go
+++ b/src/db.go
@@ -22,7 +22,10 @@ CREATE TABLE IF NOT EXISTS battles (
 	id INTEGER NOT NULL PRIMARY KEY,
 	created_at DATETIME NOT NULL,
 	name TEXT,
-	public BOOLEAN
+	public BOOLEAN,
+	raw_output TEXT,
+	max_rounds INTEGER,
+	arena_size INTEGER
 );
 CREATE TABLE IF NOT EXISTS archs (
 	id INTEGER NOT NULL PRIMARY KEY,
@@ -89,6 +92,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 65a3212..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")
 }
 
@@ -86,11 +86,30 @@ func main() {
 	auth_needed.HandleFunc("/user/{id}", userHandler)
 	auth_needed.HandleFunc("/user/{id}/profile", profileHandler)
 
-	auth_needed.HandleFunc("/battle", battlesHandler)
+	r.HandleFunc("/battle", battlesHandler)
+	r.HandleFunc("/battle/{id}", battleSingleHandler)
 	auth_needed.HandleFunc("/battle/new", battleNewHandler)
-	auth_needed.HandleFunc("/battle/{id}", battleSingleHandler)
+	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)
 
 	log.Printf("[i] HTTP Server running on %s:%d\n", host, port)
 	log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", host, port), r))
 }
+
+/* Convenience functions */
+
+// log_and_redir_with_msg takes a few args, let's go through them one by one:
+//   - w: the response writer
+//   - r: the initial request
+//   - err: the error that occurred, this one will be logged
+//   - target: the target of the redirect, this must be a format string with some format parameter
+//     receiving a string, for example `/battles/?err=%s`, the `%s` format string will then be
+//     filled with the message
+//   - msg: the message to print after being redirected
+func log_and_redir_with_msg(w http.ResponseWriter, r *http.Request, err error, target string, msg string) {
+	log.Println(err)
+	http.Redirect(w, r, fmt.Sprintf(target, msg), http.StatusSeeOther)
+	return
+}
diff --git a/src/r2.go b/src/r2.go
index 6ecd24b..d736f59 100644
--- a/src/r2.go
+++ b/src/r2.go
@@ -7,10 +7,7 @@ import (
 )
 
 func r2cmd(r2p *r2pipe.Pipe, input string) (string, error) {
-
-	log.Println("---")
 	log.Printf("> %s\n", input)
-	log.Println("---")
 
 	// send a command
 	buf1, err := r2p.Cmd(input)
diff --git a/src/user.go b/src/user.go
index 48bc299..cbedf03 100644
--- a/src/user.go
+++ b/src/user.go
@@ -71,6 +71,10 @@ func UserGetAll() ([]User, error) {
 	return globalState.GetAllUsers()
 }
 
+func UserGetUsernameCount(username string) (int, error) {
+	return globalState.GetUsernameCount(username)
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // DATABASE
 
@@ -119,7 +123,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 {
@@ -151,8 +157,13 @@ 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
@@ -174,7 +185,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
@@ -216,15 +231,36 @@ func (s *State) GetAllUsers() ([]User, error) {
 	return users, nil
 }
 
+func (s *State) GetUsernameCount(username string) (int, error) {
+	rows, err := s.db.Query(`
+		SELECT COUNT(*)
+		FROM users
+		WHERE name=?`, username)
+	defer rows.Close()
+	if err != nil {
+		return -1, err
+	}
+
+	var count int
+	rows.Next()
+	if err := rows.Scan(&count); err != nil {
+		return -1, err
+	}
+	if err = rows.Err(); err != nil {
+		return -1, err
+	}
+	return count, nil
+}
+
+//  return globalState.GetUsernameCount(username)
+
 //////////////////////////////////////////////////////////////////////////////
 // HTTP
 
 func loginHandler(w http.ResponseWriter, r *http.Request) {
 	switch r.Method {
 	case "GET":
-		log.Println("GET /login")
 		// define data
-		log.Println("[d] Defining breadcrumbs")
 		data := map[string]interface{}{}
 		data["version"] = os.Getenv("VERSION")
 		data["pagelink1"] = Link{"login", "/login"}
@@ -236,7 +272,6 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		// session foo
-		log.Println("[d] Getting session")
 		session, _ := globalState.sessions.Get(r, "session")
 		username := session.Values["username"]
 
@@ -245,7 +280,6 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
 			log.Printf("[d] Getting the user %s\n", username.(string))
 			user, err := UserGetUserFromUsername(username.(string))
 			if user.Name == "" {
-				log.Println("no user found")
 			} else if err != nil {
 				log.Println(err)
 				msg := "Error: could not get the user for given username"
@@ -257,14 +291,12 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		// display errors passed via query parameters
-		log.Println("[d] Getting previous results")
 		queryres := r.URL.Query().Get("res")
 		if queryres != "" {
 			data["res"] = queryres
 		}
 
 		// get the template
-		log.Println("[d] Getting the template")
 		t, err := template.ParseGlob(fmt.Sprintf("%s/*.html", templatesPath))
 		if err != nil {
 			log.Printf("Error reading the template Path: %s/*.html", templatesPath)
@@ -275,7 +307,6 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
 		}
 
 		// exec!
-		log.Println("[d] Executing the template")
 		t.ExecuteTemplate(w, "login", data)
 
 	case "POST":
@@ -337,8 +368,6 @@ func registerHandler(w http.ResponseWriter, r *http.Request) {
 			{Name: "login/", Target: "/login"},
 		}
 
-		log.Println(username)
-
 		if username != nil {
 			data["logged_in"] = true
 		}
@@ -381,6 +410,13 @@ func registerHandler(w http.ResponseWriter, r *http.Request) {
 			return
 		}
 
+		// Fetch all users and check that there isn't another user with the name here
+		if _, err := UserGetUsernameCount(username); err != nil {
+			w.WriteHeader(http.StatusInternalServerError)
+			w.Write([]byte("500 - Oi', Backend here! That username has already been taken!"))
+			return
+		}
+
 		// if we've got a password, hash it and store it and create a User
 		if password1 != "" {
 			passwordHash := argon2.IDKey([]byte(password1), []byte(os.Getenv("SALT")), 1, 64*1024, 4, 32)