Merge branch 'LBPUnion-main'

This commit is contained in:
LumaLivy 2021-11-18 15:16:39 -05:00
commit 93fe204563
28 changed files with 193 additions and 100 deletions

View file

@ -19,7 +19,7 @@ namespace LBPUnion.ProjectLighthouse.Tests
public LighthouseTest() public LighthouseTest()
{ {
this.Server = new TestServer(new WebHostBuilder().UseStartup<Startup>()); this.Server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
this.Client = this.Server.CreateClient(); this.Client = this.Server.CreateClient();
} }

View file

@ -13,6 +13,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0"/>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0"/> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="6.0.0"/>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0"> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>

View file

@ -1,3 +1,4 @@
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Levels;
@ -48,10 +49,17 @@ namespace LBPUnion.ProjectLighthouse.Tests
LoginResult loginResult = await this.Authenticate(); LoginResult loginResult = await this.Authenticate();
string respA = await (await this.AuthenticatedRequest("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser0", loginResult.AuthTicket)).Content HttpResponseMessage respMessageA = await this.AuthenticatedRequest("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser0", loginResult.AuthTicket);
.ReadAsStringAsync(); HttpResponseMessage respMessageB = await this.AuthenticatedRequest("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser1", loginResult.AuthTicket);
string respB = await (await this.AuthenticatedRequest("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser1", loginResult.AuthTicket)).Content
.ReadAsStringAsync(); Assert.True(respMessageA.IsSuccessStatusCode);
Assert.True(respMessageB.IsSuccessStatusCode);
string respA = await respMessageA.Content.ReadAsStringAsync();
string respB = await respMessageB.Content.ReadAsStringAsync();
Assert.False(string.IsNullOrEmpty(respA));
Assert.False(string.IsNullOrEmpty(respB));
Assert.NotEqual(respA, respB); Assert.NotEqual(respA, respB);
Assert.DoesNotContain(respA, "slotB"); Assert.DoesNotContain(respA, "slotB");

View file

@ -73,6 +73,7 @@
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseExplicitType</s:String> <s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForOtherTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String> <s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DLC/@EntryIndexedValue">DLC</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=DLC/@EntryIndexedValue">DLC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LBP/@EntryIndexedValue">LBP</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LBP/@EntryIndexedValue">LBP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MM/@EntryIndexedValue">MM</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MM/@EntryIndexedValue">MM</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NAT/@EntryIndexedValue">NAT</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=NAT/@EntryIndexedValue">NAT</s:String>
@ -93,6 +94,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=BCJS/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=BCJS/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Braaains/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Braaains/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=brun/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=brun/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=dpadrate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=ezoiar/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=ezoiar/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=farc/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=farc/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=friendscores/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=friendscores/@EntryIndexedValue">True</s:Boolean>

View file

@ -1,3 +1,4 @@
#nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -44,14 +45,12 @@ namespace LBPUnion.ProjectLighthouse.Controllers
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
XmlSerializer serializer = new(typeof(Comment)); XmlSerializer serializer = new(typeof(Comment));
Comment comment = (Comment)serializer.Deserialize(new StringReader(bodyString)); Comment? comment = (Comment?)serializer.Deserialize(new StringReader(bodyString));
User poster = await this.database.UserFromRequest(this.Request);
User? poster = await this.database.UserFromRequest(this.Request);
if (poster == null) return this.StatusCode(403, ""); if (poster == null) return this.StatusCode(403, "");
User target = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); User? target = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
if (comment == null || target == null) return this.BadRequest(); if (comment == null || target == null) return this.BadRequest();
comment.PosterUserId = poster.UserId; comment.PosterUserId = poster.UserId;
@ -67,10 +66,14 @@ namespace LBPUnion.ProjectLighthouse.Controllers
[HttpPost("deleteUserComment/{username}")] [HttpPost("deleteUserComment/{username}")]
public async Task<IActionResult> DeleteComment([FromQuery] int commentId, string username) public async Task<IActionResult> DeleteComment([FromQuery] int commentId, string username)
{ {
User user = await this.database.UserFromRequest(this.Request); User? user = await this.database.UserFromRequest(this.Request);
if (user == null) return this.StatusCode(403, ""); if (user == null) return this.StatusCode(403, "");
Comment comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId); Comment? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
if (comment == null)
{
return this.NotFound();
}
if (comment.TargetUserId != user.UserId && comment.PosterUserId != user.UserId) return this.StatusCode(403, ""); if (comment.TargetUserId != user.UserId && comment.PosterUserId != user.UserId) return this.StatusCode(403, "");

View file

@ -1,4 +1,5 @@
#nullable enable #nullable enable
using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types;
@ -52,7 +53,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
default: return this.BadRequest(); default: return this.BadRequest();
} }
v = new(); v = new VisitedLevel();
v.SlotId = slotId; v.SlotId = slotId;
v.UserId = user.UserId; v.UserId = user.UserId;
this.database.VisitedLevels.Add(v); this.database.VisitedLevels.Add(v);
@ -63,6 +64,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers
} }
if (v == null) return this.StatusCode(403, ""); if (v == null) return this.StatusCode(403, "");
if (v == null)
{
return this.NotFound();
}
switch (gameVersion) switch (gameVersion)
{ {
case GameVersion.LittleBigPlanet2: case GameVersion.LittleBigPlanet2:
@ -77,7 +83,10 @@ namespace LBPUnion.ProjectLighthouse.Controllers
slot.PlaysLBPVita++; slot.PlaysLBPVita++;
v.PlaysLBPVita++; v.PlaysLBPVita++;
break; break;
default: return this.BadRequest(); case GameVersion.LittleBigPlanetPSP: throw new NotImplementedException();
case GameVersion.Unknown:
default:
return this.BadRequest();
} }
await this.database.SaveChangesAsync(); await this.database.SaveChangesAsync();
@ -101,7 +110,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
{ {
slot.PlaysLBP1Unique++; slot.PlaysLBP1Unique++;
v = new(); v = new VisitedLevel();
v.SlotId = id; v.SlotId = id;
v.UserId = user.UserId; v.UserId = user.UserId;
this.database.VisitedLevels.Add(v); this.database.VisitedLevels.Add(v);
@ -112,6 +121,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers
} }
if (v == null) return StatusCode(403, ""); if (v == null) return StatusCode(403, "");
if (v == null)
{
return this.NotFound();
}
slot.PlaysLBP1++; slot.PlaysLBP1++;
v.PlaysLBP1++; v.PlaysLBP1++;

