From 973ca5bb78ecb506a91118d61a125fad76ab05f7 Mon Sep 17 00:00:00 2001 From: MaxJa4 <74194322+MaxJa4@users.noreply.github.com> Date: Mon, 22 Jan 2024 22:10:29 +0100 Subject: [PATCH] Fix player deletion. Add PersonaID + NucleusID fetching upon Add-Player action. --- controllers/player_controller.go | 15 ++++- ...re_controller.go => tracker_controller.go} | 64 ++++++++++++++++--- models/player.go | 10 +-- models/tracker_json.go | 7 ++ templates/modals/add_player.html | 16 ++++- 5 files changed, 94 insertions(+), 18 deletions(-) rename controllers/{score_controller.go => tracker_controller.go} (71%) diff --git a/controllers/player_controller.go b/controllers/player_controller.go index c625e37..164e297 100644 --- a/controllers/player_controller.go +++ b/controllers/player_controller.go @@ -37,6 +37,10 @@ func GetAllPlayers(c *gin.Context) { func GetPlayersByClanHTML(c *gin.Context) { var players []models.Player clanId := c.Request.URL.Query().Get("clan_id") + if clanId == "NaN" { + c.String(http.StatusBadRequest, "") + return + } if err := models.DB. Where("clan_id = ?", utils.StringToUint(clanId)). Find(&players).Error; err != nil { @@ -103,7 +107,14 @@ func AddPlayer(c *gin.Context) { return } - player = models.Player{Name: input.Name, ClanID: input.ClanID} + personaID, nucleusID, statusCode := GetPlayerIds(input.Name) + if personaID == 0 || nucleusID == 0 { + c.JSON(statusCode, gin.H{"error": "Player not found!"}) + utils.Logger.Errorf("[PLAYER] Could not find player! Name: %s, Status: %d", input.Name, statusCode) + return + } + + player = models.Player{Name: input.Name, ClanID: input.ClanID, PersonaID: personaID, NucleusID: nucleusID} if err := models.DB.Create(&player); err.Error != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error.Error()}) utils.Logger.Errorf("[PLAYER] Could not create player! Error: %s", err.Error.Error()) @@ -168,7 +179,7 @@ func UpdatePlayerByID(c *gin.Context) { func DeletePlayerByID(c *gin.Context) { var player models.Player - if err := models.DB.Clauses(clause.Returning{}).Delete(&player).Error; err != nil { + if err := models.DB.Clauses(clause.Returning{}).Where("id = ?", c.Param("id")).Delete(&player).Error; err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) utils.Logger.Errorf("[PLAYER] Could not delete player! Error: %s", err.Error()) return diff --git a/controllers/score_controller.go b/controllers/tracker_controller.go similarity index 71% rename from controllers/score_controller.go rename to controllers/tracker_controller.go index 9b4a038..145e7ae 100644 --- a/controllers/score_controller.go +++ b/controllers/tracker_controller.go @@ -72,7 +72,7 @@ func GetScoreByPlayerName(c *gin.Context) { } func CalcPlayerScore(playerName string, gameTag string) float32 { - if gameTag != "BF5" && gameTag != "BF2042" { + if gameTag != "BF2042" { utils.Logger.Errorf("[SCORE] Invalid game tag '%s'", gameTag) return -1 } @@ -88,13 +88,7 @@ func CalcPlayerScore(playerName string, gameTag string) float32 { c := http.Client{} - var reqUri string - if gameTag == "BF5" { - reqUri = "https://api.gametools.network/bfv/weapons/?raw=false&format_values=false&name=" + playerName + "&platform=pc" - } else if gameTag == "BF2042" { - reqUri = "https://api.gametools.network/bf2042/stats/?raw=false&format_values=false&name=" + playerName + "&platform=pc" - } - + reqUri := "https://api.gametools.network/bf2042/stats/?raw=false&format_values=false&name=" + playerName + "&platform=pc" req, err := http.NewRequest("GET", reqUri, nil) if err != nil { utils.Logger.Errorf("[SCORE] Failed to create request: %s", err.Error()) @@ -121,9 +115,13 @@ func CalcPlayerScore(playerName string, gameTag string) float32 { } var data models.TrackerWeaponJSON - var body, _ = io.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) + if err != nil { + utils.Logger.Errorf("[SCORE] Failed to read response body: %s", err.Error()) + return -1 + } if err := json.Unmarshal(body, &data); err != nil { - utils.Logger.Errorf("Failed to deserialize tracker API response: %s", err) + utils.Logger.Errorf("[SCORE] Failed to deserialize tracker API response: %s", err) return -1 } @@ -171,3 +169,49 @@ func CalcPlayerScore(playerName string, gameTag string) float32 { return float32(score) } + +// GetPlayerIds Returns: PersonaID, NucleusID, StatusCode +func GetPlayerIds(playerName string) (uint, uint, int) { + c := http.Client{} + + req, err := http.NewRequest("GET", "https://api.gametools.network/bf2042/player/?name="+playerName, nil) + if err != nil { + utils.Logger.Errorf("[TRK-PID] Failed to create request: %s", err.Error()) + return 0, 0, 0 + } + + req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36") + + res, err := c.Do(req) + if err != nil { + utils.Logger.Errorf("[TRK-PID] Failed to send request: %s", err.Error()) + return 0, 0, 0 + } + + defer func(Body io.ReadCloser) { + _ = Body.Close() + }(res.Body) + if res.StatusCode == 404 { + utils.Logger.Errorf("[TRK-PID] User '%s' does not exist!", playerName) + return 0, 0, res.StatusCode + } else if res.StatusCode == 503 { + utils.Logger.Errorf("[TRK-PID] Service unavailable!") + return 0, 0, res.StatusCode + } else if res.StatusCode != 200 { + utils.Logger.Errorf("[TRK-PID] Status code error: %d %s", res.StatusCode, res.Status) + return 0, 0, res.StatusCode + } + + var data models.PlayerIDsJSON + body, err := io.ReadAll(res.Body) + if err != nil { + utils.Logger.Errorf("[TRK-PID] Failed to read response body: %s", err.Error()) + return 0, 0, 0 + } + if err := json.Unmarshal(body, &data); err != nil { + utils.Logger.Errorf("[TRK-PID] Failed to deserialize tracker API response: %s", err) + return 0, 0, 0 + } + + return data.Results[0].PersonaID, data.Results[0].NucleusID, 0 +} diff --git a/models/player.go b/models/player.go index e042481..37aaf41 100644 --- a/models/player.go +++ b/models/player.go @@ -1,8 +1,10 @@ package models type Player struct { - ID uint `json:"id" gorm:"primary_key"` - Name string `json:"name"` - ClanID uint `json:"clan_id"` - Clan Clan `gorm:"references:ID"` + ID uint `json:"id" gorm:"primary_key"` + Name string `json:"name" gorm:"not null"` + PersonaID uint `json:"persona_id" gorm:"not null"` + NucleusID uint `json:"nucleus_id" gorm:"not null"` + ClanID uint `json:"clan_id" gorm:"not null"` + Clan Clan `gorm:"references:ID"` } diff --git a/models/tracker_json.go b/models/tracker_json.go index 4e9ec9d..5f806c4 100644 --- a/models/tracker_json.go +++ b/models/tracker_json.go @@ -14,3 +14,10 @@ type Weapon struct { ShotsHit int `json:"shotsHit"` Accuracy float64 `json:"-"` } + +type PlayerIDsJSON struct { + Results []struct { + PersonaID uint `json:"personaId"` + NucleusID uint `json:"nucleusId"` + } `json:"results"` +} diff --git a/templates/modals/add_player.html b/templates/modals/add_player.html index 0ad625c..d310729 100644 --- a/templates/modals/add_player.html +++ b/templates/modals/add_player.html @@ -41,6 +41,8 @@ const homeClanList = document.getElementById('home-clan'); const oppClanList = document.getElementById('opponent-clan'); + const spinner = '' + function validateInput() { if (playerName.value.length < 1) { playerName.classList.add('is-invalid'); @@ -57,6 +59,9 @@ const clanId = parseInt(selectedClan.value); + submitButton.innerHTML = spinner; + submitButton.disabled = true; + fetch("/player", { method: "POST", body: JSON.stringify({ @@ -68,8 +73,12 @@ } }) .then(response => { - if (!response.ok) { - throw new Error('Hinzufügen fehlgeschlagen!\nSpielername existiert möglichweise bereits.'); + if (response.status === 404) { + throw new Error('Hinzufügen fehlgeschlagen!\nSpielername existiert nicht.'); + } else if (response.status === 503) { + throw new Error('Hinzufügen fehlgeschlagen!\nTracker überlastet. Versuche es später erneut.'); + } else if (!response.ok) { + throw new Error('Hinzufügen fehlgeschlagen!\nSpielername existiert möglicherweise bereits.'); } return response.text(); }) @@ -84,6 +93,9 @@ }).catch((error) => { errorDiv.innerText = error.message; errorDiv.style.display = 'block'; + }).finally(() => { + submitButton.innerHTML = 'Hinzufügen'; + submitButton.disabled = false; }); } }