From 219e02d6cb679b3c7cf5ea711ec92b2b16c6cd16 Mon Sep 17 00:00:00 2001 From: jvyden Date: Mon, 31 Jan 2022 23:47:48 -0500 Subject: [PATCH] Add simple api --- .../Controllers/Api/GetSlotEndpoint.cs | 27 ++++++++++++++++ .../Controllers/Api/GetSlotsEndpoint.cs | 32 +++++++++++++++++++ .../Controllers/Api/GetUserEndpoint.cs | 26 +++++++++++++++ .../Controllers/Api/StatisticsEndpoint.cs | 24 ++++++++++++++ .../GameApi/Slots/SlotsController.cs | 2 +- .../GameApi/StatisticsController.cs | 2 +- ProjectLighthouse/Helpers/StatisticsHelper.cs | 2 +- .../Types/Api/StatisticsResponse.cs | 10 ++++++ ProjectLighthouse/Types/ApiEndpoint.cs | 9 ++++++ ProjectLighthouse/Types/Levels/MinimalSlot.cs | 26 +++++++++++++++ ProjectLighthouse/Types/Levels/Slot.cs | 26 +++++++++++++++ ProjectLighthouse/Types/User.cs | 27 ++++++++++++++++ 12 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 ProjectLighthouse/Controllers/Api/GetSlotEndpoint.cs create mode 100644 ProjectLighthouse/Controllers/Api/GetSlotsEndpoint.cs create mode 100644 ProjectLighthouse/Controllers/Api/GetUserEndpoint.cs create mode 100644 ProjectLighthouse/Controllers/Api/StatisticsEndpoint.cs create mode 100644 ProjectLighthouse/Types/Api/StatisticsResponse.cs create mode 100644 ProjectLighthouse/Types/ApiEndpoint.cs create mode 100644 ProjectLighthouse/Types/Levels/MinimalSlot.cs diff --git a/ProjectLighthouse/Controllers/Api/GetSlotEndpoint.cs b/ProjectLighthouse/Controllers/Api/GetSlotEndpoint.cs new file mode 100644 index 00000000..395ccce9 --- /dev/null +++ b/ProjectLighthouse/Controllers/Api/GetSlotEndpoint.cs @@ -0,0 +1,27 @@ +#nullable enable +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Types; +using LBPUnion.ProjectLighthouse.Types.Levels; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Controllers.Api; + +public class GetSlotEndpoint : ApiEndpoint +{ + private readonly Database database; + + public GetSlotEndpoint(Database database) + { + this.database = database; + } + + [HttpGet("slot/{id:int}")] + public async Task OnGet(int id) + { + Slot? slot = await this.database.Slots.FirstOrDefaultAsync(u => u.SlotId == id); + if (slot == null) return this.NotFound(); + + return this.Ok(slot); + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/Api/GetSlotsEndpoint.cs b/ProjectLighthouse/Controllers/Api/GetSlotsEndpoint.cs new file mode 100644 index 00000000..f1ed2b55 --- /dev/null +++ b/ProjectLighthouse/Controllers/Api/GetSlotsEndpoint.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Types; +using LBPUnion.ProjectLighthouse.Types.Levels; +using LBPUnion.ProjectLighthouse.Types.Settings; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Controllers.Api; + +public class GetSlotsEndpoint : ApiEndpoint +{ + private readonly Database database; + + public GetSlotsEndpoint(Database database) + { + this.database = database; + } + + [HttpGet("slots")] + public async Task OnGet([FromQuery] int limit = 20, [FromQuery] int skip = 0) + { + limit = Math.Min(ServerStatics.PageSize, limit); + + IEnumerable minimalSlots = (await this.database.Slots.OrderByDescending(s => s.FirstUploaded).Skip(skip).Take(limit).ToListAsync()).Select + (MinimalSlot.FromSlot); + + return this.Ok(minimalSlots); + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/Api/GetUserEndpoint.cs b/ProjectLighthouse/Controllers/Api/GetUserEndpoint.cs new file mode 100644 index 00000000..40291cac --- /dev/null +++ b/ProjectLighthouse/Controllers/Api/GetUserEndpoint.cs @@ -0,0 +1,26 @@ +#nullable enable +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Types; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace LBPUnion.ProjectLighthouse.Controllers.Api; + +public class GetUserEndpoint : ApiEndpoint +{ + private readonly Database database; + + public GetUserEndpoint(Database database) + { + this.database = database; + } + + [HttpGet("user/{id:int}")] + public async Task OnGet(int id) + { + User? user = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id); + if (user == null) return this.NotFound(); + + return this.Ok(user); + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/Api/StatisticsEndpoint.cs b/ProjectLighthouse/Controllers/Api/StatisticsEndpoint.cs new file mode 100644 index 00000000..7ca24c7e --- /dev/null +++ b/ProjectLighthouse/Controllers/Api/StatisticsEndpoint.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Helpers; +using LBPUnion.ProjectLighthouse.Types; +using LBPUnion.ProjectLighthouse.Types.Api; +using Microsoft.AspNetCore.Mvc; + +namespace LBPUnion.ProjectLighthouse.Controllers.Api; + +public class StatisticsEndpoint : ApiEndpoint +{ + [HttpGet("statistics")] + public async Task OnGet() + => this.Ok + ( + new StatisticsResponse + { + Photos = await StatisticsHelper.PhotoCount(), + Slots = await StatisticsHelper.SlotCount(), + Users = await StatisticsHelper.UserCount(), + RecentMatches = await StatisticsHelper.RecentMatches(), + TeamPicks = await StatisticsHelper.TeamPickCount(), + } + ); +} \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/GameApi/Slots/SlotsController.cs b/ProjectLighthouse/Controllers/GameApi/Slots/SlotsController.cs index 539b4282..25038f69 100644 --- a/ProjectLighthouse/Controllers/GameApi/Slots/SlotsController.cs +++ b/ProjectLighthouse/Controllers/GameApi/Slots/SlotsController.cs @@ -177,7 +177,7 @@ public class SlotsController : ControllerBase "hint_start", pageStart + Math.Min(pageSize, ServerSettings.Instance.EntitledSlots) }, { - "total", await StatisticsHelper.MMPicksCount() + "total", await StatisticsHelper.TeamPickCount() }, } ) diff --git a/ProjectLighthouse/Controllers/GameApi/StatisticsController.cs b/ProjectLighthouse/Controllers/GameApi/StatisticsController.cs index c0686443..47d4b4f0 100644 --- a/ProjectLighthouse/Controllers/GameApi/StatisticsController.cs +++ b/ProjectLighthouse/Controllers/GameApi/StatisticsController.cs @@ -24,7 +24,7 @@ public class StatisticsController : ControllerBase public async Task PlanetStats() { int totalSlotCount = await StatisticsHelper.SlotCount(); - int mmPicksCount = await StatisticsHelper.MMPicksCount(); + int mmPicksCount = await StatisticsHelper.TeamPickCount(); return this.Ok ( diff --git a/ProjectLighthouse/Helpers/StatisticsHelper.cs b/ProjectLighthouse/Helpers/StatisticsHelper.cs index a2a27d6a..7051fda0 100644 --- a/ProjectLighthouse/Helpers/StatisticsHelper.cs +++ b/ProjectLighthouse/Helpers/StatisticsHelper.cs @@ -14,7 +14,7 @@ public static class StatisticsHelper public static async Task UserCount() => await database.Users.CountAsync(u => !u.Banned); - public static async Task MMPicksCount() => await database.Slots.CountAsync(s => s.TeamPick); + public static async Task TeamPickCount() => await database.Slots.CountAsync(s => s.TeamPick); public static async Task PhotoCount() => await database.Photos.CountAsync(); } \ No newline at end of file diff --git a/ProjectLighthouse/Types/Api/StatisticsResponse.cs b/ProjectLighthouse/Types/Api/StatisticsResponse.cs new file mode 100644 index 00000000..79f443f7 --- /dev/null +++ b/ProjectLighthouse/Types/Api/StatisticsResponse.cs @@ -0,0 +1,10 @@ +namespace LBPUnion.ProjectLighthouse.Types.Api; + +public class StatisticsResponse +{ + public int RecentMatches { get; set; } + public int Slots { get; set; } + public int Users { get; set; } + public int TeamPicks { get; set; } + public int Photos { get; set; } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/ApiEndpoint.cs b/ProjectLighthouse/Types/ApiEndpoint.cs new file mode 100644 index 00000000..ced32880 --- /dev/null +++ b/ProjectLighthouse/Types/ApiEndpoint.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Mvc; + +namespace LBPUnion.ProjectLighthouse.Types; + +[ApiController] +[Route("/api/v1/")] +[Produces("application/json")] +public class ApiEndpoint : ControllerBase +{} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Levels/MinimalSlot.cs b/ProjectLighthouse/Types/Levels/MinimalSlot.cs new file mode 100644 index 00000000..4778389f --- /dev/null +++ b/ProjectLighthouse/Types/Levels/MinimalSlot.cs @@ -0,0 +1,26 @@ +namespace LBPUnion.ProjectLighthouse.Types.Levels; + +public struct MinimalSlot +{ + public int SlotId { get; set; } + public string Name { get; set; } + public string IconHash { get; set; } + public bool TeamPick { get; set; } + public GameVersion GameVersion { get; set; } + #if DEBUG + public long FirstUploaded { get; set; } + #endif + + public static MinimalSlot FromSlot(Slot slot) + => new() + { + SlotId = slot.SlotId, + Name = slot.Name, + IconHash = slot.IconHash, + TeamPick = slot.TeamPick, + GameVersion = slot.GameVersion, + #if DEBUG + FirstUploaded = slot.FirstUploaded, + #endif + }; +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Levels/Slot.cs b/ProjectLighthouse/Types/Levels/Slot.cs index b768593a..425b8668 100644 --- a/ProjectLighthouse/Types/Levels/Slot.cs +++ b/ProjectLighthouse/Types/Levels/Slot.cs @@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using System.Text.Json.Serialization; using System.Xml.Serialization; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Serialization; @@ -19,6 +20,7 @@ public class Slot { [XmlAttribute("type")] [NotMapped] + [JsonIgnore] public string Type { get; set; } = "user"; [Key] @@ -35,24 +37,29 @@ public class Slot public string IconHash { get; set; } = ""; [XmlElement("rootLevel")] + [JsonIgnore] public string RootLevel { get; set; } = ""; + [JsonIgnore] public string ResourceCollection { get; set; } = ""; [NotMapped] [XmlElement("resource")] + [JsonIgnore] public string[] Resources { get => this.ResourceCollection.Split(","); set => this.ResourceCollection = string.Join(',', value); } [XmlIgnore] + [JsonIgnore] public int LocationId { get; set; } [XmlIgnore] public int CreatorId { get; set; } [ForeignKey(nameof(CreatorId))] + [JsonIgnore] public User? Creator { get; set; } /// @@ -60,6 +67,7 @@ public class Slot /// [XmlElement("location")] [ForeignKey(nameof(LocationId))] + [JsonIgnore] public Location? Location { get; set; } [XmlElement("initiallyLocked")] @@ -78,6 +86,7 @@ public class Slot public string AuthorLabels { get; set; } = ""; [XmlElement("background")] + [JsonIgnore] public string BackgroundHash { get; set; } = ""; [XmlElement("minPlayers")] @@ -103,6 +112,7 @@ public class Slot [XmlIgnore] [NotMapped] + [JsonIgnore] public int Hearts { get { using Database database = new(); @@ -124,42 +134,55 @@ public class Slot public int PlaysComplete => this.PlaysLBP1Complete + this.PlaysLBP2Complete + this.PlaysLBP3Complete + this.PlaysLBPVitaComplete; [XmlIgnore] + [JsonIgnore] public int PlaysLBP1 { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBP1Complete { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBP1Unique { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBP2 { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBP2Complete { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBP2Unique { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBP3 { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBP3Complete { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBP3Unique { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBPVita { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBPVitaComplete { get; set; } [XmlIgnore] + [JsonIgnore] public int PlaysLBPVitaUnique { get; set; } [NotMapped] + [JsonIgnore] [XmlElement("thumbsup")] public int Thumbsup { get { @@ -170,6 +193,7 @@ public class Slot } [NotMapped] + [JsonIgnore] [XmlElement("thumbsdown")] public int Thumbsdown { get { @@ -180,6 +204,7 @@ public class Slot } [NotMapped] + [JsonPropertyName("averageRating")] [XmlElement("averageRating")] public double RatingLBP1 { get { @@ -193,6 +218,7 @@ public class Slot } [NotMapped] + [JsonIgnore] [XmlElement("reviewCount")] public int ReviewCount { get { diff --git a/ProjectLighthouse/Types/User.cs b/ProjectLighthouse/Types/User.cs index 42eae3ff..14436ebb 100644 --- a/ProjectLighthouse/Types/User.cs +++ b/ProjectLighthouse/Types/User.cs @@ -1,6 +1,7 @@ using System.ComponentModel.DataAnnotations.Schema; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Text.Json.Serialization; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Serialization; using LBPUnion.ProjectLighthouse.Types.Profiles; @@ -13,11 +14,17 @@ public class User public readonly ClientsConnected ClientsConnected = new(); public int UserId { get; set; } public string Username { get; set; } + + [JsonIgnore] public string Password { get; set; } + public string IconHash { get; set; } + + [JsonIgnore] public int Game { get; set; } [NotMapped] + [JsonIgnore] public int Lists => 0; /// @@ -26,6 +33,7 @@ public class User public string Biography { get; set; } [NotMapped] + [JsonIgnore] public string WebsiteAvatarHash { get { string avatarHash = this.IconHash; @@ -40,6 +48,7 @@ public class User } [NotMapped] + [JsonIgnore] public int Reviews { get { using Database database = new(); @@ -48,6 +57,7 @@ public class User } [NotMapped] + [JsonIgnore] public int Comments { get { using Database database = new(); @@ -56,6 +66,7 @@ public class User } [NotMapped] + [JsonIgnore] public int PhotosByMe { get { using Database database = new(); @@ -64,6 +75,7 @@ public class User } [NotMapped] + [JsonIgnore] public int PhotosWithMe { get { using Database database = new(); @@ -71,15 +83,18 @@ public class User } } + [JsonIgnore] public int LocationId { get; set; } /// /// The location of the profile card on the user's earth /// [ForeignKey("LocationId")] + [JsonIgnore] public Location Location { get; set; } [NotMapped] + [JsonIgnore] public int HeartedLevels { get { using Database database = new(); @@ -88,6 +103,7 @@ public class User } [NotMapped] + [JsonIgnore] public int HeartedUsers { get { using Database database = new(); @@ -96,6 +112,7 @@ public class User } [NotMapped] + [JsonIgnore] public int QueuedLevels { get { using Database database = new(); @@ -103,10 +120,13 @@ public class User } } + [JsonIgnore] public string Pins { get; set; } = ""; + [JsonIgnore] public string PlanetHash { get; set; } = ""; + [JsonIgnore] public int Hearts { get { using Database database = new(); @@ -115,8 +135,10 @@ public class User } } + [JsonIgnore] public bool IsAdmin { get; set; } = false; + [JsonIgnore] public bool PasswordResetRequired { get; set; } public string YayHash { get; set; } = ""; @@ -125,6 +147,7 @@ public class User #nullable enable [NotMapped] + [JsonIgnore] public string Status { get { using Database database = new(); @@ -139,8 +162,10 @@ public class User } #nullable disable + [JsonIgnore] public bool Banned { get; set; } + [JsonIgnore] public string BannedReason { get; set; } public string Serialize(GameVersion gameVersion = GameVersion.LittleBigPlanet1) @@ -178,6 +203,7 @@ public class User /// The number of used slots on the earth /// [NotMapped] + [JsonIgnore] public int UsedSlots { get { using Database database = new(); @@ -194,6 +220,7 @@ public class User /// /// The number of slots remaining on the earth /// + [JsonIgnore] public int FreeSlots => ServerSettings.Instance.EntitledSlots - this.UsedSlots; private static readonly string[] slotTypes =