From 78faff36b560d1ebec399e2e163a27f334e7ddac Mon Sep 17 00:00:00 2001 From: Slendy Date: Thu, 15 Sep 2022 22:53:00 -0500 Subject: [PATCH 01/14] Initial support for lbp3 playlists Will add migration when user settings is merged --- .../Controllers/Slots/CollectionController.cs | 142 +++++++++++++++++- ProjectLighthouse/Levels/HeartedPlaylist.cs | 21 +++ ProjectLighthouse/Levels/Playlist.cs | 70 +++++++++ ProjectLighthouse/PlayerData/Profiles/User.cs | 9 +- 4 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 ProjectLighthouse/Levels/HeartedPlaylist.cs create mode 100644 ProjectLighthouse/Levels/Playlist.cs diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs index 504f8e80..9ea1e307 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs @@ -1,4 +1,7 @@ #nullable enable +using System.Xml.Schema; +using System.Xml.Serialization; +using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Helpers; using LBPUnion.ProjectLighthouse.Levels; using LBPUnion.ProjectLighthouse.Levels.Categories; @@ -6,8 +9,8 @@ using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.PlayerData; using LBPUnion.ProjectLighthouse.PlayerData.Profiles; using LBPUnion.ProjectLighthouse.Serialization; -using LBPUnion.ProjectLighthouse.Types; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots; @@ -23,8 +26,143 @@ public class CollectionController : ControllerBase this.database = database; } + + [HttpGet("playlists/{playlistId:int}/slots")] + public async Task GetPlaylistSlots(int playlistId) + { + GameToken? token = await this.database.GameTokenFromRequest(this.Request); + if (token == null) return this.StatusCode(403, ""); + + Playlist? targetPlaylist = await this.database.Playlists.FirstOrDefaultAsync(p => p.PlaylistId == playlistId); + if (targetPlaylist == null) return this.BadRequest(); + + IQueryable slots = this.database.Slots.Include(s => s.Creator) + .Include(s => s.Location) + .Where(s => targetPlaylist.SlotIds.Contains(s.SlotId)); + + string response = Enumerable.Aggregate(slots, string.Empty, (current, slot) => current + slot.Serialize()); + int total = targetPlaylist.SlotIds.Length; + + return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "total", total)); + } + + [HttpPost("playlists/{playlistId:int}")] + [HttpPost("playlists/{playlistId:int}/slots")] + [HttpPost("playlists/{playlistId:int}/slots/{slotId:int}/delete")] + [HttpPost("playlists/{playlistId:int}/order_slots")] + public async Task UpdatePlaylist(int playlistId, int slotId) + { + GameToken? token = await this.database.GameTokenFromRequest(this.Request); + if (token == null) return this.StatusCode(403, ""); + + Playlist? targetPlaylist = await this.database.Playlists.FirstOrDefaultAsync(p => p.PlaylistId == playlistId); + if (targetPlaylist == null) return this.BadRequest(); + + if (token.UserId != targetPlaylist.CreatorId) return this.BadRequest(); + + // Delete a slot from playlist + if (slotId != 0) + { + targetPlaylist.SlotIds = targetPlaylist.SlotIds.Where(s => s != slotId).ToArray(); + await this.database.SaveChangesAsync(); + return this.Ok(this.GetUserPlaylists(token.UserId)); + } + + this.Request.Body.Position = 0; + string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); + + + string rootElement = bodyString.Contains("levels") ? "levels" : "playlist"; // I hate lbp3 + XmlSerializer serializer = new(typeof(Playlist), new XmlRootAttribute(rootElement)); + Playlist? newPlaylist = (Playlist?)serializer.Deserialize(new StringReader(bodyString)); + + if (newPlaylist == null) return this.BadRequest(); + + if (newPlaylist.LevelIds != null) + { + HashSet slotIds = new(targetPlaylist.SlotIds); + + // Reorder + if (slotIds.SetEquals(newPlaylist.LevelIds)) + { + targetPlaylist.SlotIds = newPlaylist.LevelIds; + } + // Add a level + else + { + foreach (int id in newPlaylist.LevelIds) + { + targetPlaylist.SlotIds = targetPlaylist.SlotIds.Append(id).ToArray(); + } + } + } + + if (!string.IsNullOrWhiteSpace(newPlaylist.Name)) + { + targetPlaylist.Name = newPlaylist.Name; + } + + if (!string.IsNullOrWhiteSpace(newPlaylist.Description)) + { + targetPlaylist.Description = newPlaylist.Description; + } + + await this.database.SaveChangesAsync(); + + return this.Ok(this.GetUserPlaylists(token.UserId)); + } + + private string GetUserPlaylists(int userId) + { + string response = Enumerable.Aggregate( + this.database.Playlists.Include(p => p.Creator).Where(p => p.CreatorId == userId), + string.Empty, + (current, slot) => current + slot.Serialize()); + int total = this.database.Playlists.Count(p => p.CreatorId == userId); + + return LbpSerializer.TaggedStringElement("playlists", response, "total", total); + } + + [HttpPost("playlists")] + public async Task CreatePlaylist() + { + GameToken? token = await this.database.GameTokenFromRequest(this.Request); + if (token == null) return this.StatusCode(403, ""); + + int playlistCount = await this.database.Playlists.CountAsync(p => p.CreatorId == token.UserId); + + if (playlistCount > ServerConfiguration.Instance.UserGeneratedContentLimits.ListsQuota) return this.BadRequest(); + + this.Request.Body.Position = 0; + string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); + + XmlSerializer serializer = new(typeof(Playlist), new XmlRootAttribute("playlist")); + Playlist? playlist = (Playlist?)serializer.Deserialize(new StringReader(bodyString)); + + if (playlist == null) return this.BadRequest(); + + playlist.CreatorId = token.UserId; + + SanitizationHelper.SanitizeStringsInClass(playlist); + + this.database.Playlists.Add(playlist); + + await this.database.SaveChangesAsync(); + + return this.Ok(this.GetUserPlaylists(token.UserId)); + } + [HttpGet("user/{username}/playlists")] - public IActionResult GetUserPlaylists(string username) => this.Ok(""); + public async Task GetUserPlaylists(string username) + { + GameToken? token = await this.database.GameTokenFromRequest(this.Request); + if (token == null) return this.StatusCode(403, ""); + + int targetUserId = await this.database.Users.Where(u => u.Username == username).Select(u => u.UserId).FirstOrDefaultAsync(); + if (targetUserId == 0) return this.BadRequest(); + + return this.Ok(this.GetUserPlaylists(targetUserId)); + } [HttpGet("searches")] [HttpGet("genres")] diff --git a/ProjectLighthouse/Levels/HeartedPlaylist.cs b/ProjectLighthouse/Levels/HeartedPlaylist.cs new file mode 100644 index 00000000..f17e8c30 --- /dev/null +++ b/ProjectLighthouse/Levels/HeartedPlaylist.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using LBPUnion.ProjectLighthouse.PlayerData.Profiles; + +namespace LBPUnion.ProjectLighthouse.Levels; + +public class HeartedPlaylist +{ + [Key] + public int HeartedPlaylistId { get; set; } + + public int UserId { get; set; } + + [ForeignKey(nameof(UserId))] + public User User { get; set; } + + public int PlaylistId { get; set; } + + [ForeignKey(nameof(PlaylistId))] + public Playlist Playlist { get; set; } +} \ No newline at end of file diff --git a/ProjectLighthouse/Levels/Playlist.cs b/ProjectLighthouse/Levels/Playlist.cs new file mode 100644 index 00000000..4355afc2 --- /dev/null +++ b/ProjectLighthouse/Levels/Playlist.cs @@ -0,0 +1,70 @@ +#nullable enable +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text.Json.Serialization; +using System.Xml.Serialization; +using LBPUnion.ProjectLighthouse.Configuration; +using LBPUnion.ProjectLighthouse.PlayerData.Profiles; +using LBPUnion.ProjectLighthouse.Serialization; + +namespace LBPUnion.ProjectLighthouse.Levels; + +public class Playlist +{ + [Key] + public int PlaylistId { get; set; } + + [XmlElement("name")] + public string Name { get; set; } = ""; + + [XmlElement("description")] + public string Description { get; set; } = ""; + + public int CreatorId { get; set; } + + [ForeignKey(nameof(CreatorId))] + [JsonIgnore] + public User? Creator { get; set; } + + public string SlotCollection { get; set; } = ""; + + [JsonIgnore] + [NotMapped] + [XmlElement("level_id")] + public int[]? LevelIds { get; set; } + + [NotMapped] + public int[] SlotIds + { + get => this.SlotCollection.Split(",").Where(x => int.TryParse(x, out _)).Select(int.Parse).ToArray(); + set => this.SlotCollection = string.Join(",", value); + } + + public string Serialize() + { + using Database database = new(); + string playlist = LbpSerializer.StringElement("id", this.PlaylistId) + + LbpSerializer.StringElement("author", + LbpSerializer.StringElement("npHandle", this.Creator?.Username)) + + LbpSerializer.StringElement("name", this.Name) + + LbpSerializer.StringElement("description", this.Description) + + LbpSerializer.StringElement("levels", this.SlotIds.Length) + + LbpSerializer.StringElement("thumbs", 0) + + LbpSerializer.StringElement("plays", 0) + + LbpSerializer.StringElement("unique_plays", 0) + + LbpSerializer.StringElement("levels_quota", ServerConfiguration.Instance.UserGeneratedContentLimits.ListsQuota) + + this.SerializeIcons(database); + + return LbpSerializer.StringElement("playlist", playlist); + } + + private string SerializeIcons(Database database) + { + string iconList = this.SlotIds.Select(id => database.Slots.FirstOrDefault(s => s.SlotId == id)) + .Where(slot => slot != null) + .Aggregate(string.Empty, (current, slot) => current + LbpSerializer.StringElement("icon", slot?.IconHash)); + return LbpSerializer.StringElement("icons", iconList); + } + +} \ No newline at end of file diff --git a/ProjectLighthouse/PlayerData/Profiles/User.cs b/ProjectLighthouse/PlayerData/Profiles/User.cs index cfaaa6c3..259eb573 100644 --- a/ProjectLighthouse/PlayerData/Profiles/User.cs +++ b/ProjectLighthouse/PlayerData/Profiles/User.cs @@ -49,7 +49,7 @@ public class User [NotMapped] [JsonIgnore] - public int Lists => 0; + public int Lists => this.database.Playlists.Count(p => p.CreatorId == this.UserId); /// /// A user-customizable biography shown on the profile card @@ -183,6 +183,7 @@ public class User /// /// ARRR! Forces the user to see Pirate English translations on the website. /// + [NotMapped] public bool IsAPirate { get; set; } public PrivacyType LevelVisibility { get; set; } = PrivacyType.All; @@ -197,14 +198,14 @@ public class User string user = LbpSerializer.TaggedStringElement("npHandle", this.Username, "icon", this.IconHash) + LbpSerializer.StringElement("game", (int)gameVersion) + this.serializeSlots(gameVersion) + - LbpSerializer.StringElement("lists", this.Lists, true) + - LbpSerializer.StringElement + LbpSerializer.StringElement("lists", this.Lists, true) + + LbpSerializer.StringElement ( "lists_quota", ServerConfiguration.Instance.UserGeneratedContentLimits.ListsQuota, true ) + // technically not a part of the user but LBP expects it - LbpSerializer.StringElement("heartCount", this.Hearts, true) + + LbpSerializer.StringElement("heartCount", this.Hearts, true) + this.serializeEarth(gameVersion) + LbpSerializer.StringElement("yay2", this.YayHash, true) + LbpSerializer.StringElement("boo2", this.BooHash, true) + From 4483819bd7c4ef158e6a89766e1c702bebb24167 Mon Sep 17 00:00:00 2001 From: Slendy Date: Fri, 23 Sep 2022 00:03:54 -0500 Subject: [PATCH 02/14] Implement hearting playlists --- .../Controllers/Slots/ListController.cs | 63 ++++++++++++++ ProjectLighthouse/Database.cs | 24 +++++ ProjectLighthouse/Levels/Playlist.cs | 10 +-- ProjectLighthouse/PlayerData/Profiles/User.cs | 5 ++ ProjectLighthouse/ProjectLighthouse.csproj | 4 +- .../Migrations/DatabaseModelSnapshot.cs | 87 ++++++++++++++++++- 6 files changed, 185 insertions(+), 8 deletions(-) diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs index 3e1d051b..6abe73d1 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs @@ -197,6 +197,69 @@ public class ListController : ControllerBase #endregion + #region Hearted Playlists + + [HttpGet("favouritePlaylists/{username}")] + public async Task GetFavouritePlaylists(string username, [FromQuery] int pageStart, [FromQuery] int pageSize) + { + GameToken? token = await this.database.GameTokenFromRequest(this.Request); + if (token == null) return this.StatusCode(403, ""); + + if (pageSize <= 0) return this.BadRequest(); + + User? targetUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); + if (targetUser == null) return this.StatusCode(403, ""); + + IEnumerable heartedPlaylists = this.database.Playlists.Where(p => p.CreatorId == targetUser.UserId) + .Skip(Math.Max(0, pageStart - 1)) + .Take(Math.Min(pageSize, 30)) + .AsEnumerable(); + + string response = heartedPlaylists.Aggregate(string.Empty, (current, p) => current + p.Serialize()); + + return this.Ok + ( + LbpSerializer.TaggedStringElement("favouritePlaylists", response, new Dictionary + { + { "total", this.database.HeartedPlaylists.Count(p => p.UserId == targetUser.UserId) }, + { "hint_start", pageStart + Math.Min(pageSize, 30) }, + }) + ); + } + + [HttpPost("favourite/playlist/{playlistId:int}")] + public async Task AddFavouritePlaylist(int playlistId) + { + GameToken? token = await this.database.GameTokenFromRequest(this.Request); + if (token == null) return this.StatusCode(403, ""); + + User? user = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == token.UserId); + if (user == null) return this.BadRequest(); + + Playlist? playlist = await this.database.Playlists.FirstOrDefaultAsync(s => s.PlaylistId == playlistId); + if (playlist == null) return this.NotFound(); + + await this.database.HeartPlaylist(token.UserId, playlist); + + return await this.GetFavouritePlaylists(user.Username, 1, 30); + } + + [HttpPost("unfavourite/slot/{playlistId:int}")] + public async Task RemoveFavouritePlaylist(int playlistId) + { + GameToken? token = await this.database.GameTokenFromRequest(this.Request); + if (token == null) return this.StatusCode(403, ""); + + Playlist? playlist = await this.database.Playlists.FirstOrDefaultAsync(s => s.PlaylistId == playlistId); + if (playlist == null) return this.NotFound(); + + await this.database.UnheartPlaylist(token.UserId, playlist); + + return this.Ok(); + } + + #endregion + #endregion Levels #region Users diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs index 86d1a38a..c87263fe 100644 --- a/ProjectLighthouse/Database.cs +++ b/ProjectLighthouse/Database.cs @@ -30,6 +30,7 @@ public class Database : DbContext public DbSet QueuedLevels { get; set; } public DbSet HeartedLevels { get; set; } public DbSet HeartedProfiles { get; set; } + public DbSet HeartedPlaylists { get; set; } public DbSet Comments { get; set; } public DbSet GameTokens { get; set; } public DbSet WebTokens { get; set; } @@ -51,6 +52,7 @@ public class Database : DbContext public DbSet PasswordResetTokens { get; set; } public DbSet RegistrationTokens { get; set; } public DbSet APIKeys { get; set; } + public DbSet Playlists { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder options) => options.UseMySql(ServerConfiguration.Instance.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion); @@ -231,6 +233,28 @@ public class Database : DbContext await this.SaveChangesAsync(); } + public async Task HeartPlaylist(int userId, Playlist heartedPlaylist) + { + HeartedPlaylist? heartedList = await this.HeartedPlaylists.FirstOrDefaultAsync(p => p.UserId == userId && p.PlaylistId == heartedPlaylist.PlaylistId); + if (heartedList != null) return; + + this.HeartedPlaylists.Add(new HeartedPlaylist() + { + PlaylistId = heartedPlaylist.PlaylistId, + UserId = userId, + }); + + await this.SaveChangesAsync(); + } + + public async Task UnheartPlaylist(int userId, Playlist heartedPlaylist) + { + HeartedPlaylist? heartedList = await this.HeartedPlaylists.FirstOrDefaultAsync(p => p.UserId == userId && p.PlaylistId == heartedPlaylist.PlaylistId); + if (heartedList != null) this.HeartedPlaylists.Remove(heartedList); + + await this.SaveChangesAsync(); + } + public async Task HeartLevel(int userId, Slot heartedSlot) { HeartedLevel? heartedLevel = await this.HeartedLevels.FirstOrDefaultAsync(q => q.UserId == userId && q.SlotId == heartedSlot.SlotId); diff --git a/ProjectLighthouse/Levels/Playlist.cs b/ProjectLighthouse/Levels/Playlist.cs index 4355afc2..deb2a108 100644 --- a/ProjectLighthouse/Levels/Playlist.cs +++ b/ProjectLighthouse/Levels/Playlist.cs @@ -27,6 +27,8 @@ public class Playlist [JsonIgnore] public User? Creator { get; set; } + public int Hearts(Database database) => database.HeartedPlaylists.Count(p => p.HeartedPlaylistId == this.PlaylistId); + public string SlotCollection { get; set; } = ""; [JsonIgnore] @@ -46,13 +48,11 @@ public class Playlist using Database database = new(); string playlist = LbpSerializer.StringElement("id", this.PlaylistId) + LbpSerializer.StringElement("author", - LbpSerializer.StringElement("npHandle", this.Creator?.Username)) + + LbpSerializer.StringElement("npHandle", this.Creator?.Username)) + LbpSerializer.StringElement("name", this.Name) + LbpSerializer.StringElement("description", this.Description) + LbpSerializer.StringElement("levels", this.SlotIds.Length) + - LbpSerializer.StringElement("thumbs", 0) + - LbpSerializer.StringElement("plays", 0) + - LbpSerializer.StringElement("unique_plays", 0) + + LbpSerializer.StringElement("hearts", this.Hearts(database)) + LbpSerializer.StringElement("levels_quota", ServerConfiguration.Instance.UserGeneratedContentLimits.ListsQuota) + this.SerializeIcons(database); @@ -62,7 +62,7 @@ public class Playlist private string SerializeIcons(Database database) { string iconList = this.SlotIds.Select(id => database.Slots.FirstOrDefault(s => s.SlotId == id)) - .Where(slot => slot != null) + .Where(slot => slot != null && slot.IconHash.Length > 0) .Aggregate(string.Empty, (current, slot) => current + LbpSerializer.StringElement("icon", slot?.IconHash)); return LbpSerializer.StringElement("icons", iconList); } diff --git a/ProjectLighthouse/PlayerData/Profiles/User.cs b/ProjectLighthouse/PlayerData/Profiles/User.cs index 534fc9bd..46983b08 100644 --- a/ProjectLighthouse/PlayerData/Profiles/User.cs +++ b/ProjectLighthouse/PlayerData/Profiles/User.cs @@ -116,6 +116,10 @@ public class User [JsonIgnore] public int HeartedUsers => this.database.HeartedProfiles.Count(p => p.UserId == this.UserId); + [NotMapped] + [JsonIgnore] + public int HeartedPlaylists => this.database.HeartedPlaylists.Count(p => p.UserId == this.UserId); + [NotMapped] [JsonIgnore] public int QueuedLevels => this.database.QueuedLevels.Count(p => p.UserId == this.UserId); @@ -218,6 +222,7 @@ public class User LbpSerializer.StringElement("location", this.Location.Serialize()) + LbpSerializer.StringElement("favouriteSlotCount", this.HeartedLevels, true) + LbpSerializer.StringElement("favouriteUserCount", this.HeartedUsers, true) + + LbpSerializer.StringElement("favouritePlaylistCount", this.HeartedPlaylists, true) + LbpSerializer.StringElement("lolcatftwCount", this.QueuedLevels, true) + LbpSerializer.StringElement("pins", this.Pins, true); diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index fd7a2b22..8f670e49 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -10,8 +10,8 @@ - - + + diff --git a/ProjectLighthouse/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs b/ProjectLighthouse/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs index 1ce63adf..e4084263 100644 --- a/ProjectLighthouse/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs +++ b/ProjectLighthouse/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs @@ -16,7 +16,7 @@ namespace ProjectLighthouse.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "6.0.8") + .HasAnnotation("ProductVersion", "6.0.9") .HasAnnotation("Relational:MaxIdentifierLength", 64); modelBuilder.Entity("LBPUnion.ProjectLighthouse.Administration.CompletedMigration", b => @@ -172,6 +172,55 @@ namespace ProjectLighthouse.Migrations b.ToTable("HeartedLevels"); }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Levels.HeartedPlaylist", b => + { + b.Property("HeartedPlaylistId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("PlaylistId") + .HasColumnType("int"); + + b.Property("UserId") + .HasColumnType("int"); + + b.HasKey("HeartedPlaylistId"); + + b.HasIndex("PlaylistId"); + + b.HasIndex("UserId"); + + b.ToTable("HeartedPlaylists"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Levels.Playlist", b => + { + b.Property("PlaylistId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + b.Property("CreatorId") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("SlotCollection") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("PlaylistId"); + + b.HasIndex("CreatorId"); + + b.ToTable("Playlists"); + }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Levels.QueuedLevel", b => { b.Property("QueuedLevelId") @@ -273,6 +322,9 @@ namespace ProjectLighthouse.Migrations b.Property("InternalSlotId") .HasColumnType("int"); + b.Property("IsAdventurePlanet") + .HasColumnType("tinyint(1)"); + b.Property("LastUpdated") .HasColumnType("bigint"); @@ -903,6 +955,9 @@ namespace ProjectLighthouse.Migrations .ValueGeneratedOnAdd() .HasColumnType("int"); + b.Property("ChildSlotId") + .HasColumnType("int"); + b.Property("PlayerIdCollection") .HasColumnType("longtext"); @@ -989,6 +1044,36 @@ namespace ProjectLighthouse.Migrations b.Navigation("User"); }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Levels.HeartedPlaylist", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.Levels.Playlist", "Playlist") + .WithMany() + .HasForeignKey("PlaylistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("LBPUnion.ProjectLighthouse.PlayerData.Profiles.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Playlist"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Levels.Playlist", b => + { + b.HasOne("LBPUnion.ProjectLighthouse.PlayerData.Profiles.User", "Creator") + .WithMany() + .HasForeignKey("CreatorId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Creator"); + }); + modelBuilder.Entity("LBPUnion.ProjectLighthouse.Levels.QueuedLevel", b => { b.HasOne("LBPUnion.ProjectLighthouse.Levels.Slot", "Slot") From 84e645942aa9a510e2e0b061d79a1e5f2d2a7f55 Mon Sep 17 00:00:00 2001 From: Slendy Date: Fri, 23 Sep 2022 22:03:25 -0500 Subject: [PATCH 03/14] Make playlist serialization include hint_start --- .../Controllers/Slots/CollectionController.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs index 9ea1e307..a401f965 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs @@ -1,5 +1,4 @@ #nullable enable -using System.Xml.Schema; using System.Xml.Serialization; using LBPUnion.ProjectLighthouse.Configuration; using LBPUnion.ProjectLighthouse.Helpers; @@ -120,7 +119,11 @@ public class CollectionController : ControllerBase (current, slot) => current + slot.Serialize()); int total = this.database.Playlists.Count(p => p.CreatorId == userId); - return LbpSerializer.TaggedStringElement("playlists", response, "total", total); + return LbpSerializer.TaggedStringElement("playlists", response, new Dictionary + { + {"total", total}, + {"hint_start", total+1}, + }); } [HttpPost("playlists")] From af0e5bd4241353e8af2e0335cfc3a68349b13bdf Mon Sep 17 00:00:00 2001 From: Slendy Date: Sat, 24 Sep 2022 19:24:38 -0500 Subject: [PATCH 04/14] Changes from self review --- .../Controllers/Slots/CollectionController.cs | 42 +++++++++---------- .../Controllers/Slots/ListController.cs | 13 +++--- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs index a401f965..f712acf2 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs @@ -25,7 +25,6 @@ public class CollectionController : ControllerBase this.database = database; } - [HttpGet("playlists/{playlistId:int}/slots")] public async Task GetPlaylistSlots(int playlistId) { @@ -67,13 +66,7 @@ public class CollectionController : ControllerBase return this.Ok(this.GetUserPlaylists(token.UserId)); } - this.Request.Body.Position = 0; - string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); - - - string rootElement = bodyString.Contains("levels") ? "levels" : "playlist"; // I hate lbp3 - XmlSerializer serializer = new(typeof(Playlist), new XmlRootAttribute(rootElement)); - Playlist? newPlaylist = (Playlist?)serializer.Deserialize(new StringReader(bodyString)); + Playlist? newPlaylist = await this.getPlaylistFromBody(); if (newPlaylist == null) return this.BadRequest(); @@ -96,15 +89,9 @@ public class CollectionController : ControllerBase } } - if (!string.IsNullOrWhiteSpace(newPlaylist.Name)) - { - targetPlaylist.Name = newPlaylist.Name; - } + if (!string.IsNullOrWhiteSpace(newPlaylist.Name)) targetPlaylist.Name = newPlaylist.Name; - if (!string.IsNullOrWhiteSpace(newPlaylist.Description)) - { - targetPlaylist.Description = newPlaylist.Description; - } + if (!string.IsNullOrWhiteSpace(newPlaylist.Description)) targetPlaylist.Description = newPlaylist.Description; await this.database.SaveChangesAsync(); @@ -136,18 +123,12 @@ public class CollectionController : ControllerBase if (playlistCount > ServerConfiguration.Instance.UserGeneratedContentLimits.ListsQuota) return this.BadRequest(); - this.Request.Body.Position = 0; - string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); - - XmlSerializer serializer = new(typeof(Playlist), new XmlRootAttribute("playlist")); - Playlist? playlist = (Playlist?)serializer.Deserialize(new StringReader(bodyString)); + Playlist? playlist = await this.getPlaylistFromBody(); if (playlist == null) return this.BadRequest(); playlist.CreatorId = token.UserId; - SanitizationHelper.SanitizeStringsInClass(playlist); - this.database.Playlists.Add(playlist); await this.database.SaveChangesAsync(); @@ -262,4 +243,19 @@ public class CollectionController : ControllerBase ) ); } + + private async Task getPlaylistFromBody() + { + this.Request.Body.Position = 0; + string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); + + string rootElement = bodyString.Contains("levels") ? "levels" : "playlist"; + XmlSerializer serializer = new(typeof(Playlist), new XmlRootAttribute(rootElement)); + Playlist? playlist = (Playlist?)serializer.Deserialize(new StringReader(bodyString)); + + SanitizationHelper.SanitizeStringsInClass(playlist); + + return playlist; + } + } \ No newline at end of file diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs index 6abe73d1..aee2d425 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs @@ -207,10 +207,10 @@ public class ListController : ControllerBase if (pageSize <= 0) return this.BadRequest(); - User? targetUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username); - if (targetUser == null) return this.StatusCode(403, ""); + int targetUserId = await this.database.Users.Where(u => u.Username == username).Select(u => u.UserId).FirstOrDefaultAsync(); + if (targetUserId == 0) return this.StatusCode(403, ""); - IEnumerable heartedPlaylists = this.database.Playlists.Where(p => p.CreatorId == targetUser.UserId) + IEnumerable heartedPlaylists = this.database.Playlists.Where(p => p.CreatorId == targetUserId) .Skip(Math.Max(0, pageStart - 1)) .Take(Math.Min(pageSize, 30)) .AsEnumerable(); @@ -221,7 +221,7 @@ public class ListController : ControllerBase ( LbpSerializer.TaggedStringElement("favouritePlaylists", response, new Dictionary { - { "total", this.database.HeartedPlaylists.Count(p => p.UserId == targetUser.UserId) }, + { "total", this.database.HeartedPlaylists.Count(p => p.UserId == targetUserId) }, { "hint_start", pageStart + Math.Min(pageSize, 30) }, }) ); @@ -233,15 +233,14 @@ public class ListController : ControllerBase GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); - User? user = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == token.UserId); - if (user == null) return this.BadRequest(); + string username = await this.database.UsernameFromGameToken(token); Playlist? playlist = await this.database.Playlists.FirstOrDefaultAsync(s => s.PlaylistId == playlistId); if (playlist == null) return this.NotFound(); await this.database.HeartPlaylist(token.UserId, playlist); - return await this.GetFavouritePlaylists(user.Username, 1, 30); + return await this.GetFavouritePlaylists(username, 1, 30); } [HttpPost("unfavourite/slot/{playlistId:int}")] From 5865f7eb0e32bdc38c957c25345880afcdec4c7f Mon Sep 17 00:00:00 2001 From: Slendy Date: Sat, 24 Sep 2022 19:31:17 -0500 Subject: [PATCH 05/14] Forgot the migration file --- .../Migrations/20220923042831_AddPlaylists.cs | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 ProjectLighthouse/Migrations/20220923042831_AddPlaylists.cs diff --git a/ProjectLighthouse/Migrations/20220923042831_AddPlaylists.cs b/ProjectLighthouse/Migrations/20220923042831_AddPlaylists.cs new file mode 100644 index 00000000..f7023a6d --- /dev/null +++ b/ProjectLighthouse/Migrations/20220923042831_AddPlaylists.cs @@ -0,0 +1,94 @@ +using LBPUnion.ProjectLighthouse; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ProjectLighthouse.Migrations +{ + [DbContext(typeof(Database))] + [Migration("20220923042831_AddPlaylists")] + public partial class AddPlaylists : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Playlists", + columns: table => new + { + PlaylistId = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + Name = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Description = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + CreatorId = table.Column(type: "int", nullable: false), + SlotCollection = table.Column(type: "longtext", nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_Playlists", x => x.PlaylistId); + table.ForeignKey( + name: "FK_Playlists_Users_CreatorId", + column: x => x.CreatorId, + principalTable: "Users", + principalColumn: "UserId", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateTable( + name: "HeartedPlaylists", + columns: table => new + { + HeartedPlaylistId = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + UserId = table.Column(type: "int", nullable: false), + PlaylistId = table.Column(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_HeartedPlaylists", x => x.HeartedPlaylistId); + table.ForeignKey( + name: "FK_HeartedPlaylists_Playlists_PlaylistId", + column: x => x.PlaylistId, + principalTable: "Playlists", + principalColumn: "PlaylistId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_HeartedPlaylists_Users_UserId", + column: x => x.UserId, + principalTable: "Users", + principalColumn: "UserId", + onDelete: ReferentialAction.Cascade); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_HeartedPlaylists_PlaylistId", + table: "HeartedPlaylists", + column: "PlaylistId"); + + migrationBuilder.CreateIndex( + name: "IX_HeartedPlaylists_UserId", + table: "HeartedPlaylists", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_Playlists_CreatorId", + table: "Playlists", + column: "CreatorId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "HeartedPlaylists"); + + migrationBuilder.DropTable( + name: "Playlists"); + } + } +} From d7fa63d31cf098a0662375f10bdece486e44fa07 Mon Sep 17 00:00:00 2001 From: Slendy Date: Sat, 24 Sep 2022 19:43:22 -0500 Subject: [PATCH 06/14] Fix hearting playlists --- .../Controllers/Slots/ListController.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs index aee2d425..afe56e37 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs @@ -210,7 +210,7 @@ public class ListController : ControllerBase int targetUserId = await this.database.Users.Where(u => u.Username == username).Select(u => u.UserId).FirstOrDefaultAsync(); if (targetUserId == 0) return this.StatusCode(403, ""); - IEnumerable heartedPlaylists = this.database.Playlists.Where(p => p.CreatorId == targetUserId) + IEnumerable heartedPlaylists = this.database.Playlists.Include(p => p.Creator).Where(p => p.CreatorId == targetUserId) .Skip(Math.Max(0, pageStart - 1)) .Take(Math.Min(pageSize, 30)) .AsEnumerable(); @@ -233,14 +233,12 @@ public class ListController : ControllerBase GameToken? token = await this.database.GameTokenFromRequest(this.Request); if (token == null) return this.StatusCode(403, ""); - string username = await this.database.UsernameFromGameToken(token); - Playlist? playlist = await this.database.Playlists.FirstOrDefaultAsync(s => s.PlaylistId == playlistId); if (playlist == null) return this.NotFound(); await this.database.HeartPlaylist(token.UserId, playlist); - return await this.GetFavouritePlaylists(username, 1, 30); + return this.Ok(); } [HttpPost("unfavourite/slot/{playlistId:int}")] From a15ff2c886f62a0a50956634e5bcd77c504d6f02 Mon Sep 17 00:00:00 2001 From: Slendy Date: Sat, 24 Sep 2022 21:28:05 -0500 Subject: [PATCH 07/14] Fix typo in unfavourite route --- .../Controllers/Slots/ListController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs index afe56e37..b3936942 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs @@ -241,7 +241,7 @@ public class ListController : ControllerBase return this.Ok(); } - [HttpPost("unfavourite/slot/{playlistId:int}")] + [HttpPost("unfavourite/playlist/{playlistId:int}")] public async Task RemoveFavouritePlaylist(int playlistId) { GameToken? token = await this.database.GameTokenFromRequest(this.Request); From 2217c2080396e6e18dda9b4656694d47c9ead91b Mon Sep 17 00:00:00 2001 From: Slendy Date: Sat, 24 Sep 2022 21:34:05 -0500 Subject: [PATCH 08/14] Fix favouritePlaylists logic --- .../Controllers/Slots/ListController.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs index b3936942..f9783862 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ListController.cs @@ -210,10 +210,8 @@ public class ListController : ControllerBase int targetUserId = await this.database.Users.Where(u => u.Username == username).Select(u => u.UserId).FirstOrDefaultAsync(); if (targetUserId == 0) return this.StatusCode(403, ""); - IEnumerable heartedPlaylists = this.database.Playlists.Include(p => p.Creator).Where(p => p.CreatorId == targetUserId) - .Skip(Math.Max(0, pageStart - 1)) - .Take(Math.Min(pageSize, 30)) - .AsEnumerable(); + IEnumerable heartedPlaylists = this.database.HeartedPlaylists.Where(p => p.UserId == targetUserId) + .Include(p => p.Playlist).Include(p => p.Playlist.Creator).OrderByDescending(p => p.HeartedPlaylistId).Select(p => p.Playlist); string response = heartedPlaylists.Aggregate(string.Empty, (current, p) => current + p.Serialize()); From f46bd4fc8748754394e773e99af4fc6b0cc830f3 Mon Sep 17 00:00:00 2001 From: Slendy Date: Tue, 27 Sep 2022 21:52:56 -0500 Subject: [PATCH 09/14] Fix playlist descriptions and pirate bug --- .../Controllers/Slots/CollectionController.cs | 2 +- .../Pages/PirateSignupPage.cshtml.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs index f712acf2..1184a603 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/CollectionController.cs @@ -249,7 +249,7 @@ public class CollectionController : ControllerBase this.Request.Body.Position = 0; string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync(); - string rootElement = bodyString.Contains("levels") ? "levels" : "playlist"; + string rootElement = bodyString.StartsWith("") ? "playlist" : "levels"; XmlSerializer serializer = new(typeof(Playlist), new XmlRootAttribute(rootElement)); Playlist? playlist = (Playlist?)serializer.Deserialize(new StringReader(bodyString)); diff --git a/ProjectLighthouse.Servers.Website/Pages/PirateSignupPage.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/PirateSignupPage.cshtml.cs index a65827f4..3d88a60e 100644 --- a/ProjectLighthouse.Servers.Website/Pages/PirateSignupPage.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/PirateSignupPage.cshtml.cs @@ -12,7 +12,7 @@ public class PirateSignupPage : BaseLayout public IActionResult OnGet() { User? user = this.Database.UserFromWebRequest(this.Request); - if (user == null) return this.RedirectToPage("/login"); + if (user == null) return this.Redirect("/login"); return this.Page(); } From ee11798dc6941f016ab80e4384d8fa014ede7e32 Mon Sep 17 00:00:00 2001 From: Josh Date: Thu, 29 Sep 2022 17:34:22 -0500 Subject: [PATCH 10/14] Login with email and confirm age on registration (#493) * Implement login with email * Add confirm age checkbox to register page * Fix registration unit tests * Fix registration unit tests for real this time Co-authored-by: Dagg <32235163+daggintosh@users.noreply.github.com> --- ProjectLighthouse.Localization/General.resx | 3 +++ .../StringLists/GeneralStrings.cs | 1 + .../Pages/LoginForm.cshtml | 17 +++++++++------- .../Pages/LoginForm.cshtml.cs | 20 +++++++++++++++++-- .../Pages/RegisterForm.cshtml | 6 ++++++ .../Pages/UserSettingsPage.cshtml | 2 +- .../Tests/RegisterTests.cs | 6 ++++++ 7 files changed, 45 insertions(+), 10 deletions(-) diff --git a/ProjectLighthouse.Localization/General.resx b/ProjectLighthouse.Localization/General.resx index f3bd12b5..138736e8 100644 --- a/ProjectLighthouse.Localization/General.resx +++ b/ProjectLighthouse.Localization/General.resx @@ -54,4 +54,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/StringLists/GeneralStrings.cs b/ProjectLighthouse.Localization/StringLists/GeneralStrings.cs index 1b30afc9..edc3eb5f 100644 --- a/ProjectLighthouse.Localization/StringLists/GeneralStrings.cs +++ b/ProjectLighthouse.Localization/StringLists/GeneralStrings.cs @@ -4,6 +4,7 @@ public static class GeneralStrings { public static readonly TranslatableString Username = create("username"); public static readonly TranslatableString Password = create("password"); + public static readonly TranslatableString Email = create("email"); public static readonly TranslatableString Register = create("register"); public static readonly TranslatableString ResetPassword = create("reset_password"); public static readonly TranslatableString ForgotPassword = create("forgot_password"); diff --git a/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml b/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml index cedbbdc7..401ec447 100644 --- a/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml @@ -41,9 +41,12 @@
- + @{ + string username = ServerConfiguration.Instance.Mail.MailEnabled ? Model.Translate(GeneralStrings.Email) : Model.Translate(GeneralStrings.Username); + } +
- +
@@ -75,9 +78,9 @@ }
- -
- @Model.Translate(GeneralStrings.ForgotPassword) -
-
+ +
+ @Model.Translate(GeneralStrings.ForgotPassword) +
+
\ No newline at end of file diff --git a/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml.cs b/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml.cs index c751290e..8e9454b6 100644 --- a/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml.cs +++ b/ProjectLighthouse.Servers.Website/Pages/LoginForm.cshtml.cs @@ -27,7 +27,7 @@ public class LoginForm : BaseLayout { if (string.IsNullOrWhiteSpace(username)) { - this.Error = this.Translate(ErrorStrings.UsernameInvalid); + this.Error = ServerConfiguration.Instance.Mail.MailEnabled ? this.Translate(ErrorStrings.UsernameInvalid) : this.Translate(ErrorStrings.EmailInvalid); return this.Page(); } @@ -43,7 +43,23 @@ public class LoginForm : BaseLayout return this.Page(); } - User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username); + User? user; + + if (!ServerConfiguration.Instance.Mail.MailEnabled) + { + user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username); + } + else + { + user = await this.Database.Users.FirstOrDefaultAsync(u => u.EmailAddress == username); + if (user == null) + { + User? noEmailUser = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username); + if (noEmailUser != null && noEmailUser.EmailAddress == null) user = noEmailUser; + + } + } + if (user == null) { Logger.Warn($"User {username} failed to login on web due to invalid username", LogArea.Login); diff --git a/ProjectLighthouse.Servers.Website/Pages/RegisterForm.cshtml b/ProjectLighthouse.Servers.Website/Pages/RegisterForm.cshtml index 46ebd31a..56ccafa6 100644 --- a/ProjectLighthouse.Servers.Website/Pages/RegisterForm.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/RegisterForm.cshtml @@ -74,6 +74,12 @@ +
+
+ + +
+
@if (ServerConfiguration.Instance.Captcha.CaptchaEnabled) { diff --git a/ProjectLighthouse.Servers.Website/Pages/UserSettingsPage.cshtml b/ProjectLighthouse.Servers.Website/Pages/UserSettingsPage.cshtml index 5fe1bfc3..7acab753 100644 --- a/ProjectLighthouse.Servers.Website/Pages/UserSettingsPage.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/UserSettingsPage.cshtml @@ -67,7 +67,7 @@ function onSubmit(e){ @if (ServerConfiguration.Instance.Mail.MailEnabled && (Model.User == Model.ProfileUser || Model.User!.IsAdmin)) {
- +
} diff --git a/ProjectLighthouse.Tests.WebsiteTests/Tests/RegisterTests.cs b/ProjectLighthouse.Tests.WebsiteTests/Tests/RegisterTests.cs index 7624ca83..be2561ca 100644 --- a/ProjectLighthouse.Tests.WebsiteTests/Tests/RegisterTests.cs +++ b/ProjectLighthouse.Tests.WebsiteTests/Tests/RegisterTests.cs @@ -28,6 +28,8 @@ public class RegisterTests : LighthouseWebTest this.Driver.FindElement(By.Id("password")).SendKeys(password); this.Driver.FindElement(By.Id("confirmPassword")).SendKeys(password); + this.Driver.FindElement(By.Id("age-checkbox")).Click(); + this.Driver.FindElement(By.Id("submit")).Click(); User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username); @@ -51,6 +53,8 @@ public class RegisterTests : LighthouseWebTest this.Driver.FindElement(By.Id("password")).SendKeys(password); this.Driver.FindElement(By.Id("confirmPassword")).SendKeys(password + "a"); + this.Driver.FindElement(By.Id("age-checkbox")).Click(); + this.Driver.FindElement(By.Id("submit")).Click(); User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == username); @@ -76,6 +80,8 @@ public class RegisterTests : LighthouseWebTest this.Driver.FindElement(By.Id("password")).SendKeys(password); this.Driver.FindElement(By.Id("confirmPassword")).SendKeys(password); + this.Driver.FindElement(By.Id("age-checkbox")).Click(); + this.Driver.FindElement(By.Id("submit")).Click(); Assert.Contains("The username you've chosen is already taken.", this.Driver.PageSource); From 9217fa3f6c229fa315366f49879ede4b9a420cae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 17:37:44 -0500 Subject: [PATCH 11/14] Bump Microsoft.NET.Test.Sdk from 17.3.1 to 17.3.2 (#502) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.3.1 to 17.3.2. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v17.3.1...v17.3.2) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../ProjectLighthouse.Tests.GameApiTests.csproj | 2 +- .../ProjectLighthouse.Tests.WebsiteTests.csproj | 2 +- ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj b/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj index 660e2cb4..55d4d04c 100644 --- a/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj +++ b/ProjectLighthouse.Tests.GameApiTests/ProjectLighthouse.Tests.GameApiTests.csproj @@ -14,7 +14,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive
- + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj b/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj index 33af481e..a8d98cd1 100644 --- a/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj +++ b/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj @@ -14,7 +14,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj index b8c96bab..23cd2d59 100644 --- a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj +++ b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj @@ -19,7 +19,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + runtime; build; native; contentfiles; analyzers; buildtransitive From cbeca7c8ac57f1311733f9faa28e62fb162a44ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 17:40:55 -0500 Subject: [PATCH 12/14] Bump Selenium.WebDriver from 4.4.0 to 4.5.0 (#505) Bumps Selenium.WebDriver from 4.4.0 to 4.5.0. --- updated-dependencies: - dependency-name: Selenium.WebDriver dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../ProjectLighthouse.Tests.WebsiteTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj b/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj index a8d98cd1..5b8c545c 100644 --- a/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj +++ b/ProjectLighthouse.Tests.WebsiteTests/ProjectLighthouse.Tests.WebsiteTests.csproj @@ -15,7 +15,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + From fd9d4a1c1697702463d34e9ca511c716772bc6e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 17:50:55 -0500 Subject: [PATCH 13/14] Bump InfluxDB.Client from 4.5.0 to 4.6.0 (#506) Bumps [InfluxDB.Client](https://github.com/influxdata/influxdb-client-csharp) from 4.5.0 to 4.6.0. - [Release notes](https://github.com/influxdata/influxdb-client-csharp/releases) - [Changelog](https://github.com/influxdata/influxdb-client-csharp/blob/master/CHANGELOG.md) - [Commits](https://github.com/influxdata/influxdb-client-csharp/compare/v4.5.0...v4.6.0) --- updated-dependencies: - dependency-name: InfluxDB.Client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- ProjectLighthouse/ProjectLighthouse.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj index 8f670e49..2254c57d 100644 --- a/ProjectLighthouse/ProjectLighthouse.csproj +++ b/ProjectLighthouse/ProjectLighthouse.csproj @@ -13,7 +13,7 @@ - + From e8a7eb2a41c9de588c4acb2443118de3a00b44ad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 29 Sep 2022 18:49:26 -0500 Subject: [PATCH 14/14] Update the localization files (#507) [skip ci] Update the localization files Co-authored-by: Crowdin Bot --- ProjectLighthouse.Localization/General.lang-ar-SA.resx | 3 +++ ProjectLighthouse.Localization/General.lang-da-DK.resx | 3 +++ ProjectLighthouse.Localization/General.lang-de-DE.resx | 3 +++ ProjectLighthouse.Localization/General.lang-en-PT.resx | 3 +++ ProjectLighthouse.Localization/General.lang-eo-UY.resx | 3 +++ ProjectLighthouse.Localization/General.lang-es-ES.resx | 3 +++ ProjectLighthouse.Localization/General.lang-es-MX.resx | 3 +++ ProjectLighthouse.Localization/General.lang-et-EE.resx | 3 +++ ProjectLighthouse.Localization/General.lang-fi-FI.resx | 3 +++ ProjectLighthouse.Localization/General.lang-fil-PH.resx | 3 +++ ProjectLighthouse.Localization/General.lang-fr-FR.resx | 3 +++ ProjectLighthouse.Localization/General.lang-ga-IE.resx | 3 +++ ProjectLighthouse.Localization/General.lang-he-IL.resx | 3 +++ ProjectLighthouse.Localization/General.lang-hi-IN.resx | 3 +++ ProjectLighthouse.Localization/General.lang-id-ID.resx | 3 +++ ProjectLighthouse.Localization/General.lang-it-IT.resx | 3 +++ ProjectLighthouse.Localization/General.lang-ja-JP.resx | 3 +++ ProjectLighthouse.Localization/General.lang-nl-NL.resx | 3 +++ ProjectLighthouse.Localization/General.lang-no-NO.resx | 3 +++ ProjectLighthouse.Localization/General.lang-pl-PL.resx | 3 +++ ProjectLighthouse.Localization/General.lang-pt-PT.resx | 3 +++ ProjectLighthouse.Localization/General.lang-ru-RU.resx | 3 +++ ProjectLighthouse.Localization/General.lang-sv-SE.resx | 3 +++ ProjectLighthouse.Localization/General.lang-th-TH.resx | 3 +++ ProjectLighthouse.Localization/General.lang-tr-TR.resx | 3 +++ ProjectLighthouse.Localization/General.lang-uk-UA.resx | 3 +++ ProjectLighthouse.Localization/General.lang-zh-CN.resx | 3 +++ ProjectLighthouse.Localization/General.lang-zh-TW.resx | 3 +++ 28 files changed, 84 insertions(+) diff --git a/ProjectLighthouse.Localization/General.lang-ar-SA.resx b/ProjectLighthouse.Localization/General.lang-ar-SA.resx index 16a1a80d..ca5e4960 100644 --- a/ProjectLighthouse.Localization/General.lang-ar-SA.resx +++ b/ProjectLighthouse.Localization/General.lang-ar-SA.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-da-DK.resx b/ProjectLighthouse.Localization/General.lang-da-DK.resx index fb9cc03a..6111fc81 100644 --- a/ProjectLighthouse.Localization/General.lang-da-DK.resx +++ b/ProjectLighthouse.Localization/General.lang-da-DK.resx @@ -53,4 +53,7 @@ De seneste billeder + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-de-DE.resx b/ProjectLighthouse.Localization/General.lang-de-DE.resx index a4ed9594..360d7f10 100644 --- a/ProjectLighthouse.Localization/General.lang-de-DE.resx +++ b/ProjectLighthouse.Localization/General.lang-de-DE.resx @@ -53,4 +53,7 @@ Neueste Fotos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-en-PT.resx b/ProjectLighthouse.Localization/General.lang-en-PT.resx index 8c46dc33..555d884e 100644 --- a/ProjectLighthouse.Localization/General.lang-en-PT.resx +++ b/ProjectLighthouse.Localization/General.lang-en-PT.resx @@ -53,4 +53,7 @@ Most recent maps + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-eo-UY.resx b/ProjectLighthouse.Localization/General.lang-eo-UY.resx index 1179db9d..f11fd9b1 100644 --- a/ProjectLighthouse.Localization/General.lang-eo-UY.resx +++ b/ProjectLighthouse.Localization/General.lang-eo-UY.resx @@ -53,4 +53,7 @@ Plej lastatempaj bildoj + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-es-ES.resx b/ProjectLighthouse.Localization/General.lang-es-ES.resx index aa1692e4..206928e5 100644 --- a/ProjectLighthouse.Localization/General.lang-es-ES.resx +++ b/ProjectLighthouse.Localization/General.lang-es-ES.resx @@ -53,4 +53,7 @@ Fotos más recientes + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-es-MX.resx b/ProjectLighthouse.Localization/General.lang-es-MX.resx index adbbea3f..24a9545e 100644 --- a/ProjectLighthouse.Localization/General.lang-es-MX.resx +++ b/ProjectLighthouse.Localization/General.lang-es-MX.resx @@ -53,4 +53,7 @@ Fotos más recientes + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-et-EE.resx b/ProjectLighthouse.Localization/General.lang-et-EE.resx index e78d2849..ae31a0b4 100644 --- a/ProjectLighthouse.Localization/General.lang-et-EE.resx +++ b/ProjectLighthouse.Localization/General.lang-et-EE.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-fi-FI.resx b/ProjectLighthouse.Localization/General.lang-fi-FI.resx index 49b80ec7..5c99c43b 100644 --- a/ProjectLighthouse.Localization/General.lang-fi-FI.resx +++ b/ProjectLighthouse.Localization/General.lang-fi-FI.resx @@ -53,4 +53,7 @@ Viimeisimmät kuvat + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-fil-PH.resx b/ProjectLighthouse.Localization/General.lang-fil-PH.resx index 88945423..8110303c 100644 --- a/ProjectLighthouse.Localization/General.lang-fil-PH.resx +++ b/ProjectLighthouse.Localization/General.lang-fil-PH.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-fr-FR.resx b/ProjectLighthouse.Localization/General.lang-fr-FR.resx index 65c30c8a..8bb50d3a 100644 --- a/ProjectLighthouse.Localization/General.lang-fr-FR.resx +++ b/ProjectLighthouse.Localization/General.lang-fr-FR.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-ga-IE.resx b/ProjectLighthouse.Localization/General.lang-ga-IE.resx index bbd6553d..5007e301 100644 --- a/ProjectLighthouse.Localization/General.lang-ga-IE.resx +++ b/ProjectLighthouse.Localization/General.lang-ga-IE.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-he-IL.resx b/ProjectLighthouse.Localization/General.lang-he-IL.resx index e78d2849..ae31a0b4 100644 --- a/ProjectLighthouse.Localization/General.lang-he-IL.resx +++ b/ProjectLighthouse.Localization/General.lang-he-IL.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-hi-IN.resx b/ProjectLighthouse.Localization/General.lang-hi-IN.resx index e78d2849..ae31a0b4 100644 --- a/ProjectLighthouse.Localization/General.lang-hi-IN.resx +++ b/ProjectLighthouse.Localization/General.lang-hi-IN.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-id-ID.resx b/ProjectLighthouse.Localization/General.lang-id-ID.resx index e78d2849..ae31a0b4 100644 --- a/ProjectLighthouse.Localization/General.lang-id-ID.resx +++ b/ProjectLighthouse.Localization/General.lang-id-ID.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-it-IT.resx b/ProjectLighthouse.Localization/General.lang-it-IT.resx index e78d2849..ae31a0b4 100644 --- a/ProjectLighthouse.Localization/General.lang-it-IT.resx +++ b/ProjectLighthouse.Localization/General.lang-it-IT.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-ja-JP.resx b/ProjectLighthouse.Localization/General.lang-ja-JP.resx index b164cd2f..bcd980f2 100644 --- a/ProjectLighthouse.Localization/General.lang-ja-JP.resx +++ b/ProjectLighthouse.Localization/General.lang-ja-JP.resx @@ -53,4 +53,7 @@ 最近の写真 + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-nl-NL.resx b/ProjectLighthouse.Localization/General.lang-nl-NL.resx index e78d2849..ae31a0b4 100644 --- a/ProjectLighthouse.Localization/General.lang-nl-NL.resx +++ b/ProjectLighthouse.Localization/General.lang-nl-NL.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-no-NO.resx b/ProjectLighthouse.Localization/General.lang-no-NO.resx index fafe11cf..6b7248a5 100644 --- a/ProjectLighthouse.Localization/General.lang-no-NO.resx +++ b/ProjectLighthouse.Localization/General.lang-no-NO.resx @@ -53,4 +53,7 @@ Siste bilder + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-pl-PL.resx b/ProjectLighthouse.Localization/General.lang-pl-PL.resx index 9079146a..072b9ded 100644 --- a/ProjectLighthouse.Localization/General.lang-pl-PL.resx +++ b/ProjectLighthouse.Localization/General.lang-pl-PL.resx @@ -53,4 +53,7 @@ Ostatnie zdjęcia + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-pt-PT.resx b/ProjectLighthouse.Localization/General.lang-pt-PT.resx index 4ec21051..d107092d 100644 --- a/ProjectLighthouse.Localization/General.lang-pt-PT.resx +++ b/ProjectLighthouse.Localization/General.lang-pt-PT.resx @@ -53,4 +53,7 @@ Fotos mais recentes + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-ru-RU.resx b/ProjectLighthouse.Localization/General.lang-ru-RU.resx index 4717a55d..81646fa3 100644 --- a/ProjectLighthouse.Localization/General.lang-ru-RU.resx +++ b/ProjectLighthouse.Localization/General.lang-ru-RU.resx @@ -53,4 +53,7 @@ Самые последние фото + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-sv-SE.resx b/ProjectLighthouse.Localization/General.lang-sv-SE.resx index b543cc11..00202f04 100644 --- a/ProjectLighthouse.Localization/General.lang-sv-SE.resx +++ b/ProjectLighthouse.Localization/General.lang-sv-SE.resx @@ -53,4 +53,7 @@ Senaste foton + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-th-TH.resx b/ProjectLighthouse.Localization/General.lang-th-TH.resx index e78d2849..ae31a0b4 100644 --- a/ProjectLighthouse.Localization/General.lang-th-TH.resx +++ b/ProjectLighthouse.Localization/General.lang-th-TH.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-tr-TR.resx b/ProjectLighthouse.Localization/General.lang-tr-TR.resx index e78d2849..ae31a0b4 100644 --- a/ProjectLighthouse.Localization/General.lang-tr-TR.resx +++ b/ProjectLighthouse.Localization/General.lang-tr-TR.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-uk-UA.resx b/ProjectLighthouse.Localization/General.lang-uk-UA.resx index e78d2849..ae31a0b4 100644 --- a/ProjectLighthouse.Localization/General.lang-uk-UA.resx +++ b/ProjectLighthouse.Localization/General.lang-uk-UA.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-zh-CN.resx b/ProjectLighthouse.Localization/General.lang-zh-CN.resx index c47dce25..f2af7010 100644 --- a/ProjectLighthouse.Localization/General.lang-zh-CN.resx +++ b/ProjectLighthouse.Localization/General.lang-zh-CN.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file diff --git a/ProjectLighthouse.Localization/General.lang-zh-TW.resx b/ProjectLighthouse.Localization/General.lang-zh-TW.resx index 601772cf..f57e4ae1 100644 --- a/ProjectLighthouse.Localization/General.lang-zh-TW.resx +++ b/ProjectLighthouse.Localization/General.lang-zh-TW.resx @@ -53,4 +53,7 @@ Most recent photos + + Email + \ No newline at end of file