View file

@ -46,7 +46,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers
string response = queuedLevels.Aggregate(string.Empty, (current, q) => current + q.Slot.Serialize()); string response = queuedLevels.Aggregate(string.Empty, (current, q) => current + q.Slot.Serialize());
return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "total", this.database.QueuedLevels.Include(q => q.User).Where(q => q.User.Username == username).Count())); return this.Ok
(
LbpSerializer.TaggedStringElement
("slots", response, "total", this.database.QueuedLevels.Include(q => q.User).Count(q => q.User.Username == username))
);
} }
[HttpPost("lolcatftw/add/user/{id:int}")] [HttpPost("lolcatftw/add/user/{id:int}")]
@ -110,7 +114,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers
string response = heartedLevels.Aggregate(string.Empty, (current, q) => current + q.Slot.Serialize()); string response = heartedLevels.Aggregate(string.Empty, (current, q) => current + q.Slot.Serialize());
return this.Ok(LbpSerializer.TaggedStringElement("favouriteSlots", response, "total", this.database.HeartedLevels.Include(q => q.User).Where(q => q.User.Username == username).Count())); return this.Ok
(
LbpSerializer.TaggedStringElement
("favouriteSlots", response, "total", this.database.HeartedLevels.Include(q => q.User).Count(q => q.User.Username == username))
);
} }
[HttpPost("favourite/slot/user/{id:int}")] [HttpPost("favourite/slot/user/{id:int}")]
@ -173,7 +181,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers
string response = heartedProfiles.Aggregate(string.Empty, (current, q) => current + q.HeartedUser.Serialize(token.GameVersion)); string response = heartedProfiles.Aggregate(string.Empty, (current, q) => current + q.HeartedUser.Serialize(token.GameVersion));
return this.Ok(LbpSerializer.TaggedStringElement("favouriteUsers", response, "total", this.database.HeartedProfiles.Include(q => q.User).Where(q => q.User.Username == username).Count())); return this.Ok
(
LbpSerializer.TaggedStringElement
("favouriteUsers", response, "total", this.database.HeartedProfiles.Include(q => q.User).Count(q => q.User.Username == username))
);
} }
[HttpPost("favourite/user/{username}")] [HttpPost("favourite/user/{username}")]
@ -224,4 +236,4 @@ namespace LBPUnion.ProjectLighthouse.Controllers
#endregion #endregion
} }
} }

View file

