diff --git a/ProjectLighthouse.Tests/LighthouseTest.cs b/ProjectLighthouse.Tests/LighthouseTest.cs index 00a7e191..df207d74 100644 --- a/ProjectLighthouse.Tests/LighthouseTest.cs +++ b/ProjectLighthouse.Tests/LighthouseTest.cs @@ -19,7 +19,7 @@ namespace LBPUnion.ProjectLighthouse.Tests public LighthouseTest() { - this.Server = new TestServer(new WebHostBuilder().UseStartup()); + this.Server = new TestServer(new WebHostBuilder().UseStartup()); this.Client = this.Server.CreateClient(); } diff --git a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj index cc77d93b..0f656960 100644 --- a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj +++ b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj @@ -13,6 +13,7 @@ + all diff --git a/ProjectLighthouse.Tests/Tests/SlotTests.cs b/ProjectLighthouse.Tests/Tests/SlotTests.cs index ea0ea3c3..65abac0f 100644 --- a/ProjectLighthouse.Tests/Tests/SlotTests.cs +++ b/ProjectLighthouse.Tests/Tests/SlotTests.cs @@ -1,3 +1,4 @@ +using System.Net.Http; using System.Threading.Tasks; using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types.Levels; @@ -48,10 +49,17 @@ namespace LBPUnion.ProjectLighthouse.Tests LoginResult loginResult = await this.Authenticate(); - string respA = await (await this.AuthenticatedRequest("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser0", loginResult.AuthTicket)).Content - .ReadAsStringAsync(); - string respB = await (await this.AuthenticatedRequest("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser1", loginResult.AuthTicket)).Content - .ReadAsStringAsync(); + HttpResponseMessage respMessageA = await this.AuthenticatedRequest("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser0", loginResult.AuthTicket); + HttpResponseMessage respMessageB = await this.AuthenticatedRequest("LITTLEBIGPLANETPS3_XML/slots/by?u=unitTestUser1", loginResult.AuthTicket); + + 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.DoesNotContain(respA, "slotB"); diff --git a/ProjectLighthouse.sln.DotSettings b/ProjectLighthouse.sln.DotSettings index 779d9d6e..34c3a59a 100644 --- a/ProjectLighthouse.sln.DotSettings +++ b/ProjectLighthouse.sln.DotSettings @@ -73,6 +73,7 @@ UseExplicitType UseExplicitType DLC + IP LBP MM NAT @@ -93,6 +94,7 @@ True True True + True True True True diff --git a/ProjectLighthouse/Controllers/CommentController.cs b/ProjectLighthouse/Controllers/CommentController.cs index 5d673e5e..fd7cbbbf 100644 --- a/ProjectLighthouse/Controllers/CommentController.cs +++ b/ProjectLighthouse/Controllers/CommentController.cs @@ -1,3 +1,4 @@ +#nullable enable using System.Collections.Generic; using System.IO; using System.Linq; @@ -44,14 +45,12 @@ namespace LBPUnion.ProjectLighthouse.Controllers string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); XmlSerializer serializer = new(typeof(Comment)); - Comment comment = (Comment)serializer.Deserialize(new StringReader(bodyString)); - - User poster = await this.database.UserFromRequest(this.Request); + Comment? comment = (Comment?)serializer.Deserialize(new StringReader(bodyString)); + User? poster = await this.database.UserFromRequest(this.Request); 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(); comment.PosterUserId = poster.UserId; @@ -67,10 +66,14 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("deleteUserComment/{username}")] public async Task 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, ""); - 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, ""); diff --git a/ProjectLighthouse/Controllers/EnterLevelController.cs b/ProjectLighthouse/Controllers/EnterLevelController.cs index cebca719..d704cfcc 100644 --- a/ProjectLighthouse/Controllers/EnterLevelController.cs +++ b/ProjectLighthouse/Controllers/EnterLevelController.cs @@ -1,4 +1,5 @@ #nullable enable +using System; using System.Linq; using System.Threading.Tasks; using LBPUnion.ProjectLighthouse.Types; @@ -52,7 +53,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers default: return this.BadRequest(); } - v = new(); + v = new VisitedLevel(); v.SlotId = slotId; v.UserId = user.UserId; 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.NotFound(); + } + switch (gameVersion) { case GameVersion.LittleBigPlanet2: @@ -77,7 +83,10 @@ namespace LBPUnion.ProjectLighthouse.Controllers slot.PlaysLBPVita++; v.PlaysLBPVita++; break; - default: return this.BadRequest(); + case GameVersion.LittleBigPlanetPSP: throw new NotImplementedException(); + case GameVersion.Unknown: + default: + return this.BadRequest(); } await this.database.SaveChangesAsync(); @@ -101,7 +110,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers { slot.PlaysLBP1Unique++; - v = new(); + v = new VisitedLevel(); v.SlotId = id; v.UserId = user.UserId; this.database.VisitedLevels.Add(v); @@ -112,6 +121,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers } if (v == null) return StatusCode(403, ""); + if (v == null) + { + return this.NotFound(); + } + slot.PlaysLBP1++; v.PlaysLBP1++; diff --git a/ProjectLighthouse/Controllers/ListController.cs b/ProjectLighthouse/Controllers/ListController.cs index a290bc36..4e3014f8 100644 --- a/ProjectLighthouse/Controllers/ListController.cs +++ b/ProjectLighthouse/Controllers/ListController.cs @@ -46,7 +46,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers 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}")] @@ -110,7 +114,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers 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}")] @@ -173,7 +181,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers 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}")] @@ -224,4 +236,4 @@ namespace LBPUnion.ProjectLighthouse.Controllers #endregion } -} +} \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/PhotosController.cs b/ProjectLighthouse/Controllers/PhotosController.cs index 3f224432..6dce4228 100644 --- a/ProjectLighthouse/Controllers/PhotosController.cs +++ b/ProjectLighthouse/Controllers/PhotosController.cs @@ -82,7 +82,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers { User? userFromQuery = await this.database.Users.FirstOrDefaultAsync(u => u.Username == user); // ReSharper disable once ConditionIsAlwaysTrueOrFalse - if (user == null || userFromQuery == null) return this.NotFound(); + if (userFromQuery == null) return this.NotFound(); List photos = await this.database.Photos.Include (p => p.Creator) @@ -100,7 +100,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers { User? userFromQuery = await this.database.Users.FirstOrDefaultAsync(u => u.Username == user); // ReSharper disable once ConditionIsAlwaysTrueOrFalse - if (user == null || userFromQuery == null) return this.NotFound(); + if (userFromQuery == null) return this.NotFound(); List photos = new(); foreach (Photo photo in this.database.Photos.Include(p => p.Creator)) diff --git a/ProjectLighthouse/Controllers/PublishController.cs b/ProjectLighthouse/Controllers/PublishController.cs index 483d4b22..d7094138 100644 --- a/ProjectLighthouse/Controllers/PublishController.cs +++ b/ProjectLighthouse/Controllers/PublishController.cs @@ -1,3 +1,5 @@ +#nullable enable +using System; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -30,10 +32,10 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("startPublish")] public async Task StartPublish() { - User user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromRequest(this.Request); 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 (string.IsNullOrEmpty(slot.RootLevel)) return this.BadRequest(); @@ -43,7 +45,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers // Republish logic 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.CreatorId != user.UserId) return this.BadRequest(); } @@ -72,13 +74,17 @@ namespace LBPUnion.ProjectLighthouse.Controllers User user = userAndToken.Value.Item1; 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 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.Location == null) throw new ArgumentNullException(); + if (oldSlot.CreatorId != user.UserId) return this.BadRequest(); oldSlot.Location.X = slot.Location.X; @@ -125,10 +131,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("unpublish/{id:int}")] public async Task 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, ""); - 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, ""); @@ -140,13 +149,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers return this.Ok(); } - public async Task GetSlotFromBody() + public async Task GetSlotFromBody() { this.Request.Body.Position = 0; string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); XmlSerializer serializer = new(typeof(Slot)); - Slot slot = (Slot)serializer.Deserialize(new StringReader(bodyString)); + Slot? slot = (Slot?)serializer.Deserialize(new StringReader(bodyString)); return slot; } diff --git a/ProjectLighthouse/Controllers/ReviewController.cs b/ProjectLighthouse/Controllers/ReviewController.cs index cece8a3e..c50435af 100644 --- a/ProjectLighthouse/Controllers/ReviewController.cs +++ b/ProjectLighthouse/Controllers/ReviewController.cs @@ -33,13 +33,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == user.UserId); if (ratedLevel == null) { - ratedLevel = new(); + ratedLevel = new RatedLevel(); ratedLevel.SlotId = slotId; ratedLevel.UserId = user.UserId; ratedLevel.Rating = 0; this.database.RatedLevels.Add(ratedLevel); } - + ratedLevel.RatingLBP1 = Math.Max(Math.Min(5, rating), 0); await this.database.SaveChangesAsync(); @@ -48,7 +48,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers } // LBP2 and beyond rating - [HttpPost("dpadrate/user/{slotId}")] + [HttpPost("dpadrate/user/{slotId:int}")] public async Task DPadRate(int slotId, [FromQuery] int rating) { 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); if (ratedLevel == null) { - ratedLevel = new(); + ratedLevel = new RatedLevel(); ratedLevel.SlotId = slotId; ratedLevel.UserId = user.UserId; ratedLevel.RatingLBP1 = 0; this.database.RatedLevels.Add(ratedLevel); } - + ratedLevel.Rating = Math.Max(Math.Min(1, rating), -1); await this.database.SaveChangesAsync(); return this.Ok(); } - + } } \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/ScoreController.cs b/ProjectLighthouse/Controllers/ScoreController.cs index 283dc0b9..6f75e4d1 100644 --- a/ProjectLighthouse/Controllers/ScoreController.cs +++ b/ProjectLighthouse/Controllers/ScoreController.cs @@ -102,6 +102,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers 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) { // This is hella ugly but it technically assigns the proper rank to a score diff --git a/ProjectLighthouse/Controllers/SlotsController.cs b/ProjectLighthouse/Controllers/SlotsController.cs index 4f1b112b..48e45184 100644 --- a/ProjectLighthouse/Controllers/SlotsController.cs +++ b/ProjectLighthouse/Controllers/SlotsController.cs @@ -32,14 +32,14 @@ namespace LBPUnion.ProjectLighthouse.Controllers GameVersion gameVersion = token.GameVersion; 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 ( this.database.Slots.Where(s => s.GameVersion <= gameVersion) .Include(s => s.Creator) .Include(s => s.Location) - .Where(s => s.Creator.Username == user.Username) + .Where(s => s.Creator!.Username == user.Username) .Skip(pageStart - 1) .Take(Math.Min(pageSize, ServerSettings.EntitledSlots)), string.Empty, diff --git a/ProjectLighthouse/Controllers/UserController.cs b/ProjectLighthouse/Controllers/UserController.cs index 2fd3efe2..7e54b1ad 100644 --- a/ProjectLighthouse/Controllers/UserController.cs +++ b/ProjectLighthouse/Controllers/UserController.cs @@ -26,9 +26,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers this.database = database; } - public async Task GetSerializedUser(string username, GameVersion gameVersion = GameVersion.LittleBigPlanet1) + public async Task GetSerializedUser(string username, GameVersion gameVersion = GameVersion.LittleBigPlanet1) { - User? user = await this.database.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.Username == username); if (user == null) return ""; return user.Serialize(gameVersion); @@ -52,14 +51,14 @@ namespace LBPUnion.ProjectLighthouse.Controllers Token? token = await this.database.TokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); - List serializedUsers = new(); + List serializedUsers = new(); foreach (string userId in u) { string? serializedUser = await this.GetSerializedUser(userId, token.GameVersion); 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)); } @@ -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: 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 - if (l == null) return this.StatusCode(403, ""); + Location? l = await this.database.Locations.FirstOrDefaultAsync(l => l.Id == user.LocationId); // find the location in the database again + + 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 l.X = user.Location.X; l.Y = user.Location.Y; @@ -166,7 +170,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers string pinsString = await new StreamReader(this.Request.Body).ReadToEndAsync(); Pins? pinJson = JsonSerializer.Deserialize(pinsString); - if (pinJson == null) return this.BadRequest(); // Sometimes the update gets called periodically as pin progress updates via playing, diff --git a/ProjectLighthouse/FakeRemoteIPAddressMiddleware.cs b/ProjectLighthouse/FakeRemoteIPAddressMiddleware.cs new file mode 100644 index 00000000..6a5a200e --- /dev/null +++ b/ProjectLighthouse/FakeRemoteIPAddressMiddleware.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/EulaHelper.cs b/ProjectLighthouse/Helpers/EulaHelper.cs index 195963c5..bf59ff2c 100644 --- a/ProjectLighthouse/Helpers/EulaHelper.cs +++ b/ProjectLighthouse/Helpers/EulaHelper.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; + namespace LBPUnion.ProjectLighthouse.Helpers { public static class EulaHelper @@ -19,7 +21,7 @@ along with this program. If not, see ."; 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."; - // ReSharper disable once UnreachableCode + [SuppressMessage("ReSharper", "HeuristicUnreachableCode")] public const string PrivateInstanceNoticeOrBlank = ShowPrivateInstanceNotice ? PrivateInstanceNotice : ""; public const bool ShowPrivateInstanceNotice = false; diff --git a/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs b/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs index 177027de..72ef05af 100644 --- a/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs +++ b/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs @@ -1,17 +1,10 @@ using System.IO; +using System.Linq; namespace LBPUnion.ProjectLighthouse.Helpers.Extensions { public static class StringExtensions { - public static string ToFileName(this string text) - { - char[] invalidPathChars = Path.GetInvalidFileNameChars(); - string path = text; - - foreach (char c in invalidPathChars) path = path.Replace(c.ToString(), ""); - - return path; - } + public static string ToFileName(this string text) => Path.GetInvalidFileNameChars().Aggregate(text, (current, c) => current.Replace(c.ToString(), "")); } } \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/FriendHelper.cs b/ProjectLighthouse/Helpers/FriendHelper.cs index 9475e582..41639c46 100644 --- a/ProjectLighthouse/Helpers/FriendHelper.cs +++ b/ProjectLighthouse/Helpers/FriendHelper.cs @@ -1,12 +1,14 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics.CodeAnalysis; namespace LBPUnion.ProjectLighthouse.Helpers { [NotMapped] + [SuppressMessage("ReSharper", "CollectionNeverQueried.Global")] public static class FriendHelper { - public static Dictionary FriendIdsByUserId = new(); - public static Dictionary BlockedIdsByUserId = new(); + public static readonly Dictionary FriendIdsByUserId = new(); + public static readonly Dictionary BlockedIdsByUserId = new(); } } \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/RoomHelper.cs b/ProjectLighthouse/Helpers/RoomHelper.cs index e654bed3..285e2b93 100644 --- a/ProjectLighthouse/Helpers/RoomHelper.cs +++ b/ProjectLighthouse/Helpers/RoomHelper.cs @@ -20,7 +20,7 @@ namespace LBPUnion.ProjectLighthouse.Helpers SlotId = 0, }; - private static int roomIdIncrement = 0; + private static int roomIdIncrement; internal static int RoomIdIncrement => roomIdIncrement++; @@ -128,13 +128,8 @@ namespace LBPUnion.ProjectLighthouse.Helpers public static Room? FindRoomByUser(User user, bool createIfDoesNotExist = false) { - foreach (Room room in Rooms) - { - foreach (User player in room.Players) - { - if (user == player) return room; - } - } + foreach (Room room in Rooms.Where(room => room.Players.Any(player => user == player))) return room; + return createIfDoesNotExist ? CreateRoom(user) : null; } diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index 1b8e4906..51f3117d 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -9,6 +9,7 @@ + diff --git a/ProjectLighthouse/Startup.cs b/ProjectLighthouse/Startup.cs index 106b27da..93e41f3d 100644 --- a/ProjectLighthouse/Startup.cs +++ b/ProjectLighthouse/Startup.cs @@ -51,7 +51,7 @@ namespace LBPUnion.ProjectLighthouse } // 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; string serverDigestKey = Environment.GetEnvironmentVariable("SERVER_DIGEST_KEY"); diff --git a/ProjectLighthouse/TestStartup.cs b/ProjectLighthouse/TestStartup.cs new file mode 100644 index 00000000..2601c9ca --- /dev/null +++ b/ProjectLighthouse/TestStartup.cs @@ -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(); + base.Configure(app, env); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Levels/Slot.cs b/ProjectLighthouse/Types/Levels/Slot.cs index d597f88c..f21c7240 100644 --- a/ProjectLighthouse/Types/Levels/Slot.cs +++ b/ProjectLighthouse/Types/Levels/Slot.cs @@ -17,25 +17,25 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels { [XmlAttribute("type")] [NotMapped] - public string Type { get; set; } + public string Type { get; set; } = "user"; [Key] [XmlElement("id")] public int SlotId { get; set; } [XmlElement("name")] - public string Name { get; set; } + public string Name { get; set; } = ""; [XmlElement("description")] - public string Description { get; set; } + public string Description { get; set; } = ""; [XmlElement("icon")] - public string IconHash { get; set; } + public string IconHash { get; set; } = ""; [XmlElement("rootLevel")] - public string RootLevel { get; set; } + public string RootLevel { get; set; } = ""; - public string ResourceCollection { get; set; } + public string ResourceCollection { get; set; } = ""; [NotMapped] [XmlElement("resource")] @@ -51,14 +51,14 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels public int CreatorId { get; set; } [ForeignKey(nameof(CreatorId))] - public User Creator { get; set; } + public User? Creator { get; set; } /// /// The location of the level on the creator's earth /// [XmlElement("location")] [ForeignKey(nameof(LocationId))] - public Location Location { get; set; } + public Location? Location { get; set; } [XmlElement("initiallyLocked")] public bool InitiallyLocked { get; set; } @@ -111,21 +111,15 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels [XmlIgnore] [NotMapped] - public int Plays { - get => this.PlaysLBP1 + this.PlaysLBP2 + this.PlaysLBP3 + this.PlaysLBPVita; - } + public int Plays => this.PlaysLBP1 + this.PlaysLBP2 + this.PlaysLBP3 + this.PlaysLBPVita; [XmlIgnore] [NotMapped] - public int PlaysUnique { - get => this.PlaysLBP1Unique + this.PlaysLBP2Unique + this.PlaysLBP3Unique + this.PlaysLBPVitaUnique; - } + public int PlaysUnique => this.PlaysLBP1Unique + this.PlaysLBP2Unique + this.PlaysLBP3Unique + this.PlaysLBPVitaUnique; [XmlIgnore] [NotMapped] - public int PlaysComplete { - get => this.PlaysLBP1Complete + this.PlaysLBP2Complete + this.PlaysLBP3Complete + this.PlaysLBPVitaComplete; - } + public int PlaysComplete => this.PlaysLBP1Complete + this.PlaysLBP2Complete + this.PlaysLBP3Complete + this.PlaysLBPVitaComplete; [XmlIgnore] public int PlaysLBP1 { get; set; } @@ -193,8 +187,6 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels if (!ratedLevels.Any()) return 3.0; return Enumerable.Average(ratedLevels, r => r.RatingLBP1); - - ; } } @@ -217,7 +209,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels LbpSerializer.StringElement("icon", this.IconHash) + LbpSerializer.StringElement("rootLevel", this.RootLevel) + this.SerializeResources() + - LbpSerializer.StringElement("location", this.Location.Serialize()) + + LbpSerializer.StringElement("location", this.Location?.Serialize()) + LbpSerializer.StringElement("initiallyLocked", this.InitiallyLocked) + LbpSerializer.StringElement("isSubLevel", this.SubLevel) + LbpSerializer.StringElement("isLBP1Only", this.Lbp1Only) + diff --git a/ProjectLighthouse/Types/Match/FindBestRoomResponse.cs b/ProjectLighthouse/Types/Match/FindBestRoomResponse.cs index 6c1e968f..e1eed707 100644 --- a/ProjectLighthouse/Types/Match/FindBestRoomResponse.cs +++ b/ProjectLighthouse/Types/Match/FindBestRoomResponse.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; namespace LBPUnion.ProjectLighthouse.Types.Match @@ -13,6 +14,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Match public IEnumerable FirstSlot => this.Slots[0]; [JsonPropertyName("Location")] + [SuppressMessage("ReSharper", "CollectionNeverQueried.Global")] public List Locations { get; set; } } } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Match/Room.cs b/ProjectLighthouse/Types/Match/Room.cs index 213e565f..4c6b93d5 100644 --- a/ProjectLighthouse/Types/Match/Room.cs +++ b/ProjectLighthouse/Types/Match/Room.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using LBPUnion.ProjectLighthouse.Types.Levels; namespace LBPUnion.ProjectLighthouse.Types.Match @@ -17,6 +18,13 @@ namespace LBPUnion.ProjectLighthouse.Types.Match public User Host => this.Players[0]; #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) { 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); + [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] public override int GetHashCode() => this.RoomId; #nullable disable } diff --git a/ProjectLighthouse/Types/Match/RoomState.cs b/ProjectLighthouse/Types/Match/RoomState.cs index f3d31406..5d949ac0 100644 --- a/ProjectLighthouse/Types/Match/RoomState.cs +++ b/ProjectLighthouse/Types/Match/RoomState.cs @@ -1,5 +1,8 @@ +using System.Diagnostics.CodeAnalysis; + namespace LBPUnion.ProjectLighthouse.Types.Match { + [SuppressMessage("ReSharper", "UnusedMember.Global")] public enum RoomState { /// diff --git a/ProjectLighthouse/Types/Match/UpdateMyPlayerData.cs b/ProjectLighthouse/Types/Match/UpdateMyPlayerData.cs index fde5b8e7..50d774cf 100644 --- a/ProjectLighthouse/Types/Match/UpdateMyPlayerData.cs +++ b/ProjectLighthouse/Types/Match/UpdateMyPlayerData.cs @@ -3,7 +3,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Match { public class UpdateMyPlayerData : IMatchData { - public string Player { get; set; } + public string Player { get; set; } = null!; public RoomState? RoomState { get; set; } } diff --git a/ProjectLighthouse/Types/Photo.cs b/ProjectLighthouse/Types/Photo.cs index bbbf39ef..317f0b09 100644 --- a/ProjectLighthouse/Types/Photo.cs +++ b/ProjectLighthouse/Types/Photo.cs @@ -22,19 +22,19 @@ namespace LBPUnion.ProjectLighthouse.Types public long Timestamp { get; set; } [XmlElement("small")] - public string SmallHash { get; set; } + public string SmallHash { get; set; } = ""; [XmlElement("medium")] - public string MediumHash { get; set; } + public string MediumHash { get; set; } = ""; [XmlElement("large")] - public string LargeHash { get; set; } + public string LargeHash { get; set; } = ""; [XmlElement("plan")] - public string PlanHash { get; set; } + public string PlanHash { get; set; } = ""; [NotMapped] - private List? subjects; + private List? _subjects; [NotMapped] [XmlArray("subjects")] @@ -45,15 +45,13 @@ namespace LBPUnion.ProjectLighthouse.Types public List Subjects { get { if (this.SubjectsXmlDontUseLiterallyEver != null) return this.SubjectsXmlDontUseLiterallyEver; - if (this.subjects != null) return this.subjects; + if (this._subjects != null) return this._subjects; List response = 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."); PhotoSubject? photoSubject = database.PhotoSubjects.Include(p => p.User).FirstOrDefault(p => p.PhotoSubjectId == id); @@ -64,7 +62,7 @@ namespace LBPUnion.ProjectLighthouse.Types return response; } - set => this.subjects = value; + set => this._subjects = value; } [NotMapped] @@ -74,12 +72,12 @@ namespace LBPUnion.ProjectLighthouse.Types set => this.PhotoSubjectCollection = string.Join(',', value); } - public string PhotoSubjectCollection { get; set; } + public string PhotoSubjectCollection { get; set; } = ""; public int CreatorId { get; set; } [ForeignKey(nameof(CreatorId))] - public User Creator { get; set; } + public User? Creator { get; set; } public string Serialize(int slotId) { @@ -92,7 +90,7 @@ namespace LBPUnion.ProjectLighthouse.Types LbpSerializer.StringElement("medium", this.MediumHash) + LbpSerializer.StringElement("large", this.LargeHash) + LbpSerializer.StringElement("plan", this.PlanHash) + - LbpSerializer.StringElement("author", this.Creator.Username) + + LbpSerializer.StringElement("author", this.Creator?.Username) + LbpSerializer.StringElement("subjects", subjectsAggregate) + slot; diff --git a/ProjectLighthouse/Types/User.cs b/ProjectLighthouse/Types/User.cs index 14de418d..83c0806a 100644 --- a/ProjectLighthouse/Types/User.cs +++ b/ProjectLighthouse/Types/User.cs @@ -206,6 +206,7 @@ namespace LBPUnion.ProjectLighthouse.Types } public static bool operator !=(User? user1, User? user2) => !(user1 == user2); + [SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")] public override int GetHashCode() => this.UserId; #nullable disable }