From 04c899500323ccf7a3795ba213e98232a291a36b Mon Sep 17 00:00:00 2001 From: LumaLivy Date: Thu, 4 Nov 2021 00:53:06 -0400 Subject: [PATCH 1/8] I don't know what git is doing --- .../Controllers/ScoreController.cs | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/ProjectLighthouse/Controllers/ScoreController.cs b/ProjectLighthouse/Controllers/ScoreController.cs index 287be62c..e71d3810 100644 --- a/ProjectLighthouse/Controllers/ScoreController.cs +++ b/ProjectLighthouse/Controllers/ScoreController.cs @@ -1,7 +1,11 @@ +using System; using System.IO; +using System.Linq; +using System.Collections.Generic; using System.Threading.Tasks; using System.Xml.Serialization; using LBPUnion.ProjectLighthouse.Types; +using LBPUnion.ProjectLighthouse.Serialization; using Microsoft.AspNetCore.Mvc; namespace LBPUnion.ProjectLighthouse.Controllers @@ -30,10 +34,58 @@ namespace LBPUnion.ProjectLighthouse.Controllers score.SlotId = id; - this.database.Scores.Add(score); + IQueryable existingScore = this.database.Scores.Where(s => s.PlayerIdCollection == score.PlayerIdCollection); + + if (existingScore.Any()) + { + Score first = existingScore.FirstOrDefault(s => s.SlotId == score.SlotId); + score.ScoreId = first.ScoreId; + score.Points = Math.Max(first.Points, score.Points); + this.database.Entry(first).CurrentValues.SetValues(score); + } + else + { + this.database.Scores.Add(score); + } await this.database.SaveChangesAsync(); return this.Ok(); } + + [HttpGet("topscores/user/{slotId:int}/{type:int}")] + public async Task TopScores(int slotId, int type, [FromQuery] int pageStart, [FromQuery] int pageSize) + { + // Get username + User user = await this.database.UserFromRequest(this.Request); + + // Find your score, even if you aren't in the top list + List myScore = this.database.Scores + .Where(s => s.SlotId == slotId && s.Type == type && s.PlayerIdCollection.Contains(user.Username)).ToList(); + + //Split this out from pagination, so we can count totalNumScores below + IQueryable allScoresOfType = this.database.Scores + .Where(s => s.SlotId == slotId && s.Type == type); + + //Paginated viewing + IQueryable pagedScores = allScoresOfType + .OrderByDescending(s => s.Points) + .Skip(pageStart - 1) + .Take(Math.Min(pageSize, 30)); + + //Calculate rank and serialize top scores + int rank = 1; + string serializedScores = Enumerable.Aggregate(pagedScores, string.Empty, (current, score) => { + score.Rank = (pageStart - 1) * pageSize + rank++; + return current + score.Serialize(); + }); + + string res = LbpSerializer.TaggedStringElement("scores", serializedScores, new Dictionary() { + {"yourScore", myScore.OrderByDescending(score => score.Points).FirstOrDefault()}, + {"yourRank", 0 }, // afaik, this is unused + {"totalNumScores", allScoresOfType.Count() } // This is shown as "Ranked 1/x" in the side menu if you have the global highscore + }); + + return this.Ok(res); + } } } \ No newline at end of file From 35fba33216b33e7f1c50bdb9c49255c7a02a08b0 Mon Sep 17 00:00:00 2001 From: LumaLivy Date: Thu, 4 Nov 2021 00:54:51 -0400 Subject: [PATCH 2/8] Add some necessary properties for topscores --- ProjectLighthouse/Types/Score.cs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/ProjectLighthouse/Types/Score.cs b/ProjectLighthouse/Types/Score.cs index 14668872..b6b4c4c5 100644 --- a/ProjectLighthouse/Types/Score.cs +++ b/ProjectLighthouse/Types/Score.cs @@ -1,6 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Xml.Serialization; +using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Types.Levels; namespace LBPUnion.ProjectLighthouse.Types @@ -28,12 +29,36 @@ namespace LBPUnion.ProjectLighthouse.Types [NotMapped] [XmlElement("playerIds")] - public string[] PlayerIds { + public string[] PlayerIds + { get => this.PlayerIdCollection.Split(","); set => this.PlayerIdCollection = string.Join(',', value); } + [XmlElement("mainPlayer")] + [NotMapped] + public string MainPlayer + { + get => this.PlayerIds[0]; + set => this.PlayerIds[0] = value; + } + + [XmlElement("rank")] + [NotMapped] + public int Rank { get; set; } + [XmlElement("score")] public int Points { get; set; } + + public string Serialize() + { + string score = LbpSerializer.StringElement("type", this.Type) + + LbpSerializer.StringElement("playerIds", this.PlayerIdCollection) + + LbpSerializer.StringElement("mainPlayer", this.MainPlayer) + + LbpSerializer.StringElement("rank", this.Rank) + + LbpSerializer.StringElement("score", this.Points); + + return LbpSerializer.StringElement("playRecord", score); + } } } \ No newline at end of file From ce032d8e4d8c66cc96af769f9a6c0a63fba3d3bf Mon Sep 17 00:00:00 2001 From: LumaLivy Date: Thu, 4 Nov 2021 00:57:42 -0400 Subject: [PATCH 3/8] Add another TaggedStringElement definition to support multiple key value pairs in XML tags --- ProjectLighthouse/Serialization/LbpSerializer.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ProjectLighthouse/Serialization/LbpSerializer.cs b/ProjectLighthouse/Serialization/LbpSerializer.cs index 9bec4cb2..29fc17fd 100644 --- a/ProjectLighthouse/Serialization/LbpSerializer.cs +++ b/ProjectLighthouse/Serialization/LbpSerializer.cs @@ -26,6 +26,11 @@ namespace LBPUnion.ProjectLighthouse.Serialization public static string TaggedStringElement(string key, object value, string tagKey, object tagValue) => $"<{key} {tagKey}=\"{tagValue}\">{value}"; + public static string TaggedStringElement(string key, object value, Dictionary attrKeyValuePairs) + => $"<{key} " + + Enumerable.Aggregate(attrKeyValuePairs, string.Empty, (current, kvp) => current + $"{kvp.Key}=\"{kvp.Value}\" ") + + $">{value}"; + public static string Elements (params KeyValuePair[] pairs) => pairs.Aggregate(string.Empty, (current, pair) => current + StringElement(pair)); From 0938140e958c8505aaab765f63a89109cae69805 Mon Sep 17 00:00:00 2001 From: LumaLivy Date: Thu, 4 Nov 2021 01:01:02 -0400 Subject: [PATCH 4/8] Reorganize attributes --- ProjectLighthouse/Types/Score.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProjectLighthouse/Types/Score.cs b/ProjectLighthouse/Types/Score.cs index b6b4c4c5..341f4e3b 100644 --- a/ProjectLighthouse/Types/Score.cs +++ b/ProjectLighthouse/Types/Score.cs @@ -35,16 +35,16 @@ namespace LBPUnion.ProjectLighthouse.Types set => this.PlayerIdCollection = string.Join(',', value); } - [XmlElement("mainPlayer")] [NotMapped] + [XmlElement("mainPlayer")] public string MainPlayer { get => this.PlayerIds[0]; set => this.PlayerIds[0] = value; } - [XmlElement("rank")] [NotMapped] + [XmlElement("rank")] public int Rank { get; set; } [XmlElement("score")] From 85f1afaf3529afcf710b7eaf9168c78309f5f84f Mon Sep 17 00:00:00 2001 From: LumaLivy Date: Thu, 4 Nov 2021 03:14:45 -0400 Subject: [PATCH 5/8] Add support for score ranks --- .../Controllers/ScoreController.cs | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/ProjectLighthouse/Controllers/ScoreController.cs b/ProjectLighthouse/Controllers/ScoreController.cs index e71d3810..f22ed928 100644 --- a/ProjectLighthouse/Controllers/ScoreController.cs +++ b/ProjectLighthouse/Controllers/ScoreController.cs @@ -58,33 +58,38 @@ namespace LBPUnion.ProjectLighthouse.Controllers // Get username User user = await this.database.UserFromRequest(this.Request); - // Find your score, even if you aren't in the top list - List myScore = this.database.Scores - .Where(s => s.SlotId == slotId && s.Type == type && s.PlayerIdCollection.Contains(user.Username)).ToList(); - - //Split this out from pagination, so we can count totalNumScores below - IQueryable allScoresOfType = this.database.Scores - .Where(s => s.SlotId == slotId && s.Type == type); - - //Paginated viewing - IQueryable pagedScores = allScoresOfType + // This is hella ugly but it technically assigns the proper rank to a score + // var needed for Anonymous type returned from SELECT + var rankedScores = this.database.Scores + .Where(s => s.SlotId == slotId && s.Type == type) .OrderByDescending(s => s.Points) + .ToList() + .Select((Score s, int rank) => new { Score = s, Rank = rank + 1 }); + + // Find your score, since even if you aren't in the top list your score is pinned + var myScore = rankedScores + .Where(rs => rs.Score.PlayerIdCollection.Contains(user.Username)) + .OrderByDescending(rs => rs.Score.Points) + .FirstOrDefault(); + + // Paginated viewing + var pagedScores = rankedScores .Skip(pageStart - 1) .Take(Math.Min(pageSize, 30)); - //Calculate rank and serialize top scores - int rank = 1; - string serializedScores = Enumerable.Aggregate(pagedScores, string.Empty, (current, score) => { - score.Rank = (pageStart - 1) * pageSize + rank++; - return current + score.Serialize(); + string serializedScores = Enumerable.Aggregate(pagedScores, string.Empty, (current, rs) => { + rs.Score.Rank = rs.Rank; + return current + rs.Score.Serialize(); }); string res = LbpSerializer.TaggedStringElement("scores", serializedScores, new Dictionary() { - {"yourScore", myScore.OrderByDescending(score => score.Points).FirstOrDefault()}, - {"yourRank", 0 }, // afaik, this is unused - {"totalNumScores", allScoresOfType.Count() } // This is shown as "Ranked 1/x" in the side menu if you have the global highscore + {"yourScore", myScore.Score.Points}, + {"yourRank", myScore.Rank }, //This is the numerator of your position globally in the side menu. + {"totalNumScores", rankedScores.Count() } // This is the denominator of your position globally in the side menu. }); + Console.WriteLine(res); + return this.Ok(res); } } From cf348002af09755037596000320ef4d7ee310bf2 Mon Sep 17 00:00:00 2001 From: LumaLivy Date: Thu, 4 Nov 2021 03:56:08 -0400 Subject: [PATCH 6/8] Remove console write --- ProjectLighthouse/Controllers/ScoreController.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ProjectLighthouse/Controllers/ScoreController.cs b/ProjectLighthouse/Controllers/ScoreController.cs index f22ed928..c3d6c1a6 100644 --- a/ProjectLighthouse/Controllers/ScoreController.cs +++ b/ProjectLighthouse/Controllers/ScoreController.cs @@ -88,8 +88,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers {"totalNumScores", rankedScores.Count() } // This is the denominator of your position globally in the side menu. }); - Console.WriteLine(res); - return this.Ok(res); } } From c12894af9235005a49cc51851a3780e72f9bfc6b Mon Sep 17 00:00:00 2001 From: LumaLivy Date: Thu, 4 Nov 2021 05:00:42 -0400 Subject: [PATCH 7/8] Fix some situations where scores were null --- .../Controllers/ScoreController.cs | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/ProjectLighthouse/Controllers/ScoreController.cs b/ProjectLighthouse/Controllers/ScoreController.cs index c3d6c1a6..71d41b2d 100644 --- a/ProjectLighthouse/Controllers/ScoreController.cs +++ b/ProjectLighthouse/Controllers/ScoreController.cs @@ -34,7 +34,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers score.SlotId = id; - IQueryable existingScore = this.database.Scores.Where(s => s.PlayerIdCollection == score.PlayerIdCollection); + IQueryable existingScore = this.database.Scores.Where(s => s.SlotId == score.SlotId && s.PlayerIdCollection == score.PlayerIdCollection); if (existingScore.Any()) { @@ -82,11 +82,20 @@ namespace LBPUnion.ProjectLighthouse.Controllers return current + rs.Score.Serialize(); }); - string res = LbpSerializer.TaggedStringElement("scores", serializedScores, new Dictionary() { - {"yourScore", myScore.Score.Points}, - {"yourRank", myScore.Rank }, //This is the numerator of your position globally in the side menu. - {"totalNumScores", rankedScores.Count() } // This is the denominator of your position globally in the side menu. - }); + string res; + if (myScore == null) + { + res = LbpSerializer.StringElement("scores", serializedScores); + } + else + { + res = LbpSerializer.TaggedStringElement("scores", serializedScores, new Dictionary() { + {"yourScore", myScore.Score.Points}, + {"yourRank", myScore.Rank }, //This is the numerator of your position globally in the side menu. + {"totalNumScores", rankedScores.Count() } // This is the denominator of your position globally in the side menu. + }); + } + return this.Ok(res); } From 8e193c079f033de4e33412e5cbed7728e03e3ac1 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 4 Nov 2021 14:28:50 -0400 Subject: [PATCH 8/8] Cleanup code --- .../Tests/AuthenticationTests.cs | 2 +- ProjectLighthouse.sln.DotSettings | 1 + .../Controllers/ScoreController.cs | 66 ++++++++++++------- .../Helpers/Extensions/StringExtensions.cs | 7 +- .../Logging/LighthouseFileLogger.cs | 2 +- ProjectLighthouse/ProjectLighthouse.csproj | 12 ++-- .../Serialization/LbpSerializer.cs | 4 +- ProjectLighthouse/Types/Score.cs | 6 +- 8 files changed, 58 insertions(+), 42 deletions(-) diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs index a996612b..893648e0 100644 --- a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs +++ b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs @@ -12,7 +12,7 @@ namespace LBPUnion.ProjectLighthouse.Tests [Fact] public async Task ShouldReturnErrorOnNoPostData() { - HttpResponseMessage response = await this.Client.PostAsync($"/LITTLEBIGPLANETPS3_XML/login", null!); + HttpResponseMessage response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", null!); Assert.False(response.IsSuccessStatusCode); #if NET6_0_OR_GREATER Assert.True(response.StatusCode == HttpStatusCode.BadRequest); diff --git a/ProjectLighthouse.sln.DotSettings b/ProjectLighthouse.sln.DotSettings index 9035b5a5..9bfc9063 100644 --- a/ProjectLighthouse.sln.DotSettings +++ b/ProjectLighthouse.sln.DotSettings @@ -103,6 +103,7 @@ True True True + True True True True diff --git a/ProjectLighthouse/Controllers/ScoreController.cs b/ProjectLighthouse/Controllers/ScoreController.cs index 71d41b2d..90a710ee 100644 --- a/ProjectLighthouse/Controllers/ScoreController.cs +++ b/ProjectLighthouse/Controllers/ScoreController.cs @@ -1,11 +1,12 @@ using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Collections.Generic; using System.Threading.Tasks; using System.Xml.Serialization; -using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Serialization; +using LBPUnion.ProjectLighthouse.Types; using Microsoft.AspNetCore.Mvc; namespace LBPUnion.ProjectLighthouse.Controllers @@ -38,7 +39,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers if (existingScore.Any()) { - Score first = existingScore.FirstOrDefault(s => s.SlotId == score.SlotId); + Score first = existingScore.First(s => s.SlotId == score.SlotId); score.ScoreId = first.ScoreId; score.Points = Math.Max(first.Points, score.Points); this.database.Entry(first).CurrentValues.SetValues(score); @@ -53,6 +54,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers } [HttpGet("topscores/user/{slotId:int}/{type:int}")] + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] public async Task TopScores(int slotId, int type, [FromQuery] int pageStart, [FromQuery] int pageSize) { // Get username @@ -60,42 +62,62 @@ namespace LBPUnion.ProjectLighthouse.Controllers // This is hella ugly but it technically assigns the proper rank to a score // var needed for Anonymous type returned from SELECT - var rankedScores = this.database.Scores - .Where(s => s.SlotId == slotId && s.Type == type) + var rankedScores = this.database.Scores.Where(s => s.SlotId == slotId && s.Type == type) .OrderByDescending(s => s.Points) .ToList() - .Select((Score s, int rank) => new { Score = s, Rank = rank + 1 }); + .Select + ( + (Score s, int rank) => new + { + Score = s, + Rank = rank + 1, + } + ); // Find your score, since even if you aren't in the top list your score is pinned - var myScore = rankedScores - .Where(rs => rs.Score.PlayerIdCollection.Contains(user.Username)) + var myScore = rankedScores.Where + (rs => rs.Score.PlayerIdCollection.Contains(user.Username)) .OrderByDescending(rs => rs.Score.Points) .FirstOrDefault(); // Paginated viewing - var pagedScores = rankedScores - .Skip(pageStart - 1) - .Take(Math.Min(pageSize, 30)); + var pagedScores = rankedScores.Skip(pageStart - 1).Take(Math.Min(pageSize, 30)); - string serializedScores = Enumerable.Aggregate(pagedScores, string.Empty, (current, rs) => { - rs.Score.Rank = rs.Rank; - return current + rs.Score.Serialize(); - }); + string serializedScores = pagedScores.Aggregate + ( + string.Empty, + (current, rs) => + { + rs.Score.Rank = rs.Rank; + return current + rs.Score.Serialize(); + } + ); string res; if (myScore == null) { res = LbpSerializer.StringElement("scores", serializedScores); - } + } else { - res = LbpSerializer.TaggedStringElement("scores", serializedScores, new Dictionary() { - {"yourScore", myScore.Score.Points}, - {"yourRank", myScore.Rank }, //This is the numerator of your position globally in the side menu. - {"totalNumScores", rankedScores.Count() } // This is the denominator of your position globally in the side menu. - }); + res = LbpSerializer.TaggedStringElement + ( + "scores", + serializedScores, + new Dictionary() + { + { + "yourScore", myScore.Score.Points + }, + { + "yourRank", myScore.Rank + }, //This is the numerator of your position globally in the side menu. + { + "totalNumScores", rankedScores.Count() + }, // This is the denominator of your position globally in the side menu. + } + ); } - return this.Ok(res); } diff --git a/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs b/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs index 4ed898e9..177027de 100644 --- a/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs +++ b/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs @@ -8,11 +8,8 @@ namespace LBPUnion.ProjectLighthouse.Helpers.Extensions { char[] invalidPathChars = Path.GetInvalidFileNameChars(); string path = text; - - foreach (char c in invalidPathChars) - { - path = path.Replace(c.ToString(), ""); - } + + foreach (char c in invalidPathChars) path = path.Replace(c.ToString(), ""); return path; } diff --git a/ProjectLighthouse/Logging/LighthouseFileLogger.cs b/ProjectLighthouse/Logging/LighthouseFileLogger.cs index 31879a69..4b0e08a4 100644 --- a/ProjectLighthouse/Logging/LighthouseFileLogger.cs +++ b/ProjectLighthouse/Logging/LighthouseFileLogger.cs @@ -9,6 +9,7 @@ namespace LBPUnion.ProjectLighthouse.Logging public class LighthouseFileLogger : LoggerBase { private static readonly string logsDirectory = Path.Combine(Environment.CurrentDirectory, "logs"); + public override bool AllowMultiple => false; public override void Send(LoggerLine line) { @@ -22,6 +23,5 @@ namespace LBPUnion.ProjectLighthouse.Logging File.AppendAllText(Path.Combine(logsDirectory, line.LoggerLevel.Name.ToFileName() + ".log"), contentFile); File.AppendAllText(Path.Combine(logsDirectory, "all.log"), contentAll); } - public override bool AllowMultiple => false; } } \ No newline at end of file diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index 64127ba0..37dc28d0 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -8,19 +8,19 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + diff --git a/ProjectLighthouse/Serialization/LbpSerializer.cs b/ProjectLighthouse/Serialization/LbpSerializer.cs index 29fc17fd..cfa64535 100644 --- a/ProjectLighthouse/Serialization/LbpSerializer.cs +++ b/ProjectLighthouse/Serialization/LbpSerializer.cs @@ -27,9 +27,7 @@ namespace LBPUnion.ProjectLighthouse.Serialization public static string TaggedStringElement(string key, object value, string tagKey, object tagValue) => $"<{key} {tagKey}=\"{tagValue}\">{value}"; public static string TaggedStringElement(string key, object value, Dictionary attrKeyValuePairs) - => $"<{key} " + - Enumerable.Aggregate(attrKeyValuePairs, string.Empty, (current, kvp) => current + $"{kvp.Key}=\"{kvp.Value}\" ") + - $">{value}"; + => $"<{key} " + attrKeyValuePairs.Aggregate(string.Empty, (current, kvp) => current + $"{kvp.Key}=\"{kvp.Value}\" ") + $">{value}"; public static string Elements (params KeyValuePair[] pairs) diff --git a/ProjectLighthouse/Types/Score.cs b/ProjectLighthouse/Types/Score.cs index 341f4e3b..6b507e6f 100644 --- a/ProjectLighthouse/Types/Score.cs +++ b/ProjectLighthouse/Types/Score.cs @@ -29,16 +29,14 @@ namespace LBPUnion.ProjectLighthouse.Types [NotMapped] [XmlElement("playerIds")] - public string[] PlayerIds - { + public string[] PlayerIds { get => this.PlayerIdCollection.Split(","); set => this.PlayerIdCollection = string.Join(',', value); } [NotMapped] [XmlElement("mainPlayer")] - public string MainPlayer - { + public string MainPlayer { get => this.PlayerIds[0]; set => this.PlayerIds[0] = value; }