@ -82,7 +82,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
{ {
User? userFromQuery = await this.database.Users.FirstOrDefaultAsync(u => u.Username == user); User? userFromQuery = await this.database.Users.FirstOrDefaultAsync(u => u.Username == user);
// ReSharper disable once ConditionIsAlwaysTrueOrFalse // ReSharper disable once ConditionIsAlwaysTrueOrFalse
if (user == null || userFromQuery == null) return this.NotFound(); if (userFromQuery == null) return this.NotFound();
List<Photo> photos = await this.database.Photos.Include List<Photo> photos = await this.database.Photos.Include
(p => p.Creator) (p => p.Creator)
@ -100,7 +100,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
{ {
User? userFromQuery = await this.database.Users.FirstOrDefaultAsync(u => u.Username == user); User? userFromQuery = await this.database.Users.FirstOrDefaultAsync(u => u.Username == user);
// ReSharper disable once ConditionIsAlwaysTrueOrFalse // ReSharper disable once ConditionIsAlwaysTrueOrFalse
if (user == null || userFromQuery == null) return this.NotFound(); if (userFromQuery == null) return this.NotFound();
List<Photo> photos = new(); List<Photo> photos = new();
foreach (Photo photo in this.database.Photos.Include(p => p.Creator)) foreach (Photo photo in this.database.Photos.Include(p => p.Creator))

View file

@ -1,3 +1,5 @@
#nullable enable
using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -30,10 +32,10 @@ namespace LBPUnion.ProjectLighthouse.Controllers
[HttpPost("startPublish")] [HttpPost("startPublish")]
public async Task<IActionResult> StartPublish() public async Task<IActionResult> StartPublish()
{ {
User user = await this.database.UserFromRequest(this.Request); User? user = await this.database.UserFromRequest(this.Request);
if (user == null) return this.StatusCode(403, ""); if (user == null) return this.StatusCode(403, "");
Slot slot = await this.GetSlotFromBody(); Slot? slot = await this.GetSlotFromBody();
if (slot == null) return this.BadRequest(); // if the level cant be parsed then it obviously cant be uploaded if (slot == null) return this.BadRequest(); // if the level cant be parsed then it obviously cant be uploaded
if (string.IsNullOrEmpty(slot.RootLevel)) return this.BadRequest(); if (string.IsNullOrEmpty(slot.RootLevel)) return this.BadRequest();
@ -43,7 +45,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
// Republish logic // Republish logic
if (slot.SlotId != 0) if (slot.SlotId != 0)
{ {
Slot oldSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slot.SlotId); Slot? oldSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slot.SlotId);
if (oldSlot == null) return this.NotFound(); if (oldSlot == null) return this.NotFound();
if (oldSlot.CreatorId != user.UserId) return this.BadRequest(); if (oldSlot.CreatorId != user.UserId) return this.BadRequest();
} }
@ -72,13 +74,17 @@ namespace LBPUnion.ProjectLighthouse.Controllers
User user = userAndToken.Value.Item1; User user = userAndToken.Value.Item1;
Token token = userAndToken.Value.Item2; Token token = userAndToken.Value.Item2;
Slot slot = await this.GetSlotFromBody(); Slot? slot = await this.GetSlotFromBody();
if (slot == null || slot.Location == null) return this.BadRequest();
// Republish logic // Republish logic
if (slot.SlotId != 0) if (slot.SlotId != 0)
{ {
Slot oldSlot = await this.database.Slots.Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == slot.SlotId); Slot? oldSlot = await this.database.Slots.Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == slot.SlotId);
if (oldSlot == null) return this.NotFound(); if (oldSlot == null) return this.NotFound();
if (oldSlot.Location == null) throw new ArgumentNullException();
if (oldSlot.CreatorId != user.UserId) return this.BadRequest(); if (oldSlot.CreatorId != user.UserId) return this.BadRequest();
oldSlot.Location.X = slot.Location.X; oldSlot.Location.X = slot.Location.X;
@ -125,10 +131,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers
[HttpPost("unpublish/{id:int}")] [HttpPost("unpublish/{id:int}")]
public async Task<IActionResult> Unpublish(int id) public async Task<IActionResult> Unpublish(int id)
{ {
User user = await this.database.UserFromRequest(this.Request); User? user = await this.database.UserFromRequest(this.Request);
if (user == null) return this.StatusCode(403, ""); if (user == null) return this.StatusCode(403, "");
Slot slot = await this.database.Slots.Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == id); Slot? slot = await this.database.Slots.Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == id);
if (slot == null) return this.NotFound();
if (slot.Location == null) throw new ArgumentNullException();
if (slot.CreatorId != user.UserId) return this.StatusCode(403, ""); if (slot.CreatorId != user.UserId) return this.StatusCode(403, "");
@ -140,13 +149,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers
return this.Ok(); return this.Ok();
} }
public async Task<Slot> GetSlotFromBody() public async Task<Slot?> GetSlotFromBody()
{ {
this.Request.Body.Position = 0; this.Request.Body.Position = 0;
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
XmlSerializer serializer = new(typeof(Slot)); XmlSerializer serializer = new(typeof(Slot));
Slot slot = (Slot)serializer.Deserialize(new StringReader(bodyString)); Slot? slot = (Slot?)serializer.Deserialize(new StringReader(bodyString));
return slot; return slot;
} }

View file

@ -33,13 +33,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers
RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == user.UserId); RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == user.UserId);
if (ratedLevel == null) if (ratedLevel == null)
{ {
ratedLevel = new(); ratedLevel = new RatedLevel();
ratedLevel.SlotId = slotId; ratedLevel.SlotId = slotId;
ratedLevel.UserId = user.UserId; ratedLevel.UserId = user.UserId;
ratedLevel.Rating = 0; ratedLevel.Rating = 0;
this.database.RatedLevels.Add(ratedLevel); this.database.RatedLevels.Add(ratedLevel);
} }
ratedLevel.RatingLBP1 = Math.Max(Math.Min(5, rating), 0); ratedLevel.RatingLBP1 = Math.Max(Math.Min(5, rating), 0);
await this.database.SaveChangesAsync(); await this.database.SaveChangesAsync();
@ -48,7 +48,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
} }
// LBP2 and beyond rating // LBP2 and beyond rating
[HttpPost("dpadrate/user/{slotId}")] [HttpPost("dpadrate/user/{slotId:int}")]
public async Task<IActionResult> DPadRate(int slotId, [FromQuery] int rating) public async Task<IActionResult> DPadRate(int slotId, [FromQuery] int rating)
{ {
User? user = await this.database.UserFromRequest(this.Request); User? user = await this.database.UserFromRequest(this.Request);
@ -60,19 +60,19 @@ namespace LBPUnion.ProjectLighthouse.Controllers
RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == user.UserId); RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == user.UserId);
if (ratedLevel == null) if (ratedLevel == null)
{ {
ratedLevel = new(); ratedLevel = new RatedLevel();
ratedLevel.SlotId = slotId; ratedLevel.SlotId = slotId;
ratedLevel.UserId = user.UserId; ratedLevel.UserId = user.UserId;
ratedLevel.RatingLBP1 = 0; ratedLevel.RatingLBP1 = 0;
this.database.RatedLevels.Add(ratedLevel); this.database.RatedLevels.Add(ratedLevel);
} }
ratedLevel.Rating = Math.Max(Math.Min(1, rating), -1); ratedLevel.Rating = Math.Max(Math.Min(1, rating), -1);
await this.database.SaveChangesAsync(); await this.database.SaveChangesAsync();
return this.Ok(); return this.Ok();
} }
} }
} }

