From d46432919340e4cac8f4d2d3d0061372ca5f39b1 Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Wed, 17 Nov 2021 20:50:44 -0500 Subject: [PATCH 01/11] Fix a bunch of warnings --- .gitignore | 2 ++ .../Controllers/EnterLevelController.cs | 6 ++++-- .../Controllers/ListController.cs | 12 ++++++------ .../Controllers/PhotosController.cs | 4 ++-- .../Controllers/ScoreController.cs | 6 +++--- .../Controllers/SlotsController.cs | 3 ++- .../Controllers/UserController.cs | 19 ++++++++++--------- 7 files changed, 29 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 1c626784..1f63e982 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,5 @@ riderModule.iml /ProjectLighthouse/logs/* /ProjectLighthouse/ProjectLighthouse.csproj.user .vs/ +.vscode/ +.editorconfig \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/EnterLevelController.cs b/ProjectLighthouse/Controllers/EnterLevelController.cs index 1e409bd3..cebca719 100644 --- a/ProjectLighthouse/Controllers/EnterLevelController.cs +++ b/ProjectLighthouse/Controllers/EnterLevelController.cs @@ -35,7 +35,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) @@ -61,6 +61,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers { v = await visited.FirstOrDefaultAsync(); } + if (v == null) return this.StatusCode(403, ""); switch (gameVersion) { @@ -95,7 +96,7 @@ 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++; @@ -109,6 +110,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers { v = await visited.FirstOrDefaultAsync(); } + if (v == null) return StatusCode(403, ""); slot.PlaysLBP1++; v.PlaysLBP1++; diff --git a/ProjectLighthouse/Controllers/ListController.cs b/ProjectLighthouse/Controllers/ListController.cs index fffda451..71ab40e1 100644 --- a/ProjectLighthouse/Controllers/ListController.cs +++ b/ProjectLighthouse/Controllers/ListController.cs @@ -55,7 +55,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 +78,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(); @@ -119,7 +119,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 +142,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(); @@ -185,7 +185,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 +212,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); diff --git a/ProjectLighthouse/Controllers/PhotosController.cs b/ProjectLighthouse/Controllers/PhotosController.cs index c853aedf..3f224432 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 (user == null || 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 (user == null || userFromQuery == null) return this.NotFound(); List photos = new(); foreach (Photo photo in this.database.Photos.Include(p => p.Creator)) diff --git a/ProjectLighthouse/Controllers/ScoreController.cs b/ProjectLighthouse/Controllers/ScoreController.cs index 05019a1f..283dc0b9 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,10 @@ 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) + 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 5b536306..802bb0c5 100644 --- a/ProjectLighthouse/Controllers/SlotsController.cs +++ b/ProjectLighthouse/Controllers/SlotsController.cs @@ -31,7 +31,8 @@ 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 StatusCode(403, ""); string response = Enumerable.Aggregate ( diff --git a/ProjectLighthouse/Controllers/UserController.cs b/ProjectLighthouse/Controllers/UserController.cs index d3f07198..2fd3efe2 100644 --- a/ProjectLighthouse/Controllers/UserController.cs +++ b/ProjectLighthouse/Controllers/UserController.cs @@ -30,7 +30,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers { User? user = await this.database.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.Username == username); - return user?.Serialize(gameVersion); + if (user == null) return ""; + return user.Serialize(gameVersion); } [HttpGet("user/{username}")] @@ -40,7 +41,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers if (token == null) return this.StatusCode(403, ""); string? user = await this.GetSerializedUser(username, token.GameVersion); - if (user == null) return this.NotFound(); + if (user == "") return this.NotFound(); return this.Ok(user); } @@ -54,7 +55,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers List serializedUsers = new(); foreach (string userId in u) { - serializedUsers.Add(await this.GetSerializedUser(userId, token.GameVersion)); + 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); @@ -68,8 +70,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,8 +145,8 @@ 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.Where(l => l.Id == user.LocationId).FirstOrDefaultAsync(); // find the location in the database again + if (l == null) return this.StatusCode(403, ""); // set the location in the database to the one we modified above l.X = user.Location.X; l.Y = user.Location.Y; @@ -160,11 +161,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(); From fde5505b5feca20572588a9b44d9afb756204eb2 Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Fri, 19 Nov 2021 21:47:08 -0500 Subject: [PATCH 02/11] Add basic level review support --- .../Controllers/ReviewController.cs | 179 ++++++++++++++++++ .../Controllers/SlotsController.cs | 4 +- ProjectLighthouse/Database.cs | 3 + ProjectLighthouse/Types/Levels/Slot.cs | 22 ++- .../Types/Reviews/RatedReview.cs | 24 +++ ProjectLighthouse/Types/Reviews/Review.cs | 101 ++++++++++ ProjectLighthouse/Types/User.cs | 13 +- 7 files changed, 337 insertions(+), 9 deletions(-) create mode 100644 ProjectLighthouse/Types/Reviews/RatedReview.cs create mode 100644 ProjectLighthouse/Types/Reviews/Review.cs diff --git a/ProjectLighthouse/Controllers/ReviewController.cs b/ProjectLighthouse/Controllers/ReviewController.cs index c50435af..dc04da77 100644 --- a/ProjectLighthouse/Controllers/ReviewController.cs +++ b/ProjectLighthouse/Controllers/ReviewController.cs @@ -1,8 +1,15 @@ #nullable enable using System; +using System.IO; +using System.Xml.Serialization; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types.Levels; +using LBPUnion.ProjectLighthouse.Types.Reviews; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -74,5 +81,177 @@ namespace LBPUnion.ProjectLighthouse.Controllers return this.Ok(); } + [HttpPost("postReview/user/{slotId:int}")] + public async Task PostReview(int slotId) { + User? user = await this.database.UserFromRequest(this.Request); + if (user == null) return this.StatusCode(403, ""); + + Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == user.UserId); + Review? newReview = await this.GetReviewFromBody(); + if (newReview == null) return this.BadRequest(); + if (review == null) { + review = new(); + review.SlotId = slotId; + review.ReviewerId = user.UserId; + review.DeletedBy = "none"; + + } + review.LabelCollection = newReview.LabelCollection; + review.Text = newReview.Text; + review.Deleted = false; + review.Timestamp = TimeHelper.UnixTimeMilliseconds(); + + // sometimes the game posts a review without also calling dpadrate/user/etc (why??) + RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == user.UserId); + if (ratedLevel == null) + { + ratedLevel = new RatedLevel(); + ratedLevel.SlotId = slotId; + ratedLevel.UserId = user.UserId; + ratedLevel.RatingLBP1 = 0; + this.database.RatedLevels.Add(ratedLevel); + } + + ratedLevel.Rating = newReview.Thumb; + + + await this.database.SaveChangesAsync(); + + return this.Ok(); + } + + [HttpGet("reviewsFor/user/{slotId:int}")] + public async Task ReviewsFor(int slotId, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10) + { + User? user = await this.database.UserFromRequest(this.Request); + if (user == null) return this.StatusCode(403, ""); + + Token? token = await this.database.TokenFromRequest(this.Request); + if (token == null) return this.StatusCode(403, ""); + + GameVersion gameVersion = token.GameVersion; + + Random rand = new(); + + IEnumerable reviews = this.database.Reviews.Where(r => r.SlotId == slotId && r.Slot.GameVersion <= gameVersion) + .Include(r => r.Reviewer) + .Include(r => r.Slot) + .AsEnumerable() // performance? Needed for next line (ThumbsUp is not in DB) + .OrderByDescending(r => r.ThumbsUp) + .ThenByDescending(_ => rand.Next()) + .Skip(pageStart - 1) + .Take(pageSize); + + string inner = Enumerable.Aggregate(reviews, string.Empty, (current, review) => { + RatedLevel? ratedLevel = this.database.RatedLevels.FirstOrDefault(r => r.SlotId == slotId && r.UserId == review.ReviewerId); + RatedReview? ratedReview = this.database.RatedReviews.FirstOrDefault(r => r.ReviewId == review.ReviewId && r.UserId == user.UserId); + + return current + review.Serialize(ratedLevel, ratedReview); + }); + + string response = LbpSerializer.TaggedStringElement("reviews", inner, new Dictionary + { + { + "hint_start", pageStart + pageSize + }, + { + "hint", pageStart // not sure + }, + }); + return this.Ok(response); + } + + [HttpGet("reviewsBy/{username}")] + public async Task ReviewsBy(string username, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10) + { + User? user = await this.database.UserFromRequest(this.Request); + if (user == null) return this.StatusCode(403, ""); + + Token? token = await this.database.TokenFromRequest(this.Request); + if (token == null) return this.StatusCode(403, ""); + + GameVersion gameVersion = token.GameVersion; + + IEnumerable reviews = this.database.Reviews.Where(r => r.Reviewer.Username == username && r.Slot.GameVersion <= gameVersion) + .Include(r => r.Reviewer) + .Include(r => r.Slot) + .AsEnumerable() // performance? + .OrderByDescending(r => r.Timestamp) + .Skip(pageStart - 1) + .Take(pageSize); + + string inner = Enumerable.Aggregate(reviews, string.Empty, (current, review) => { + RatedLevel? ratedLevel = this.database.RatedLevels.FirstOrDefault(r => r.SlotId == review.SlotId && r.UserId == user.UserId); + RatedReview? ratedReview = this.database.RatedReviews.FirstOrDefault(r => r.ReviewId == review.ReviewId && r.UserId == user.UserId); + return current + review.Serialize(ratedLevel, ratedReview); + }); + + string response = LbpSerializer.TaggedStringElement("reviews", inner, new Dictionary + { + { + "hint_start", pageStart + }, + { + "hint", reviews.Last().Timestamp // Seems to be the timestamp of oldest + }, + }); + + return this.Ok(response); + } + + [HttpPost("rateReview/user/{slotId:int}/{username}")] + public async Task RateReview(int slotId, string username, [FromQuery] int rating = 0) { + User? user = await this.database.UserFromRequest(this.Request); + if (user == null) return this.StatusCode(403, ""); + + User? reviewer = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); + if (reviewer == null) return this.StatusCode(403, ""); + + Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == reviewer.UserId); + if (review == null) return this.StatusCode(403, ""); + + RatedReview? ratedReview = await this.database.RatedReviews.FirstOrDefaultAsync(r => r.ReviewId == review.ReviewId && r.UserId == user.UserId); + if (ratedReview == null) + { + ratedReview = new RatedReview(); + ratedReview.ReviewId = review.ReviewId; + ratedReview.UserId = user.UserId; + ratedReview.Thumb = 0; + this.database.RatedReviews.Add(ratedReview); + } + + ratedReview.Thumb = Math.Max(Math.Min(1, rating), -1); + + await this.database.SaveChangesAsync(); + + return this.Ok(); + } + + [HttpPost("deleteReview/user/{slotId:int}/{username}")] + public async Task DeleteReview(int slotId, string username) { + User? reviewer = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); + if (reviewer == null) return this.StatusCode(403, ""); + + Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == reviewer.UserId); + if (review == null) return this.StatusCode(403, ""); + + review.Deleted = true; + review.DeletedBy = "level_author"; // other value is "moderator" + + await this.database.SaveChangesAsync(); + return this.Ok(); + } + + public async Task GetReviewFromBody() + { + this.Request.Body.Position = 0; + string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); + + XmlSerializer serializer = new(typeof(Review)); + Review? review = (Review?)serializer.Deserialize(new StringReader(bodyString)); + + return review; + } + } } \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/SlotsController.cs b/ProjectLighthouse/Controllers/SlotsController.cs index 48e45184..f7cfe67e 100644 --- a/ProjectLighthouse/Controllers/SlotsController.cs +++ b/ProjectLighthouse/Controllers/SlotsController.cs @@ -7,6 +7,7 @@ using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Settings; +using LBPUnion.ProjectLighthouse.Types.Reviews; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -85,7 +86,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == id && r.UserId == user.UserId); VisitedLevel? visitedLevel = await this.database.VisitedLevels.FirstOrDefaultAsync(r => r.SlotId == id && r.UserId == user.UserId); - return this.Ok(slot.Serialize(ratedLevel, visitedLevel)); + Review? yourReview = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == id && r.ReviewerId == user.UserId); + return this.Ok(slot.Serialize(ratedLevel, visitedLevel, yourReview)); } [HttpGet("slots/lbp2cool")] diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index 20898272..0af44ada 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -7,6 +7,7 @@ using LBPUnion.ProjectLighthouse.Types; using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Profiles; using LBPUnion.ProjectLighthouse.Types.Settings; +using LBPUnion.ProjectLighthouse.Types.Reviews; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; @@ -28,6 +29,8 @@ namespace LBPUnion.ProjectLighthouse public DbSet LastMatches { get; set; } public DbSet VisitedLevels { get; set; } public DbSet RatedLevels { get; set; } + public DbSet Reviews { get; set; } + public DbSet RatedReviews { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(ServerSettings.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion); diff --git a/ProjectLighthouse/Types/Levels/Slot.cs b/ProjectLighthouse/Types/Levels/Slot.cs index f21c7240..dd117b12 100644 --- a/ProjectLighthouse/Types/Levels/Slot.cs +++ b/ProjectLighthouse/Types/Levels/Slot.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Xml.Serialization; using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Types.Profiles; +using LBPUnion.ProjectLighthouse.Types.Reviews; namespace LBPUnion.ProjectLighthouse.Types.Levels { @@ -193,12 +194,22 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels [XmlElement("leveltype")] public string LevelType { get; set; } = ""; + [NotMapped] + [XmlElement("reviewCount")] + public int ReviewCount { + get { + using Database database = new(); + + return database.Reviews.Count(r => r.SlotId == this.SlotId); + } + } + public string SerializeResources() { return this.Resources.Aggregate("", (current, resource) => current + LbpSerializer.StringElement("resource", resource)); } - public string Serialize(RatedLevel? yourRatingStats = null, VisitedLevel? yourVisitedStats = null) + public string Serialize(RatedLevel? yourRatingStats = null, VisitedLevel? yourVisitedStats = null, Review? yourReview = null) { string slotData = LbpSerializer.StringElement("name", this.Name) + @@ -246,9 +257,12 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels LbpSerializer.StringElement("yourLBP1PlayCount", yourVisitedStats?.PlaysLBP1) + LbpSerializer.StringElement("yourLBP2PlayCount", yourVisitedStats?.PlaysLBP2) + LbpSerializer.StringElement("yourLBP3PlayCount", yourVisitedStats?.PlaysLBP3) + - LbpSerializer.StringElement - ("yourLBPVitaPlayCount", yourVisitedStats?.PlaysLBPVita); // i doubt this is the right name but we'll go with it - + LbpSerializer.StringElement("yourLBPVitaPlayCount", yourVisitedStats?.PlaysLBPVita) + // i doubt this is the right name but we'll go with it + yourReview?.Serialize("yourReview") + + LbpSerializer.StringElement("reviewsEnabled", true) + + LbpSerializer.StringElement("commentsEnabled", false) + + LbpSerializer.StringElement("reviewCount", this.ReviewCount); + return LbpSerializer.TaggedStringElement("slot", slotData, "type", "user"); } } diff --git a/ProjectLighthouse/Types/Reviews/RatedReview.cs b/ProjectLighthouse/Types/Reviews/RatedReview.cs new file mode 100644 index 00000000..1ba9720f --- /dev/null +++ b/ProjectLighthouse/Types/Reviews/RatedReview.cs @@ -0,0 +1,24 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace LBPUnion.ProjectLighthouse.Types.Reviews +{ + public class RatedReview + { + // ReSharper disable once UnusedMember.Global + [Key] + public int RatedReviewId { get; set; } + + public int UserId { get; set; } + + [ForeignKey(nameof(UserId))] + public User User { get; set; } + + public int ReviewId { get; set; } + + [ForeignKey(nameof(ReviewId))] + public Review Review { get; set; } + + public int Thumb { get; set; } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Reviews/Review.cs b/ProjectLighthouse/Types/Reviews/Review.cs new file mode 100644 index 00000000..a2ee79d0 --- /dev/null +++ b/ProjectLighthouse/Types/Reviews/Review.cs @@ -0,0 +1,101 @@ +#nullable enable +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using LBPUnion.ProjectLighthouse.Types.Levels; +using LBPUnion.ProjectLighthouse.Serialization; +using System.Xml.Serialization; + +namespace LBPUnion.ProjectLighthouse.Types.Reviews +{ + [XmlRoot("review")] + [XmlType("review")] + public class Review + { + // ReSharper disable once UnusedMember.Global + [Key] + public int ReviewId { get; set; } + + [XmlIgnore] + public int ReviewerId { get; set; } + + [ForeignKey(nameof(ReviewerId))] + public User Reviewer { get; set; } + + [XmlElement("slot_id")] + public int SlotId { get; set; } + + [ForeignKey(nameof(SlotId))] + public Slot Slot { get; set; } + + [XmlElement("timestamp")] + public long Timestamp { get; set; } + + [XmlElement("labels")] + public string LabelCollection { get; set; } + + [NotMapped] + [XmlIgnore] + public string[] Labels { + get => this.LabelCollection.Split(","); + set => this.LabelCollection = string.Join(',', value); + } + + [XmlElement("deleted")] + public Boolean Deleted { get; set; } + + [XmlElement("deleted_by")] + public string DeletedBy { get; set; } // enum ? Needs testing e.g. Moderated/Author/Level Author? etc. + + [XmlElement("text")] + public string Text { get; set; } + + [NotMapped] + [XmlElement("thumb")] + public int Thumb { get; set; } // (unused) -- temp value for getting thumb from review upload body for updating level rating + + [NotMapped] + [XmlElement("thumbsup")] + public int ThumbsUp { + get { + using Database database = new(); + + return database.RatedReviews.Count(r => r.ReviewId == this.ReviewId && r.Thumb == 1); + } + } + [NotMapped] + [XmlElement("thumbsdown")] + public int ThumbsDown { + get { + using Database database = new(); + + return database.RatedReviews.Count(r => r.ReviewId == this.ReviewId && r.Thumb == -1); + } + } + + public string Serialize(RatedLevel? yourLevelRating = null, RatedReview? yourRatingStats = null) { + return this.Serialize("review", yourLevelRating, yourRatingStats); + } + + public string Serialize(string elementOverride, RatedLevel? yourLevelRating = null, RatedReview? yourRatingStats = null) + { + + string reviewData = LbpSerializer.TaggedStringElement("slot_id", this.SlotId, "type", this.Slot.Type) + + LbpSerializer.StringElement("reviewer", this.Reviewer.Username) + + LbpSerializer.StringElement("thumb", yourLevelRating?.Rating) + + LbpSerializer.StringElement("timestamp", this.Timestamp) + + LbpSerializer.StringElement("labels", this.LabelCollection) + + LbpSerializer.StringElement("deleted", this.Deleted) + + LbpSerializer.StringElement("deleted_by", this.DeletedBy) + + LbpSerializer.StringElement("text", this.Text) + + LbpSerializer.StringElement("thumbsup", this.ThumbsUp) + + LbpSerializer.StringElement("thumbsdown", this.ThumbsDown) + + LbpSerializer.StringElement("yourthumb", yourRatingStats?.Thumb == null ? 0 : yourRatingStats?.Thumb); + + return LbpSerializer.TaggedStringElement(elementOverride, reviewData, "id", this.SlotId + "." + this.Reviewer.Username); + } + } + + +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/User.cs b/ProjectLighthouse/Types/User.cs index 83c0806a..3e87be8f 100644 --- a/ProjectLighthouse/Types/User.cs +++ b/ProjectLighthouse/Types/User.cs @@ -24,13 +24,18 @@ namespace LBPUnion.ProjectLighthouse.Types public string Biography { get; set; } [NotMapped] - public int Reviews => 0; + public int Reviews { + get { + using Database database = new(); + return database.Reviews.Count(r => r.ReviewerId == this.UserId); + } + } [NotMapped] public int Comments { get { using Database database = new(); - return database.Comments.Count(c => c.PosterUserId == this.UserId); + return database.Comments.Count(c => c.TargetUserId == this.UserId); } } @@ -114,8 +119,8 @@ namespace LBPUnion.ProjectLighthouse.Types LbpSerializer.StringElement("pins", this.Pins) + LbpSerializer.StringElement("planets", this.PlanetHash) + LbpSerializer.BlankElement("photos") + - LbpSerializer.StringElement("heartCount", this.Hearts); - this.ClientsConnected.Serialize(); + LbpSerializer.StringElement("heartCount", this.Hearts) + + this.ClientsConnected.Serialize(); return LbpSerializer.TaggedStringElement("user", user, "type", "user"); } From 5326ad4dea3951aa2f928975f747aa5031bb9899 Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Fri, 19 Nov 2021 21:47:32 -0500 Subject: [PATCH 03/11] Fix misleading variable name --- ProjectLighthouse/Controllers/UserController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProjectLighthouse/Controllers/UserController.cs b/ProjectLighthouse/Controllers/UserController.cs index 7e54b1ad..2e6fc452 100644 --- a/ProjectLighthouse/Controllers/UserController.cs +++ b/ProjectLighthouse/Controllers/UserController.cs @@ -52,9 +52,9 @@ namespace LBPUnion.ProjectLighthouse.Controllers if (token == null) return this.StatusCode(403, ""); List serializedUsers = new(); - foreach (string userId in u) + foreach (string username in u) { - string? serializedUser = await this.GetSerializedUser(userId, token.GameVersion); + string? serializedUser = await this.GetSerializedUser(username, token.GameVersion); if (serializedUser != "") serializedUsers.Add(serializedUser); } From 0ce784b4ecb106cbddb9fb7a7c22816bc500b905 Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Fri, 19 Nov 2021 23:35:11 -0500 Subject: [PATCH 04/11] DB Migrations --- .../20211120025513_LevelReviews.Designer.cs | 752 ++++++++++++++++++ .../Migrations/20211120025513_LevelReviews.cs | 105 +++ .../Migrations/DatabaseModelSnapshot.cs | 101 +++ 3 files changed, 958 insertions(+) create mode 100644 ProjectLighthouse/Migrations/20211120025513_LevelReviews.Designer.cs create mode 100644 ProjectLighthouse/Migrations/20211120025513_LevelReviews.cs diff --git a/ProjectLighthouse/Migrations/20211120025513_LevelReviews.Designer.cs b/ProjectLighthouse/Migrations/20211120025513_LevelReviews.Designer.cs new file mode 100644 index 00000000..64eaac27 --- /dev/null +++ b/ProjectLighthouse/Migrations/20211120025513_LevelReviews.Designer.cs @@ -0,0 +1,752 @@ +// +using LBPUnion.ProjectLighthouse; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + [DbContext(typeof(Database))] + [Migration("20211120025513_LevelReviews")] + partial class LevelReviews + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "6.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => + { + b.Property("HeartedProfileId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("HeartedUserId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedProfileId"); + + b.HasIndex("HeartedUserId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedProfiles"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b => + { + b.Property("HeartedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b => + { + b.Property("QueuedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("QueuedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("QueuedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b => + { + b.Property("RatedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("int"); + + b.Property("RatingLBP1") + .HasColumnType("double"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("RatedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("RatedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b => + { + b.Property("SlotId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("AuthorLabels") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("BackgroundHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FirstUploaded") + .HasColumnType("bigint"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("IconHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("InitiallyLocked") + .HasColumnType("tinyint(1)"); + + b.Property("LastUpdated") + .HasColumnType("bigint"); + + b.Property("Lbp1Only") + .HasColumnType("tinyint(1)"); + + b.Property("LevelType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("MaximumPlayers") + .HasColumnType("int"); + + b.Property("MinimumPlayers") + .HasColumnType("int"); + + b.Property("MoveRequired") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PlaysLBP1") + .HasColumnType("int"); + + b.Property("PlaysLBP1Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP1Unique") + .HasColumnType("int"); + + b.Property("PlaysLBP2") + .HasColumnType("int"); + + b.Property("PlaysLBP2Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP2Unique") + .HasColumnType("int"); + + b.Property("PlaysLBP3") + .HasColumnType("int"); + + b.Property("PlaysLBP3Complete") + .HasColumnType("int"); + + b.Property("PlaysLBP3Unique") + .HasColumnType("int"); + + b.Property("PlaysLBPVita") + .HasColumnType("int"); + + b.Property("PlaysLBPVitaComplete") + .HasColumnType("int"); + + b.Property("PlaysLBPVitaUnique") + .HasColumnType("int"); + + b.Property("ResourceCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("RootLevel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Shareable") + .HasColumnType("int"); + + b.Property("SubLevel") + .HasColumnType("tinyint(1)"); + + b.Property("TeamPick") + .HasColumnType("tinyint(1)"); + + b.HasKey("SlotId"); + + b.HasIndex("CreatorId"); + + b.HasIndex("LocationId"); + + b.ToTable("Slots"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b => + { + b.Property("VisitedLevelId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlaysLBP1") + .HasColumnType("int"); + + b.Property("PlaysLBP2") + .HasColumnType("int"); + + b.Property("PlaysLBP3") + .HasColumnType("int"); + + b.Property("PlaysLBPVita") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("VisitedLevelId"); + + b.HasIndex("SlotId"); + + b.HasIndex("UserId"); + + b.ToTable("VisitedLevels"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b => + { + b.Property("PhotoId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("LargeHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("MediumHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PhotoSubjectCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PlanHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SmallHash") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("PhotoId"); + + b.HasIndex("CreatorId"); + + b.ToTable("Photos"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b => + { + b.Property("PhotoSubjectId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Bounds") + .HasColumnType("longtext"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("PhotoSubjectId"); + + b.HasIndex("UserId"); + + b.ToTable("PhotoSubjects"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b => + { + b.Property("CommentId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Message") + .HasColumnType("longtext"); + + b.Property("PosterUserId") + .HasColumnType("int"); + + b.Property("TargetUserId") + .HasColumnType("int"); + + b.Property("ThumbsDown") + .HasColumnType("int"); + + b.Property("ThumbsUp") + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("CommentId"); + + b.HasIndex("PosterUserId"); + + b.HasIndex("TargetUserId"); + + b.ToTable("Comments"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("UserId"); + + b.ToTable("LastMatches"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("X") + .HasColumnType("int"); + + b.Property("Y") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Locations"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.RatedReview", b => + { + b.Property("RatedReviewId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ReviewId") + .HasColumnType("int"); + + b.Property("Thumb") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("RatedReviewId"); + + b.HasIndex("ReviewId"); + + b.HasIndex("UserId"); + + b.ToTable("RatedReviews"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.Review", b => + { + b.Property("ReviewId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Deleted") + .HasColumnType("tinyint(1)"); + + b.Property("DeletedBy") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LabelCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ReviewerId") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("ReviewId"); + + b.HasIndex("ReviewerId"); + + b.HasIndex("SlotId"); + + b.ToTable("Reviews"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => + { + b.Property("ScoreId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlayerIdCollection") + .HasColumnType("longtext"); + + b.Property("Points") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("Type") + .HasColumnType("int"); + + b.HasKey("ScoreId"); + + b.HasIndex("SlotId"); + + b.ToTable("Scores"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b => + { + b.Property("TokenId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("GameVersion") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.Property("UserLocation") + .HasColumnType("longtext"); + + b.Property("UserToken") + .HasColumnType("longtext"); + + b.HasKey("TokenId"); + + b.ToTable("Tokens"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Biography") + .HasColumnType("longtext"); + + b.Property("Game") + .HasColumnType("int"); + + b.Property("IconHash") + .HasColumnType("longtext"); + + b.Property("LocationId") + .HasColumnType("int"); + + b.Property("Pins") + .HasColumnType("longtext"); + + b.Property("PlanetHash") + .HasColumnType("longtext"); + + b.Property("Username") + .HasColumnType("longtext"); + + b.HasKey("UserId"); + + b.HasIndex("LocationId"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser") + .WithMany() + .HasForeignKey("HeartedUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("HeartedUser"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + + b.Navigation("Location"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster") + .WithMany() + .HasForeignKey("PosterUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target") + .WithMany() + .HasForeignKey("TargetUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Poster"); + + b.Navigation("Target"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.RatedReview", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Reviews.Review", "Review") + .WithMany() + .HasForeignKey("ReviewId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Review"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.Review", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Reviewer") + .WithMany() + .HasForeignKey("ReviewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reviewer"); + + b.Navigation("Slot"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Slot"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location") + .WithMany() + .HasForeignKey("LocationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Location"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ProjectLighthouse/Migrations/20211120025513_LevelReviews.cs b/ProjectLighthouse/Migrations/20211120025513_LevelReviews.cs new file mode 100644 index 00000000..07d2e4c5 --- /dev/null +++ b/ProjectLighthouse/Migrations/20211120025513_LevelReviews.cs @@ -0,0 +1,105 @@ +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + public partial class LevelReviews : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Reviews", + columns: table => new + { + ReviewId = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + ReviewerId = table.Column(type: "int", nullable: false), + SlotId = table.Column(type: "int", nullable: false), + Timestamp = table.Column(type: "bigint", nullable: false), + LabelCollection = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Deleted = table.Column(type: "tinyint(1)", nullable: false), + DeletedBy = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Text = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_Reviews", x => x.ReviewId); + table.ForeignKey( + name: "FK_Reviews_Slots_SlotId", + column: x => x.SlotId, + principalTable: "Slots", + principalColumn: "SlotId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_Reviews_Users_ReviewerId", + column: x => x.ReviewerId, + principalTable: "Users", + principalColumn: "UserId", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "RatedReviews", + columns: table => new + { + RatedReviewId = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + UserId = table.Column(type: "int", nullable: false), + ReviewId = table.Column(type: "int", nullable: false), + Thumb = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_RatedReviews", x => x.RatedReviewId); + table.ForeignKey( + name: "FK_RatedReviews_Reviews_ReviewId", + column: x => x.ReviewId, + principalTable: "Reviews", + principalColumn: "ReviewId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_RatedReviews_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "UserId", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_RatedReviews_ReviewId", + table: "RatedReviews", + column: "ReviewId"); + + migrationBuilder.CreateIndex( + name: "IX_RatedReviews_UserId", + table: "RatedReviews", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_Reviews_ReviewerId", + table: "Reviews", + column: "ReviewerId"); + + migrationBuilder.CreateIndex( + name: "IX_Reviews_SlotId", + table: "Reviews", + column: "SlotId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "RatedReviews"); + + migrationBuilder.DropTable( + name: "Reviews"); + } + } +} diff --git a/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs b/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs index 8f8c1454..a21d10d6 100644 --- a/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs +++ b/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs @@ -385,6 +385,69 @@ namespace ProjectLighthouse.Migrations b.ToTable("Locations"); }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.RatedReview", b => + { + b.Property("RatedReviewId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("ReviewId") + .HasColumnType("int"); + + b.Property("Thumb") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("RatedReviewId"); + + b.HasIndex("ReviewId"); + + b.HasIndex("UserId"); + + b.ToTable("RatedReviews"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.Review", b => + { + b.Property("ReviewId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("Deleted") + .HasColumnType("tinyint(1)"); + + b.Property("DeletedBy") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("LabelCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ReviewerId") + .HasColumnType("int"); + + b.Property("SlotId") + .HasColumnType("int"); + + b.Property("Text") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Timestamp") + .HasColumnType("bigint"); + + b.HasKey("ReviewId"); + + b.HasIndex("ReviewerId"); + + b.HasIndex("SlotId"); + + b.ToTable("Reviews"); + }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => { b.Property("ScoreId") @@ -622,6 +685,44 @@ namespace ProjectLighthouse.Migrations b.Navigation("Target"); }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.RatedReview", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.Reviews.Review", "Review") + .WithMany() + .HasForeignKey("ReviewId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Review"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Reviews.Review", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Reviewer") + .WithMany() + .HasForeignKey("ReviewerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") + .WithMany() + .HasForeignKey("SlotId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Reviewer"); + + b.Navigation("Slot"); + }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b => { b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot") From a7443c16a0e240b50b4026f98ad60d5e744fc6a5 Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Fri, 19 Nov 2021 23:38:22 -0500 Subject: [PATCH 05/11] Messed up merge conflict? Fixed --- .../Controllers/EnterLevelController.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/ProjectLighthouse/Controllers/EnterLevelController.cs b/ProjectLighthouse/Controllers/EnterLevelController.cs index d704cfcc..af799c02 100644 --- a/ProjectLighthouse/Controllers/EnterLevelController.cs +++ b/ProjectLighthouse/Controllers/EnterLevelController.cs @@ -62,12 +62,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers { v = await visited.FirstOrDefaultAsync(); } - if (v == null) return this.StatusCode(403, ""); - - if (v == null) - { - return this.NotFound(); - } + + if (v == null) return this.NotFound(); switch (gameVersion) { @@ -119,12 +115,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers { v = await visited.FirstOrDefaultAsync(); } - if (v == null) return StatusCode(403, ""); - if (v == null) - { - return this.NotFound(); - } + if (v == null) return this.NotFound(); slot.PlaysLBP1++; v.PlaysLBP1++; From abfb1c4cd86f0a222ad14f148d7a1e9931e83444 Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Sat, 20 Nov 2021 04:34:03 -0500 Subject: [PATCH 06/11] Remove pointless .asEnumerable() --- ProjectLighthouse/Controllers/ReviewController.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/ProjectLighthouse/Controllers/ReviewController.cs b/ProjectLighthouse/Controllers/ReviewController.cs index dc04da77..bea193d1 100644 --- a/ProjectLighthouse/Controllers/ReviewController.cs +++ b/ProjectLighthouse/Controllers/ReviewController.cs @@ -175,7 +175,6 @@ namespace LBPUnion.ProjectLighthouse.Controllers IEnumerable reviews = this.database.Reviews.Where(r => r.Reviewer.Username == username && r.Slot.GameVersion <= gameVersion) .Include(r => r.Reviewer) .Include(r => r.Slot) - .AsEnumerable() // performance? .OrderByDescending(r => r.Timestamp) .Skip(pageStart - 1) .Take(pageSize); From ed1eac696a11a3bfb2b477b0bfec4c153fcafecf Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Sat, 20 Nov 2021 04:37:11 -0500 Subject: [PATCH 07/11] Fix error codes 403->400 --- ProjectLighthouse/Controllers/ReviewController.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ProjectLighthouse/Controllers/ReviewController.cs b/ProjectLighthouse/Controllers/ReviewController.cs index bea193d1..4525a43d 100644 --- a/ProjectLighthouse/Controllers/ReviewController.cs +++ b/ProjectLighthouse/Controllers/ReviewController.cs @@ -204,10 +204,10 @@ namespace LBPUnion.ProjectLighthouse.Controllers if (user == null) return this.StatusCode(403, ""); User? reviewer = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); - if (reviewer == null) return this.StatusCode(403, ""); + if (reviewer == null) return this.StatusCode(400, ""); Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == reviewer.UserId); - if (review == null) return this.StatusCode(403, ""); + if (review == null) return this.StatusCode(400, ""); RatedReview? ratedReview = await this.database.RatedReviews.FirstOrDefaultAsync(r => r.ReviewId == review.ReviewId && r.UserId == user.UserId); if (ratedReview == null) From d36a7d576560517cecfc6260661c681a5caf82be Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Sat, 20 Nov 2021 04:39:53 -0500 Subject: [PATCH 08/11] Use better null/empty check --- ProjectLighthouse/Controllers/UserController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProjectLighthouse/Controllers/UserController.cs b/ProjectLighthouse/Controllers/UserController.cs index 2e6fc452..94a7da6a 100644 --- a/ProjectLighthouse/Controllers/UserController.cs +++ b/ProjectLighthouse/Controllers/UserController.cs @@ -40,7 +40,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers if (token == null) return this.StatusCode(403, ""); string? user = await this.GetSerializedUser(username, token.GameVersion); - if (user == "") return this.NotFound(); + if (string.IsNullOrEmpty(user)) return this.NotFound(); return this.Ok(user); } From ece00c218ede04b4226bf45bcc27fc4449c4e557 Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Sat, 20 Nov 2021 04:48:49 -0500 Subject: [PATCH 09/11] Create DeletedBy enum --- ProjectLighthouse/Controllers/ReviewController.cs | 2 +- ProjectLighthouse/Types/DeletedBy.cs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 ProjectLighthouse/Types/DeletedBy.cs diff --git a/ProjectLighthouse/Controllers/ReviewController.cs b/ProjectLighthouse/Controllers/ReviewController.cs index 4525a43d..690cdf2e 100644 --- a/ProjectLighthouse/Controllers/ReviewController.cs +++ b/ProjectLighthouse/Controllers/ReviewController.cs @@ -235,7 +235,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers if (review == null) return this.StatusCode(403, ""); review.Deleted = true; - review.DeletedBy = "level_author"; // other value is "moderator" + review.DeletedBy = DeletedBy.LevelAuthor; await this.database.SaveChangesAsync(); return this.Ok(); diff --git a/ProjectLighthouse/Types/DeletedBy.cs b/ProjectLighthouse/Types/DeletedBy.cs new file mode 100644 index 00000000..02d61ec0 --- /dev/null +++ b/ProjectLighthouse/Types/DeletedBy.cs @@ -0,0 +1,9 @@ +namespace LBPUnion.ProjectLighthouse.Types +{ + public static class DeletedBy + { + public static string Moderator { get => "moderator"; } + public static string LevelAuthor { get => "level_author"; } + // TODO: deletion types for comments (profile etc) + } +} \ No newline at end of file From 0353e0b889c5e2b46b128b633b1610aa902f06c7 Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Mon, 22 Nov 2021 19:46:39 -0500 Subject: [PATCH 10/11] catch all logs folders --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ff16b3ae..15bd2de8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ riderModule.iml /.idea/.idea.ProjectLighthouse/.idea/dataSources.local.xml *.sln.DotSettings.user /ProjectLighthouse/r/* -/ProjectLighthouse/logs/* +logs /ProjectLighthouse/ProjectLighthouse.csproj.user .vs/ .vscode/ From 61da2496c8e1c8af973358282296b19321b44cd4 Mon Sep 17 00:00:00 2001 From: LumaLivy <7350336+LumaLivy@users.noreply.github.com> Date: Mon, 29 Nov 2021 16:50:51 -0500 Subject: [PATCH 11/11] Patch compatibility with main --- .../Controllers/ReviewController.cs | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/ProjectLighthouse/Controllers/ReviewController.cs b/ProjectLighthouse/Controllers/ReviewController.cs index 54f15b15..35948771 100644 --- a/ProjectLighthouse/Controllers/ReviewController.cs +++ b/ProjectLighthouse/Controllers/ReviewController.cs @@ -82,25 +82,27 @@ namespace LBPUnion.ProjectLighthouse.Controllers } [HttpPost("postReview/user/{slotId:int}")] - public async Task PostReview(int slotId) { - User? user = await this.database.UserFromRequest(this.Request); + public async Task PostReview(int slotId) + { + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == user.UserId); Review? newReview = await this.GetReviewFromBody(); if (newReview == null) return this.BadRequest(); - if (review == null) { + if (review == null) + { review = new(); review.SlotId = slotId; review.ReviewerId = user.UserId; review.DeletedBy = "none"; - + } review.LabelCollection = newReview.LabelCollection; review.Text = newReview.Text; review.Deleted = false; review.Timestamp = TimeHelper.UnixTimeMilliseconds(); - + // sometimes the game posts a review without also calling dpadrate/user/etc (why??) RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == user.UserId); if (ratedLevel == null) @@ -113,7 +115,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers } ratedLevel.Rating = newReview.Thumb; - + await this.database.SaveChangesAsync(); @@ -121,15 +123,17 @@ namespace LBPUnion.ProjectLighthouse.Controllers } [HttpGet("reviewsFor/user/{slotId:int}")] - public async Task ReviewsFor(int slotId, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10) + public async Task ReviewsFor(int slotId, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10) { - User? user = await this.database.UserFromRequest(this.Request); - if (user == null) return this.StatusCode(403, ""); + (User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request); - Token? token = await this.database.TokenFromRequest(this.Request); - if (token == null) return this.StatusCode(403, ""); + if (userAndToken == null) return this.StatusCode(403, ""); - GameVersion gameVersion = token.GameVersion; + // ReSharper disable once PossibleInvalidOperationException + User user = userAndToken.Value.Item1; + GameToken gameToken = userAndToken.Value.Item2; + + GameVersion gameVersion = gameToken.GameVersion; Random rand = new(); @@ -141,11 +145,12 @@ namespace LBPUnion.ProjectLighthouse.Controllers .ThenByDescending(_ => rand.Next()) .Skip(pageStart - 1) .Take(pageSize); - - string inner = Enumerable.Aggregate(reviews, string.Empty, (current, review) => { + + string inner = Enumerable.Aggregate(reviews, string.Empty, (current, review) => + { RatedLevel? ratedLevel = this.database.RatedLevels.FirstOrDefault(r => r.SlotId == slotId && r.UserId == review.ReviewerId); RatedReview? ratedReview = this.database.RatedReviews.FirstOrDefault(r => r.ReviewId == review.ReviewId && r.UserId == user.UserId); - + return current + review.Serialize(ratedLevel, ratedReview); }); @@ -162,15 +167,17 @@ namespace LBPUnion.ProjectLighthouse.Controllers } [HttpGet("reviewsBy/{username}")] - public async Task ReviewsBy(string username, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10) + public async Task ReviewsBy(string username, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10) { - User? user = await this.database.UserFromRequest(this.Request); - if (user == null) return this.StatusCode(403, ""); + (User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request); - Token? token = await this.database.TokenFromRequest(this.Request); - if (token == null) return this.StatusCode(403, ""); + if (userAndToken == null) return this.StatusCode(403, ""); - GameVersion gameVersion = token.GameVersion; + // ReSharper disable once PossibleInvalidOperationException + User user = userAndToken.Value.Item1; + GameToken gameToken = userAndToken.Value.Item2; + + GameVersion gameVersion = gameToken.GameVersion; IEnumerable reviews = this.database.Reviews.Where(r => r.Reviewer.Username == username && r.Slot.GameVersion <= gameVersion) .Include(r => r.Reviewer) @@ -178,8 +185,9 @@ namespace LBPUnion.ProjectLighthouse.Controllers .OrderByDescending(r => r.Timestamp) .Skip(pageStart - 1) .Take(pageSize); - - string inner = Enumerable.Aggregate(reviews, string.Empty, (current, review) => { + + string inner = Enumerable.Aggregate(reviews, string.Empty, (current, review) => + { RatedLevel? ratedLevel = this.database.RatedLevels.FirstOrDefault(r => r.SlotId == review.SlotId && r.UserId == user.UserId); RatedReview? ratedReview = this.database.RatedReviews.FirstOrDefault(r => r.ReviewId == review.ReviewId && r.UserId == user.UserId); return current + review.Serialize(ratedLevel, ratedReview); @@ -199,8 +207,9 @@ namespace LBPUnion.ProjectLighthouse.Controllers } [HttpPost("rateReview/user/{slotId:int}/{username}")] - public async Task RateReview(int slotId, string username, [FromQuery] int rating = 0) { - User? user = await this.database.UserFromRequest(this.Request); + public async Task RateReview(int slotId, string username, [FromQuery] int rating = 0) + { + User? user = await this.database.UserFromGameRequest(this.Request); if (user == null) return this.StatusCode(403, ""); User? reviewer = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); @@ -227,7 +236,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers } [HttpPost("deleteReview/user/{slotId:int}/{username}")] - public async Task DeleteReview(int slotId, string username) { + public async Task DeleteReview(int slotId, string username) + { User? reviewer = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); if (reviewer == null) return this.StatusCode(403, "");