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.sln.DotSettings b/ProjectLighthouse.sln.DotSettings index 779d9d6e..5e7b6c93 100644 --- a/ProjectLighthouse.sln.DotSettings +++ b/ProjectLighthouse.sln.DotSettings @@ -93,6 +93,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 1e409bd3..fc46d90b 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; @@ -35,7 +36,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers GameVersion gameVersion = token.GameVersion; IQueryable visited = this.database.VisitedLevels.Where(s => s.SlotId == slotId && s.UserId == user.UserId); - VisitedLevel v; + VisitedLevel? v; if (!visited.Any()) { switch (gameVersion) @@ -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); @@ -62,6 +63,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers v = await visited.FirstOrDefaultAsync(); } + if (v == null) + { + return this.NotFound(); + } + switch (gameVersion) { case GameVersion.LittleBigPlanet2: @@ -76,7 +82,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(); @@ -95,12 +104,12 @@ namespace LBPUnion.ProjectLighthouse.Controllers if (slot == null) return this.NotFound(); IQueryable visited = this.database.VisitedLevels.Where(s => s.SlotId == id && s.UserId == user.UserId); - VisitedLevel v; + VisitedLevel? v; if (!visited.Any()) { slot.PlaysLBP1Unique++; - v = new(); + v = new VisitedLevel(); v.SlotId = id; v.UserId = user.UserId; this.database.VisitedLevels.Add(v); @@ -110,6 +119,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers v = await visited.FirstOrDefaultAsync(); } + if (v == null) + { + return this.NotFound(); + } + slot.PlaysLBP1++; v.PlaysLBP1++; diff --git a/ProjectLighthouse/Controllers/ListController.cs b/ProjectLighthouse/Controllers/ListController.cs index d59cef44..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}")] @@ -55,7 +59,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers User? user = await this.database.UserFromRequest(this.Request); if (user == null) return this.StatusCode(403, ""); - QueuedLevel queuedLevel = await this.database.QueuedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); + QueuedLevel? queuedLevel = await this.database.QueuedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); if (queuedLevel != null) return this.Ok(); this.database.QueuedLevels.Add @@ -78,7 +82,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers User? user = await this.database.UserFromRequest(this.Request); if (user == null) return this.StatusCode(403, ""); - QueuedLevel queuedLevel = await this.database.QueuedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); + QueuedLevel? queuedLevel = await this.database.QueuedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); if (queuedLevel != null) this.database.QueuedLevels.Remove(queuedLevel); await this.database.SaveChangesAsync(); @@ -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}")] @@ -119,7 +127,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers User? user = await this.database.UserFromRequest(this.Request); if (user == null) return this.StatusCode(403, ""); - HeartedLevel heartedLevel = await this.database.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); + HeartedLevel? heartedLevel = await this.database.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); if (heartedLevel != null) return this.Ok(); this.database.HeartedLevels.Add @@ -142,7 +150,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers User? user = await this.database.UserFromRequest(this.Request); if (user == null) return this.StatusCode(403, ""); - HeartedLevel heartedLevel = await this.database.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); + HeartedLevel? heartedLevel = await this.database.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == user.UserId && q.SlotId == id); if (heartedLevel != null) this.database.HeartedLevels.Remove(heartedLevel); await this.database.SaveChangesAsync(); @@ -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}")] @@ -185,7 +197,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); if (heartedUser == null) return this.NotFound(); - HeartedProfile heartedProfile = await this.database.HeartedProfiles.FirstOrDefaultAsync + HeartedProfile? heartedProfile = await this.database.HeartedProfiles.FirstOrDefaultAsync (q => q.UserId == user.UserId && q.HeartedUserId == heartedUser.UserId); if (heartedProfile != null) return this.Ok(); @@ -212,7 +224,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); if (heartedUser == null) return this.NotFound(); - HeartedProfile heartedProfile = await this.database.HeartedProfiles.FirstOrDefaultAsync + HeartedProfile? heartedProfile = await this.database.HeartedProfiles.FirstOrDefaultAsync (q => q.UserId == user.UserId && q.HeartedUserId == heartedUser.UserId); if (heartedProfile != null) this.database.HeartedProfiles.Remove(heartedProfile); @@ -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 c853aedf..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) 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) 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 05019a1f..6f75e4d1 100644 --- a/ProjectLighthouse/Controllers/ScoreController.cs +++ b/ProjectLighthouse/Controllers/ScoreController.cs @@ -80,7 +80,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers await this.database.SaveChangesAsync(); - string myRanking = await GetScores(score.SlotId, score.Type, user); + string myRanking = GetScores(score.SlotId, score.Type, user); return this.Ok(myRanking); } @@ -99,10 +99,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers if (user == null) return this.StatusCode(403, ""); - return this.Ok(await GetScores(slotId, type, user, pageStart, pageSize)); + return this.Ok(GetScores(slotId, type, user, pageStart, pageSize)); } - public async Task GetScores(int slotId, int type, User user, int pageStart = -1, int pageSize = 5) + [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 // var needed for Anonymous type returned from SELECT diff --git a/ProjectLighthouse/Controllers/SlotsController.cs b/ProjectLighthouse/Controllers/SlotsController.cs index 988f63ef..48e45184 100644 --- a/ProjectLighthouse/Controllers/SlotsController.cs +++ b/ProjectLighthouse/Controllers/SlotsController.cs @@ -31,14 +31,15 @@ namespace LBPUnion.ProjectLighthouse.Controllers 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 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 d3f07198..0c787e74 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); return user?.Serialize(gameVersion); } @@ -51,13 +50,13 @@ 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) { serializedUsers.Add(await this.GetSerializedUser(userId, token.GameVersion)); } - 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)); } @@ -68,8 +67,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("updateUser")] public async Task UpdateUser() { - User user = await this.database.UserFromRequest(this.Request); - + User? user = await this.database.UserFromRequest(this.Request); if (user == null) return this.StatusCode(403, ""); XmlReaderSettings settings = new() @@ -144,7 +142,12 @@ 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 + 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; @@ -160,12 +163,11 @@ namespace LBPUnion.ProjectLighthouse.Controllers [HttpPost("update_my_pins")] public async Task UpdateMyPins() { - User user = await this.database.UserFromRequest(this.Request); + User? user = await this.database.UserFromRequest(this.Request); if (user == null) return this.StatusCode(403, ""); string pinsString = await new StreamReader(this.Request.Body).ReadToEndAsync(); - Pins pinJson = JsonSerializer.Deserialize(pinsString); - + 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/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/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 }