View file

@ -102,6 +102,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers
return this.Ok(GetScores(slotId, type, user, pageStart, pageSize)); return this.Ok(GetScores(slotId, type, user, pageStart, pageSize));
} }
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
public string GetScores(int slotId, int type, User user, int pageStart = -1, int pageSize = 5) public string GetScores(int slotId, int type, User user, int pageStart = -1, int pageSize = 5)
{ {
// This is hella ugly but it technically assigns the proper rank to a score // This is hella ugly but it technically assigns the proper rank to a score

View file

@ -32,14 +32,14 @@ namespace LBPUnion.ProjectLighthouse.Controllers
GameVersion gameVersion = token.GameVersion; GameVersion gameVersion = token.GameVersion;
User? user = await this.database.Users.FirstOrDefaultAsync(dbUser => dbUser.Username == u); User? user = await this.database.Users.FirstOrDefaultAsync(dbUser => dbUser.Username == u);
if (user == null) return StatusCode(403, ""); if (user == null) return this.NotFound();
string response = Enumerable.Aggregate string response = Enumerable.Aggregate
( (
this.database.Slots.Where(s => s.GameVersion <= gameVersion) this.database.Slots.Where(s => s.GameVersion <= gameVersion)
.Include(s => s.Creator) .Include(s => s.Creator)
.Include(s => s.Location) .Include(s => s.Location)
.Where(s => s.Creator.Username == user.Username) .Where(s => s.Creator!.Username == user.Username)
.Skip(pageStart - 1) .Skip(pageStart - 1)
.Take(Math.Min(pageSize, ServerSettings.EntitledSlots)), .Take(Math.Min(pageSize, ServerSettings.EntitledSlots)),
string.Empty, string.Empty,

View file

@ -26,9 +26,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers
this.database = database; this.database = database;
} }
public async Task<string> GetSerializedUser(string username, GameVersion gameVersion = GameVersion.LittleBigPlanet1) public async Task<string?> GetSerializedUser(string username, GameVersion gameVersion = GameVersion.LittleBigPlanet1)
{ {
User? user = await this.database.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.Username == username); User? user = await this.database.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.Username == username);
if (user == null) return ""; if (user == null) return "";
return user.Serialize(gameVersion); return user.Serialize(gameVersion);
@ -52,14 +51,14 @@ namespace LBPUnion.ProjectLighthouse.Controllers
Token? token = await this.database.TokenFromRequest(this.Request); Token? token = await this.database.TokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, ""); if (token == null) return this.StatusCode(403, "");
List<string> serializedUsers = new(); List<string?> serializedUsers = new();
foreach (string userId in u) foreach (string userId in u)
{ {
string? serializedUser = await this.GetSerializedUser(userId, token.GameVersion); string? serializedUser = await this.GetSerializedUser(userId, token.GameVersion);
if (serializedUser != "") serializedUsers.Add(serializedUser); if (serializedUser != "") serializedUsers.Add(serializedUser);
} }
string serialized = serializedUsers.Aggregate(string.Empty, (current, u) => u == null ? current : current + u); string serialized = serializedUsers.Aggregate(string.Empty, (current, user) => user == null ? current : current + user);
return this.Ok(LbpSerializer.StringElement("users", serialized)); return this.Ok(LbpSerializer.StringElement("users", serialized));
} }
@ -145,8 +144,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers
// the way location on a user card works is stupid and will not save with the way below as-is, so we do the following: // the way location on a user card works is stupid and will not save with the way below as-is, so we do the following:
if (locationChanged) // only modify the database if we modify here if (locationChanged) // only modify the database if we modify here
{ {
Location? l = await this.database.Locations.Where(l => l.Id == user.LocationId).FirstOrDefaultAsync(); // find the location in the database again Location? l = await this.database.Locations.FirstOrDefaultAsync(l => l.Id == user.LocationId); // find the location in the database again
if (l == null) return this.StatusCode(403, "");
if (l == null)
{
throw new Exception("this shouldn't happen ever but we handle this");
}
// set the location in the database to the one we modified above // set the location in the database to the one we modified above
l.X = user.Location.X; l.X = user.Location.X;
l.Y = user.Location.Y; l.Y = user.Location.Y;
@ -166,7 +170,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers
string pinsString = await new StreamReader(this.Request.Body).ReadToEndAsync(); string pinsString = await new StreamReader(this.Request.Body).ReadToEndAsync();
Pins? pinJson = JsonSerializer.Deserialize<Pins>(pinsString); Pins? pinJson = JsonSerializer.Deserialize<Pins>(pinsString);
if (pinJson == null) return this.BadRequest(); if (pinJson == null) return this.BadRequest();
// Sometimes the update gets called periodically as pin progress updates via playing, // Sometimes the update gets called periodically as pin progress updates via playing,

View file

@ -0,0 +1,24 @@
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace LBPUnion.ProjectLighthouse
{
public class FakeRemoteIPAddressMiddleware
{
private readonly RequestDelegate next;
private readonly IPAddress fakeIpAddress = IPAddress.Parse("127.0.0.1");
public FakeRemoteIPAddressMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext httpContext)
{
httpContext.Connection.RemoteIpAddress = this.fakeIpAddress;
await this.next(httpContext);
}
}
}

View file

@ -1,3 +1,5 @@
using System.Diagnostics.CodeAnalysis;
namespace LBPUnion.ProjectLighthouse.Helpers namespace LBPUnion.ProjectLighthouse.Helpers
{ {
public static class EulaHelper public static class EulaHelper
@ -19,7 +21,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.";
public const string PrivateInstanceNotice = @"This server is a private testing instance. public const string PrivateInstanceNotice = @"This server is a private testing instance.
Please do not make anything public for now, and keep in mind security isn't as tight as a full release would."; Please do not make anything public for now, and keep in mind security isn't as tight as a full release would.";
// ReSharper disable once UnreachableCode [SuppressMessage("ReSharper", "HeuristicUnreachableCode")]
public const string PrivateInstanceNoticeOrBlank = ShowPrivateInstanceNotice ? PrivateInstanceNotice : ""; public const string PrivateInstanceNoticeOrBlank = ShowPrivateInstanceNotice ? PrivateInstanceNotice : "";
public const bool ShowPrivateInstanceNotice = false; public const bool ShowPrivateInstanceNotice = false;

View file

@ -1,17 +1,10 @@
using System.IO; using System.IO;
using System.Linq;
namespace LBPUnion.ProjectLighthouse.Helpers.Extensions namespace LBPUnion.ProjectLighthouse.Helpers.Extensions
{ {
public static class StringExtensions public static class StringExtensions
{ {
public static string ToFileName(this string text) public static string ToFileName(this string text) => Path.GetInvalidFileNameChars().Aggregate(text, (current, c) => current.Replace(c.ToString(), ""));
{
char[] invalidPathChars = Path.GetInvalidFileNameChars();
string path = text;
foreach (char c in invalidPathChars) path = path.Replace(c.ToString(), "");
return path;
}
} }
} }

View file

@ -1,12 +1,14 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics.CodeAnalysis;
namespace LBPUnion.ProjectLighthouse.Helpers namespace LBPUnion.ProjectLighthouse.Helpers
{ {
[NotMapped] [NotMapped]
[SuppressMessage("ReSharper", "CollectionNeverQueried.Global")]
public static class FriendHelper public static class FriendHelper
{ {
public static Dictionary<int, int[]> FriendIdsByUserId = new(); public static readonly Dictionary<int, int[]> FriendIdsByUserId = new();
public static Dictionary<int, int[]> BlockedIdsByUserId = new(); public static readonly Dictionary<int, int[]> BlockedIdsByUserId = new();
} }
} }

View file

@ -20,7 +20,7 @@ namespace LBPUnion.ProjectLighthouse.Helpers
SlotId = 0, SlotId = 0,
}; };
private static int roomIdIncrement = 0; private static int roomIdIncrement;
internal static int RoomIdIncrement => roomIdIncrement++; internal static int RoomIdIncrement => roomIdIncrement++;
@ -128,13 +128,8 @@ namespace LBPUnion.ProjectLighthouse.Helpers
public static Room? FindRoomByUser(User user, bool createIfDoesNotExist = false) public static Room? FindRoomByUser(User user, bool createIfDoesNotExist = false)
{ {
foreach (Room room in Rooms) foreach (Room room in Rooms.Where(room => room.Players.Any(player => user == player))) return room;
{
foreach (User player in room.Players)
{
if (user == player) return room;
}
}
return createIfDoesNotExist ? CreateRoom(user) : null; return createIfDoesNotExist ? CreateRoom(user) : null;
} }

View file

@ -9,6 +9,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="BCrypt.Net-Next" Version="4.0.2"/> <PackageReference Include="BCrypt.Net-Next" Version="4.0.2"/>
<PackageReference Include="JetBrains.Annotations" Version="2021.3.0"/>
<PackageReference Include="Kettu" Version="1.2.1"/> <PackageReference Include="Kettu" Version="1.2.1"/>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.0"/> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.0"/>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0"/> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.0"/>

View file

@ -51,7 +51,7 @@ namespace LBPUnion.ProjectLighthouse
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{ {
bool computeDigests = true; bool computeDigests = true;
string serverDigestKey = Environment.GetEnvironmentVariable("SERVER_DIGEST_KEY"); string serverDigestKey = Environment.GetEnvironmentVariable("SERVER_DIGEST_KEY");

View file

@ -0,0 +1,18 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
namespace LBPUnion.ProjectLighthouse
{
public class TestStartup : Startup
{
public TestStartup(IConfiguration configuration) : base(configuration)
{}
public override void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<FakeRemoteIPAddressMiddleware>();
base.Configure(app, env);
}
}
}

View file

@ -17,25 +17,25 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels
{ {
[XmlAttribute("type")] [XmlAttribute("type")]
[NotMapped] [NotMapped]
public string Type { get; set; } public string Type { get; set; } = "user";
[Key] [Key]
[XmlElement("id")] [XmlElement("id")]
public int SlotId { get; set; } public int SlotId { get; set; }
[XmlElement("name")] [XmlElement("name")]
public string Name { get; set; } public string Name { get; set; } = "";
[XmlElement("description")] [XmlElement("description")]
public string Description { get; set; } public string Description { get; set; } = "";
[XmlElement("icon")] [XmlElement("icon")]
public string IconHash { get; set; } public string IconHash { get; set; } = "";
[XmlElement("rootLevel")] [XmlElement("rootLevel")]
public string RootLevel { get; set; } public string RootLevel { get; set; } = "";
public string ResourceCollection { get; set; } public string ResourceCollection { get; set; } = "";
[NotMapped] [NotMapped]
[XmlElement("resource")] [XmlElement("resource")]
@ -51,14 +51,14 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels
public int CreatorId { get; set; } public int CreatorId { get; set; }
[ForeignKey(nameof(CreatorId))] [ForeignKey(nameof(CreatorId))]
public User Creator { get; set; } public User? Creator { get; set; }
/// <summary> /// <summary>
/// The location of the level on the creator's earth /// The location of the level on the creator's earth
/// </summary> /// </summary>
[XmlElement("location")] [XmlElement("location")]
[ForeignKey(nameof(LocationId))] [ForeignKey(nameof(LocationId))]
public Location Location { get; set; } public Location? Location { get; set; }
[XmlElement("initiallyLocked")] [XmlElement("initiallyLocked")]
public bool InitiallyLocked { get; set; } public bool InitiallyLocked { get; set; }
@ -111,21 +111,15 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels
[XmlIgnore] [XmlIgnore]
[NotMapped] [NotMapped]
public int Plays { public int Plays => this.PlaysLBP1 + this.PlaysLBP2 + this.PlaysLBP3 + this.PlaysLBPVita;
get => this.PlaysLBP1 + this.PlaysLBP2 + this.PlaysLBP3 + this.PlaysLBPVita;
}
[XmlIgnore] [XmlIgnore]
[NotMapped] [NotMapped]
public int PlaysUnique { public int PlaysUnique => this.PlaysLBP1Unique + this.PlaysLBP2Unique + this.PlaysLBP3Unique + this.PlaysLBPVitaUnique;
get => this.PlaysLBP1Unique + this.PlaysLBP2Unique + this.PlaysLBP3Unique + this.PlaysLBPVitaUnique;
}
[XmlIgnore] [XmlIgnore]
[NotMapped] [NotMapped]
public int PlaysComplete { public int PlaysComplete => this.PlaysLBP1Complete + this.PlaysLBP2Complete + this.PlaysLBP3Complete + this.PlaysLBPVitaComplete;
get => this.PlaysLBP1Complete + this.PlaysLBP2Complete + this.PlaysLBP3Complete + this.PlaysLBPVitaComplete;
}
[XmlIgnore] [XmlIgnore]
public int PlaysLBP1 { get; set; } public int PlaysLBP1 { get; set; }
@ -193,8 +187,6 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels
if (!ratedLevels.Any()) return 3.0; if (!ratedLevels.Any()) return 3.0;
return Enumerable.Average(ratedLevels, r => r.RatingLBP1); return Enumerable.Average(ratedLevels, r => r.RatingLBP1);
;
} }
} }
@ -217,7 +209,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels
LbpSerializer.StringElement("icon", this.IconHash) + LbpSerializer.StringElement("icon", this.IconHash) +
LbpSerializer.StringElement("rootLevel", this.RootLevel) + LbpSerializer.StringElement("rootLevel", this.RootLevel) +
this.SerializeResources() + this.SerializeResources() +
LbpSerializer.StringElement("location", this.Location.Serialize()) + LbpSerializer.StringElement("location", this.Location?.Serialize()) +
LbpSerializer.StringElement("initiallyLocked", this.InitiallyLocked) + LbpSerializer.StringElement("initiallyLocked", this.InitiallyLocked) +
LbpSerializer.StringElement("isSubLevel", this.SubLevel) + LbpSerializer.StringElement("isSubLevel", this.SubLevel) +
LbpSerializer.StringElement("isLBP1Only", this.Lbp1Only) + LbpSerializer.StringElement("isLBP1Only", this.Lbp1Only) +

