From ae914b9f7a593ac83ebca9b15eba6ea79524ae4c Mon Sep 17 00:00:00 2001 From: Arda Serdar Pektezol <1669855+pektezol@users.noreply.github.com> Date: Sat, 14 Jan 2023 02:44:36 +0300 Subject: record submission looks like its working! (#23, #20) --- backend/controllers/homeController.go | 6 +- backend/controllers/recordController.go | 140 ++++++++++++++++++++++---------- backend/controllers/userController.go | 2 +- backend/database/init.sql | 37 +++++++-- backend/models/models.go | 15 ++-- go.mod | 2 +- 6 files changed, 137 insertions(+), 65 deletions(-) diff --git a/backend/controllers/homeController.go b/backend/controllers/homeController.go index 8d81eef..635038b 100644 --- a/backend/controllers/homeController.go +++ b/backend/controllers/homeController.go @@ -33,21 +33,21 @@ func Login(c *gin.Context) { default: steamID, err := openID.ValidateAndGetId() if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return } // Create user if new var checkSteamID int64 err = database.DB.QueryRow("SELECT steam_id FROM users WHERE steam_id = $1", steamID).Scan(&checkSteamID) if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return } // User does not exist if checkSteamID == 0 { user, err := steam_go.GetPlayerSummaries(steamID, os.Getenv("API_KEY")) if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return } // Insert new user to database diff --git a/backend/controllers/recordController.go b/backend/controllers/recordController.go index a44d6f6..81eb465 100644 --- a/backend/controllers/recordController.go +++ b/backend/controllers/recordController.go @@ -3,14 +3,14 @@ package controllers import ( "context" b64 "encoding/base64" - "fmt" "io" "log" "net/http" "os" - "time" + "strconv" "github.com/gin-gonic/gin" + "github.com/google/uuid" "github.com/pektezol/leastportals/backend/database" "github.com/pektezol/leastportals/backend/models" "golang.org/x/oauth2/google" @@ -23,73 +23,125 @@ func CreateRecordWithDemo(c *gin.Context) { // Check if user exists user, exists := c.Get("user") if !exists { - c.JSON(http.StatusUnauthorized, gin.H{ - "code": http.StatusUnauthorized, - "output": gin.H{ - "error": "User not logged in. Could be invalid token.", - }, - }) + c.JSON(http.StatusUnauthorized, models.ErrorResponse("User not logged in.")) return } - var record models.Record - err := c.Bind(&record) + // Check if map is sp or mp + var isCoop bool + err := database.DB.QueryRow(`SELECT is_coop FROM maps WHERE id = $1;`, mapId).Scan(&isCoop) if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return } - var recordCount int - err = database.DB.QueryRow(`SELECT COUNT(id) FROM records;`).Scan(&recordCount) + // Get record request + var record models.Record + score_count, err := strconv.Atoi(c.PostForm("score_count")) if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return } - // var mapName string - // err = database.DB.QueryRow(`SELECT map_name FROM maps WHERE id = $1;`, mapId).Scan(&mapName) - // if err != nil { - // c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) - // return - // } - outputDemoName := fmt.Sprintf("%s_%s_%d", time.Now().UTC().Format("2006-01-02"), user.(models.User).SteamID, recordCount) - header, err := c.FormFile("file") + score_time, err := strconv.Atoi(c.PostForm("score_time")) if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return } - err = c.SaveUploadedFile(header, "docs/"+header.Filename) + is_partner_orange, err := strconv.ParseBool(c.PostForm("is_partner_orange")) if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return } - f, err := os.Open("docs/" + header.Filename) + record.ScoreCount = score_count + record.ScoreTime = score_time + record.PartnerID = c.PostForm("partner_id") + record.IsPartnerOrange = is_partner_orange + // Multipart form + form, err := c.MultipartForm() if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + c.String(http.StatusBadRequest, "get form err: %s", err.Error()) return } - defer f.Close() - client := serviceAccount() - srv, err := drive.New(client) - if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + files := form.File["demos"] + if len(files) != 2 && isCoop { + c.JSON(http.StatusBadRequest, models.ErrorResponse("Not enough demos for coop submission.")) return } - file, err := createFile(srv, outputDemoName, "application/octet-stream", f, os.Getenv("GOOGLE_FOLDER_ID")) - if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + if len(files) != 1 && !isCoop { + c.JSON(http.StatusBadRequest, models.ErrorResponse("Too many demos for singleplayer submission.")) return } - os.Remove("docs/" + header.Filename) - // Demo upload success - // Insert record into database - sql := `INSERT INTO records(map_id,host_id,score_count,score_time,is_coop,partner_id,demo_id) - VALUES ($1, $2, $3, $4, $5, $6, $7);` - _, err = database.DB.Exec(sql, mapId, user.(models.User).SteamID, record.ScoreCount, record.ScoreTime, record.IsCoop, record.PartnerID, file.Id) - if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) - return + var hostDemoUUID string + var partnerDemoUUID string + for i, header := range files { + uuid := uuid.New().String() + // Upload & insert into demos + err = c.SaveUploadedFile(header, "docs/"+header.Filename) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + f, err := os.Open("docs/" + header.Filename) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + defer f.Close() + client := serviceAccount() + srv, err := drive.New(client) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + file, err := createFile(srv, uuid, "application/octet-stream", f, os.Getenv("GOOGLE_FOLDER_ID")) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + if i == 0 { + hostDemoUUID = uuid + } + if i == 1 { + partnerDemoUUID = uuid + } + _, err = database.DB.Exec(`INSERT INTO demos (id,location_id) VALUES ($1,$2)`, uuid, file.Id) + if err != nil { + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + os.Remove("docs/" + header.Filename) + } + // Insert into records + if isCoop { + sql := `INSERT INTO records_mp(map_id,score_count,score_time,host_id,partner_id,host_demo_id,partner_demo_id) + VALUES($1, $2, $3, $4, $5, $6, $7);` + var hostID string + var partnerID string + if record.IsPartnerOrange { + hostID = user.(models.User).SteamID + partnerID = record.PartnerID + } else { + partnerID = user.(models.User).SteamID + hostID = record.PartnerID + } + _, err := database.DB.Exec(sql, mapId, record.ScoreCount, record.ScoreTime, hostID, partnerID, hostDemoUUID, partnerDemoUUID) + if err != nil { + _, err = database.DB.Exec(`DELETE FROM demos WHERE id = $1 OR id = $2;`, hostDemoUUID, partnerDemoUUID) + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } + } else { + sql := `INSERT INTO records_sp(map_id,score_count,score_time,user_id,demo_id) + VALUES($1, $2, $3, $4, $5);` + _, err := database.DB.Exec(sql, mapId, record.ScoreCount, record.ScoreTime, user.(models.User).SteamID, hostDemoUUID) + if err != nil { + _, err = database.DB.Exec(`DELETE FROM demos WHERE id = $1;`, hostDemoUUID) + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) + return + } } c.JSON(http.StatusOK, models.Response{ Success: true, Message: "Successfully created record.", + Data: record, }) return } diff --git a/backend/controllers/userController.go b/backend/controllers/userController.go index 70a2a34..b23a303 100644 --- a/backend/controllers/userController.go +++ b/backend/controllers/userController.go @@ -49,7 +49,7 @@ func FetchUser(c *gin.Context) { return } if err != nil { - c.JSON(http.StatusInternalServerError, models.ErrorResponse(err.Error())) + c.JSON(http.StatusBadRequest, models.ErrorResponse(err.Error())) return } // Target user exists diff --git a/backend/database/init.sql b/backend/database/init.sql index f69bf10..12a2487 100644 --- a/backend/database/init.sql +++ b/backend/database/init.sql @@ -1,9 +1,12 @@ DROP TABLE IF EXISTS showcases; DROP TABLE IF EXISTS titles; -DROP TABLE IF EXISTS records; +DROP TABLE IF EXISTS records_sp; +DROP TABLE IF EXISTS records_mp; DROP TABLE IF EXISTS maps; DROP TABLE IF EXISTS users; +DROP TABLE IF EXISTS demos; + CREATE TABLE users ( steam_id TEXT, username TEXT NOT NULL, @@ -23,20 +26,42 @@ CREATE TABLE maps ( PRIMARY KEY (id) ); -CREATE TABLE records ( +CREATE TABLE demos ( + id UUID, + location_id TEXT NOT NULL, + PRIMARY KEY (id) +); + +CREATE TABLE records_sp ( + id SERIAL, + map_id SMALLINT NOT NULL, + user_id TEXT NOT NULL, + score_count SMALLINT NOT NULL, + score_time INTEGER NOT NULL, + demo_id UUID NOT NULL, + record_date TIMESTAMP NOT NULL DEFAULT now(), + PRIMARY KEY (id), + FOREIGN KEY (map_id) REFERENCES maps(id), + FOREIGN KEY (user_id) REFERENCES users(steam_id), + FOREIGN KEY (demo_id) REFERENCES demos(id) +); + +CREATE TABLE records_mp ( id SERIAL, map_id SMALLINT NOT NULL, host_id TEXT NOT NULL, + partner_id TEXT NOT NULL, score_count SMALLINT NOT NULL, score_time INTEGER NOT NULL, - is_coop BOOLEAN NOT NULL DEFAULT false, - partner_id TEXT NOT NULL DEFAULT '', - demo_id TEXT NOT NULL, + host_demo_id UUID NOT NULL, + partner_demo_id UUID NOT NULL, record_date TIMESTAMP NOT NULL DEFAULT now(), PRIMARY KEY (id), FOREIGN KEY (map_id) REFERENCES maps(id), FOREIGN KEY (host_id) REFERENCES users(steam_id), - FOREIGN KEY (partner_id) REFERENCES users(steam_id) + FOREIGN KEY (partner_id) REFERENCES users(steam_id), + FOREIGN KEY (host_demo_id) REFERENCES demos(id), + FOREIGN KEY (partner_demo_id) REFERENCES demos(id) ); CREATE TABLE titles ( diff --git a/backend/models/models.go b/backend/models/models.go index 994a1e7..8f4a5e5 100644 --- a/backend/models/models.go +++ b/backend/models/models.go @@ -1,7 +1,6 @@ package models import ( - "mime/multipart" "time" ) @@ -15,13 +14,9 @@ type User struct { } type Record struct { - MapID int `json:"map_id" binding:"required"` - ScoreCount int `json:"score_count" binding:"required"` - ScoreTime int `json:"score_time" binding:"required"` - IsCoop bool `json:"is_coop" binding:"required"` - PartnerID string `json:"partner_id"` -} - -type ds struct { - File *multipart.FileHeader `form:"file" binding:"required"` + ScoreCount int `json:"score_count" form:"score_count" binding:"required"` + ScoreTime int `json:"score_time" form:"score_time" binding:"required"` + PartnerID string `json:"partner_id" form:"partner_id" binding:"required"` + IsPartnerOrange bool `json:"is_partner_orange" form:"is_partner_orange" binding:"required"` + //Demos []*multipart.FileHeader `form:"demos[]" binding:"required"` } diff --git a/go.mod b/go.mod index 46a72b1..e0166d3 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( require ( github.com/golang-jwt/jwt/v4 v4.4.2 + github.com/google/uuid v1.3.0 github.com/swaggo/files v0.0.0-20220728132757-551d4a08d97a github.com/swaggo/gin-swagger v1.5.3 github.com/swaggo/swag v1.8.7 @@ -26,7 +27,6 @@ require ( github.com/go-openapi/swag v0.22.3 // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect github.com/googleapis/gax-go/v2 v2.6.0 // indirect github.com/josharian/intern v1.0.0 // indirect -- cgit v1.2.3