Merge pull request #37 from LumaLivy/main

Add support for grabbing Top Scores
This commit is contained in:
jvyden 2021-11-04 14:34:16 -04:00 committed by GitHub
commit 582d2e2de0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 124 additions and 14 deletions

View file

@ -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);

View file

@ -103,6 +103,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=PCKS/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Swingy/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=thumbsup/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=topscores/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=UCAS/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=unfavourite/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unpublish/@EntryIndexedValue">True</s:Boolean>

View file

@ -1,6 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
@ -30,10 +35,91 @@ namespace LBPUnion.ProjectLighthouse.Controllers
score.SlotId = id;
this.database.Scores.Add(score);
IQueryable<Score> existingScore = this.database.Scores.Where(s => s.SlotId == score.SlotId && s.PlayerIdCollection == score.PlayerIdCollection);
if (existingScore.Any())
{
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);
}
else
{
this.database.Scores.Add(score);
}
await this.database.SaveChangesAsync();
return this.Ok();
}
[HttpGet("topscores/user/{slotId:int}/{type:int}")]
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
public async Task<IActionResult> TopScores(int slotId, int type, [FromQuery] int pageStart, [FromQuery] int pageSize)
{
// Get username
User user = await this.database.UserFromRequest(this.Request);
// 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));
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<string, object>()
{
{
"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);
}
}
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -8,19 +8,19 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2" />
<PackageReference Include="Kettu" Version="1.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.11" />
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2"/>
<PackageReference Include="Kettu" Version="1.2.0"/>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="5.0.11"/>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.11"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.11">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.2" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.2"/>
</ItemGroup>
<ItemGroup>
<Compile Remove="Types\SlotXsd.cs" />
<Compile Remove="Types\SlotXsd.cs"/>
</ItemGroup>
</Project>

View file

@ -26,6 +26,9 @@ namespace LBPUnion.ProjectLighthouse.Serialization
public static string TaggedStringElement(string key, object value, string tagKey, object tagValue) => $"<{key} {tagKey}=\"{tagValue}\">{value}</{key}>";
public static string TaggedStringElement(string key, object value, Dictionary<string, object> attrKeyValuePairs)
=> $"<{key} " + attrKeyValuePairs.Aggregate(string.Empty, (current, kvp) => current + $"{kvp.Key}=\"{kvp.Value}\" ") + $">{value}</{key}>";
public static string Elements
(params KeyValuePair<string, object>[] pairs)
=> pairs.Aggregate(string.Empty, (current, pair) => current + StringElement(pair));

View file

@ -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
@ -33,7 +34,29 @@ namespace LBPUnion.ProjectLighthouse.Types
set => this.PlayerIdCollection = string.Join(',', value);
}
[NotMapped]
[XmlElement("mainPlayer")]
public string MainPlayer {
get => this.PlayerIds[0];
set => this.PlayerIds[0] = value;
}
[NotMapped]
[XmlElement("rank")]
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);
}
}
}