View file

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace LBPUnion.ProjectLighthouse.Types.Match namespace LBPUnion.ProjectLighthouse.Types.Match
@ -13,6 +14,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Match
public IEnumerable<int> FirstSlot => this.Slots[0]; public IEnumerable<int> FirstSlot => this.Slots[0];
[JsonPropertyName("Location")] [JsonPropertyName("Location")]
[SuppressMessage("ReSharper", "CollectionNeverQueried.Global")]
public List<string> Locations { get; set; } public List<string> Locations { get; set; }
} }
} }

View file

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Levels;
namespace LBPUnion.ProjectLighthouse.Types.Match namespace LBPUnion.ProjectLighthouse.Types.Match
@ -17,6 +18,13 @@ namespace LBPUnion.ProjectLighthouse.Types.Match
public User Host => this.Players[0]; public User Host => this.Players[0];
#nullable enable #nullable enable
public override bool Equals(object? obj)
{
if (obj is Room room) return room.RoomId == RoomId;
return false;
}
public static bool operator ==(Room? room1, Room? room2) public static bool operator ==(Room? room1, Room? room2)
{ {
if (ReferenceEquals(room1, room2)) return true; if (ReferenceEquals(room1, room2)) return true;
@ -26,6 +34,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Match
} }
public static bool operator !=(Room? room1, Room? room2) => !(room1 == room2); public static bool operator !=(Room? room1, Room? room2) => !(room1 == room2);
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
public override int GetHashCode() => this.RoomId; public override int GetHashCode() => this.RoomId;
#nullable disable #nullable disable
} }

View file

@ -1,5 +1,8 @@
using System.Diagnostics.CodeAnalysis;
namespace LBPUnion.ProjectLighthouse.Types.Match namespace LBPUnion.ProjectLighthouse.Types.Match
{ {
[SuppressMessage("ReSharper", "UnusedMember.Global")]
public enum RoomState public enum RoomState
{ {
/// <summary> /// <summary>

View file

@ -3,7 +3,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Match
{ {
public class UpdateMyPlayerData : IMatchData public class UpdateMyPlayerData : IMatchData
{ {
public string Player { get; set; } public string Player { get; set; } = null!;
public RoomState? RoomState { get; set; } public RoomState? RoomState { get; set; }
} }

View file

@ -22,19 +22,19 @@ namespace LBPUnion.ProjectLighthouse.Types
public long Timestamp { get; set; } public long Timestamp { get; set; }
[XmlElement("small")] [XmlElement("small")]
public string SmallHash { get; set; } public string SmallHash { get; set; } = "";
[XmlElement("medium")] [XmlElement("medium")]
public string MediumHash { get; set; } public string MediumHash { get; set; } = "";
[XmlElement("large")] [XmlElement("large")]
public string LargeHash { get; set; } public string LargeHash { get; set; } = "";
[XmlElement("plan")] [XmlElement("plan")]
public string PlanHash { get; set; } public string PlanHash { get; set; } = "";
[NotMapped] [NotMapped]
private List<PhotoSubject>? subjects; private List<PhotoSubject>? _subjects;
[NotMapped] [NotMapped]
[XmlArray("subjects")] [XmlArray("subjects")]
@ -45,15 +45,13 @@ namespace LBPUnion.ProjectLighthouse.Types
public List<PhotoSubject> Subjects { public List<PhotoSubject> Subjects {
get { get {
if (this.SubjectsXmlDontUseLiterallyEver != null) return this.SubjectsXmlDontUseLiterallyEver; if (this.SubjectsXmlDontUseLiterallyEver != null) return this.SubjectsXmlDontUseLiterallyEver;
if (this.subjects != null) return this.subjects; if (this._subjects != null) return this._subjects;
List<PhotoSubject> response = new(); List<PhotoSubject> response = new();
using Database database = new(); using Database database = new();
foreach (string idStr in this.PhotoSubjectIds) foreach (string idStr in this.PhotoSubjectIds.Where(idStr => !string.IsNullOrEmpty(idStr)))
{ {
if (string.IsNullOrEmpty(idStr)) continue;
if (!int.TryParse(idStr, out int id)) throw new InvalidCastException(idStr + " is not a valid number."); if (!int.TryParse(idStr, out int id)) throw new InvalidCastException(idStr + " is not a valid number.");
PhotoSubject? photoSubject = database.PhotoSubjects.Include(p => p.User).FirstOrDefault(p => p.PhotoSubjectId == id); PhotoSubject? photoSubject = database.PhotoSubjects.Include(p => p.User).FirstOrDefault(p => p.PhotoSubjectId == id);
@ -64,7 +62,7 @@ namespace LBPUnion.ProjectLighthouse.Types
return response; return response;
} }
set => this.subjects = value; set => this._subjects = value;
} }
[NotMapped] [NotMapped]
@ -74,12 +72,12 @@ namespace LBPUnion.ProjectLighthouse.Types
set => this.PhotoSubjectCollection = string.Join(',', value); set => this.PhotoSubjectCollection = string.Join(',', value);
} }
public string PhotoSubjectCollection { get; set; } public string PhotoSubjectCollection { get; set; } = "";
public int CreatorId { get; set; } public int CreatorId { get; set; }
[ForeignKey(nameof(CreatorId))] [ForeignKey(nameof(CreatorId))]
public User Creator { get; set; } public User? Creator { get; set; }
public string Serialize(int slotId) public string Serialize(int slotId)
{ {
@ -92,7 +90,7 @@ namespace LBPUnion.ProjectLighthouse.Types
LbpSerializer.StringElement("medium", this.MediumHash) + LbpSerializer.StringElement("medium", this.MediumHash) +
LbpSerializer.StringElement("large", this.LargeHash) + LbpSerializer.StringElement("large", this.LargeHash) +
LbpSerializer.StringElement("plan", this.PlanHash) + LbpSerializer.StringElement("plan", this.PlanHash) +
LbpSerializer.StringElement("author", this.Creator.Username) + LbpSerializer.StringElement("author", this.Creator?.Username) +
LbpSerializer.StringElement("subjects", subjectsAggregate) + LbpSerializer.StringElement("subjects", subjectsAggregate) +
slot; slot;

View file

@ -206,6 +206,7 @@ namespace LBPUnion.ProjectLighthouse.Types
} }
public static bool operator !=(User? user1, User? user2) => !(user1 == user2); public static bool operator !=(User? user1, User? user2) => !(user1 == user2);
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
public override int GetHashCode() => this.UserId; public override int GetHashCode() => this.UserId;
#nullable disable #nullable disable
} }