mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-05-13 13:22:28 +00:00
Refactor serialization system (#702)
* Initial work for serialization refactor * Experiment with new naming conventions * Mostly implement user and slot serialization. Still needs to be fine tuned to match original implementation Many things are left in a broken state like website features/api endpoints/lbp3 categories * Fix release building * Migrate scores, reviews, and more to new serialization system. Many things are still broken but progress is steadily being made * Fix Api responses and migrate serialization for most types * Make serialization better and fix bugs Fix recursive PrepareSerialization when recursive item is set during root item's PrepareSerialization, items, should be properly indexed in order but it's only tested to 1 level of recursion * Fix review serialization * Fix user serialization producing malformed SQL query * Remove DefaultIfEmpty query * MariaDB doesn't like double nested queries * Fix LBP1 tag counter * Implement lbp3 categories and add better deserialization handling * Implement expression tree caching to speed up reflection and write new serializer tests * Remove Game column from UserEntity and rename DatabaseContextModelSnapshot.cs back to DatabaseModelSnapshot.cs * Make UserEntity username not required * Fix recursive serialization of lists and add relevant unit tests * Actually commit the migration * Fix LocationTests to use new deserialization class * Fix comments not serializing the right author username * Replace all occurrences of StatusCode with their respective ASP.NET named result instead of StatusCode(403) everything is now in the form of Forbid() * Fix SlotBase.ConvertToEntity and LocationTests * Fix compilation error * Give Location a default value in GameUserSlot and GameUser * Reimplement stubbed website functions * Convert grief reports to new serialization system * Update DatabaseModelSnapshot and bump dotnet tool version * Remove unused directives * Fix broken type reference * Fix rated comments on website * Don't include banned users in website comments * Optimize score submission * Fix slot id calculating in in-game comment posting * Move serialization interfaces to types folder and add more documentation * Allow uploading of versus scores
This commit is contained in:
parent
307b2135a3
commit
329ab66043
248 changed files with 4993 additions and 2896 deletions
|
@ -3,7 +3,7 @@
|
||||||
"isRoot": true,
|
"isRoot": true,
|
||||||
"tools": {
|
"tools": {
|
||||||
"dotnet-ef": {
|
"dotnet-ef": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.4",
|
||||||
"commands": [
|
"commands": [
|
||||||
"dotnet-ef"
|
"dotnet-ef"
|
||||||
]
|
]
|
||||||
|
|
|
@ -28,15 +28,18 @@ public class SlotEndpoints : ApiEndpointController
|
||||||
/// <returns>The slot</returns>
|
/// <returns>The slot</returns>
|
||||||
/// <response code="200">The slot list, if successful.</response>
|
/// <response code="200">The slot list, if successful.</response>
|
||||||
[HttpGet("slots")]
|
[HttpGet("slots")]
|
||||||
[ProducesResponseType(typeof(List<MinimalSlot>), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(List<ApiSlot>), StatusCodes.Status200OK)]
|
||||||
public async Task<IActionResult> GetSlots([FromQuery] int limit = 20, [FromQuery] int skip = 0)
|
public async Task<IActionResult> GetSlots([FromQuery] int limit = 20, [FromQuery] int skip = 0)
|
||||||
{
|
{
|
||||||
if (skip < 0) skip = 0;
|
if (skip < 0) skip = 0;
|
||||||
if (limit < 0) limit = 0;
|
if (limit < 0) limit = 0;
|
||||||
limit = Math.Min(ServerStatics.PageSize, limit);
|
limit = Math.Min(ServerStatics.PageSize, limit);
|
||||||
|
|
||||||
IEnumerable<MinimalSlot> minimalSlots = (await this.database.Slots.OrderByDescending(s => s.FirstUploaded).Skip(skip).Take(limit).ToListAsync()).Select
|
IEnumerable<ApiSlot> minimalSlots = await this.database.Slots.OrderByDescending(s => s.FirstUploaded)
|
||||||
(MinimalSlot.FromSlot);
|
.Skip(skip)
|
||||||
|
.Take(limit)
|
||||||
|
.Select(s => ApiSlot.CreateFromEntity(s))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
return this.Ok(minimalSlots);
|
return this.Ok(minimalSlots);
|
||||||
}
|
}
|
||||||
|
@ -49,13 +52,13 @@ public class SlotEndpoints : ApiEndpointController
|
||||||
/// <response code="200">The slot, if successful.</response>
|
/// <response code="200">The slot, if successful.</response>
|
||||||
/// <response code="404">The slot could not be found.</response>
|
/// <response code="404">The slot could not be found.</response>
|
||||||
[HttpGet("slot/{id:int}")]
|
[HttpGet("slot/{id:int}")]
|
||||||
[ProducesResponseType(typeof(Slot), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(ApiSlot), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<IActionResult> GetSlot(int id)
|
public async Task<IActionResult> GetSlot(int id)
|
||||||
{
|
{
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(u => u.SlotId == id);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(u => u.SlotId == id);
|
||||||
if (slot == null) return this.NotFound();
|
if (slot == null) return this.NotFound();
|
||||||
|
|
||||||
return this.Ok(slot);
|
return this.Ok(ApiSlot.CreateFromEntity(slot));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,10 +2,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.API.Controllers;
|
namespace LBPUnion.ProjectLighthouse.Servers.API.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
public class StatusController : ApiEndpointController
|
||||||
[Route("/api/v1")]
|
|
||||||
[Produces("application/json")]
|
|
||||||
public class StatusController : ControllerBase
|
|
||||||
{
|
{
|
||||||
[AcceptVerbs("GET", "HEAD", Route = "status")]
|
[AcceptVerbs("GET", "HEAD", Route = "status")]
|
||||||
public IActionResult GetStatus() => this.Ok();
|
public IActionResult GetStatus() => this.Ok();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.API.Responses;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
@ -29,25 +30,25 @@ public class UserEndpoints : ApiEndpointController
|
||||||
/// <response code="200">The user, if successful.</response>
|
/// <response code="200">The user, if successful.</response>
|
||||||
/// <response code="404">The user could not be found.</response>
|
/// <response code="404">The user could not be found.</response>
|
||||||
[HttpGet("user/{id:int}")]
|
[HttpGet("user/{id:int}")]
|
||||||
[ProducesResponseType(typeof(User), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(ApiUser), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<IActionResult> GetUser(int id)
|
public async Task<IActionResult> GetUser(int id)
|
||||||
{
|
{
|
||||||
User? user = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
UserEntity? user = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
if (user == null) return this.NotFound();
|
if (user == null) return this.NotFound();
|
||||||
|
|
||||||
return this.Ok(user);
|
return this.Ok(ApiUser.CreateFromEntity(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("username/{username}")]
|
[HttpGet("username/{username}")]
|
||||||
[ProducesResponseType(typeof(User), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(ApiUser), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<IActionResult> GetUser(string username)
|
public async Task<IActionResult> GetUser(string username)
|
||||||
{
|
{
|
||||||
User? user = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
UserEntity? user = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
if (user == null) return this.NotFound();
|
if (user == null) return this.NotFound();
|
||||||
|
|
||||||
return this.Ok(user);
|
return this.Ok(ApiUser.CreateFromEntity(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -58,15 +59,16 @@ public class UserEndpoints : ApiEndpointController
|
||||||
/// <response code="200">The list of users, if any were found</response>
|
/// <response code="200">The list of users, if any were found</response>
|
||||||
/// <response code="404">No users matched the query</response>
|
/// <response code="404">No users matched the query</response>
|
||||||
[HttpGet("search/user")]
|
[HttpGet("search/user")]
|
||||||
[ProducesResponseType(typeof(User), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(ApiUser), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<IActionResult> SearchUsers(string query)
|
public async Task<IActionResult> SearchUsers(string query)
|
||||||
{
|
{
|
||||||
List<User> users = await this.database.Users
|
List<ApiUser> users = await this.database.Users
|
||||||
.Where(u => u.PermissionLevel != PermissionLevel.Banned && u.Username.Contains(query))
|
.Where(u => u.PermissionLevel != PermissionLevel.Banned && u.Username.Contains(query))
|
||||||
.Where(u => u.ProfileVisibility == PrivacyType.All) // TODO: change check for when user is logged in
|
.Where(u => u.ProfileVisibility == PrivacyType.All) // TODO: change check for when user is logged in
|
||||||
.OrderByDescending(b => b.UserId)
|
.OrderByDescending(b => b.UserId)
|
||||||
.Take(20)
|
.Take(20)
|
||||||
|
.Select(u => ApiUser.CreateFromEntity(u))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
if (!users.Any()) return this.NotFound();
|
if (!users.Any()) return this.NotFound();
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ public class UserEndpoints : ApiEndpointController
|
||||||
/// <response code="200">The user's status, if successful.</response>
|
/// <response code="200">The user's status, if successful.</response>
|
||||||
/// <response code="404">The user could not be found.</response>
|
/// <response code="404">The user could not be found.</response>
|
||||||
[HttpGet("user/{id:int}/status")]
|
[HttpGet("user/{id:int}/status")]
|
||||||
[ProducesResponseType(typeof(UserStatus), StatusCodes.Status200OK)]
|
[ProducesResponseType(typeof(ApiUser), StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public IActionResult GetUserStatus(int id)
|
public IActionResult GetUserStatus(int id)
|
||||||
{
|
{
|
||||||
|
@ -102,8 +104,8 @@ public class UserEndpoints : ApiEndpointController
|
||||||
|
|
||||||
string authToken = authHeader[(authHeader.IndexOf(' ') + 1)..];
|
string authToken = authHeader[(authHeader.IndexOf(' ') + 1)..];
|
||||||
|
|
||||||
ApiKey? apiKey = await this.database.APIKeys.FirstOrDefaultAsync(k => k.Key == authToken);
|
ApiKeyEntity? apiKey = await this.database.APIKeys.FirstOrDefaultAsync(k => k.Key == authToken);
|
||||||
if (apiKey == null) return this.StatusCode(403, null);
|
if (apiKey == null) return this.Forbid();
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(username))
|
if (!string.IsNullOrWhiteSpace(username))
|
||||||
{
|
{
|
||||||
|
@ -111,7 +113,7 @@ public class UserEndpoints : ApiEndpointController
|
||||||
if (userExists) return this.BadRequest();
|
if (userExists) return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
RegistrationToken token = new()
|
RegistrationTokenEntity token = new()
|
||||||
{
|
{
|
||||||
Created = DateTime.Now,
|
Created = DateTime.Now,
|
||||||
Token = CryptoHelper.GenerateAuthToken(),
|
Token = CryptoHelper.GenerateAuthToken(),
|
||||||
|
|
40
ProjectLighthouse.Servers.API/Responses/ApiSlot.cs
Normal file
40
ProjectLighthouse.Servers.API/Responses/ApiSlot.cs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.API.Responses;
|
||||||
|
|
||||||
|
public struct ApiSlot
|
||||||
|
{
|
||||||
|
public int SlotId { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string IconHash { get; set; }
|
||||||
|
public bool TeamPick { get; set; }
|
||||||
|
public bool IsAdventure { get; set; }
|
||||||
|
public Location Location { get; set; }
|
||||||
|
public GameVersion GameVersion { get; set; }
|
||||||
|
public long FirstUploaded { get; set; }
|
||||||
|
public long LastUpdated { get; set; }
|
||||||
|
public int Plays { get; set; }
|
||||||
|
public int PlaysUnique { get; set; }
|
||||||
|
public int PlaysComplete { get; set; }
|
||||||
|
public bool CommentsEnabled { get; set; }
|
||||||
|
|
||||||
|
public static ApiSlot CreateFromEntity(SlotEntity slot) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
SlotId = slot.SlotId,
|
||||||
|
Name = slot.Name,
|
||||||
|
IconHash = slot.IconHash,
|
||||||
|
TeamPick = slot.TeamPick,
|
||||||
|
IsAdventure = slot.IsAdventurePlanet,
|
||||||
|
Location = slot.Location,
|
||||||
|
GameVersion = slot.GameVersion,
|
||||||
|
FirstUploaded = slot.FirstUploaded,
|
||||||
|
LastUpdated = slot.LastUpdated,
|
||||||
|
Plays = slot.Plays,
|
||||||
|
PlaysUnique = slot.PlaysUnique,
|
||||||
|
PlaysComplete = slot.PlaysComplete,
|
||||||
|
CommentsEnabled = slot.CommentsEnabled,
|
||||||
|
};
|
||||||
|
}
|
42
ProjectLighthouse.Servers.API/Responses/ApiUser.cs
Normal file
42
ProjectLighthouse.Servers.API/Responses/ApiUser.cs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.API.Responses;
|
||||||
|
|
||||||
|
public struct ApiUser
|
||||||
|
{
|
||||||
|
public int UserId { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public bool EmailAddressVerified { get; set; }
|
||||||
|
public string IconHash { get; set; }
|
||||||
|
public string Biography { get; set; }
|
||||||
|
public Location Location { get; set; }
|
||||||
|
public string YayHash { get; set; }
|
||||||
|
public string MehHash { get; set; }
|
||||||
|
public string BooHash { get; set; }
|
||||||
|
public long LastLogin { get; set; }
|
||||||
|
public long LastLogout { get; set; }
|
||||||
|
public PrivacyType LevelVisibility { get; set; }
|
||||||
|
public PrivacyType ProfileVisibility { get; set; }
|
||||||
|
public bool CommentsEnabled { get; set; }
|
||||||
|
|
||||||
|
public static ApiUser CreateFromEntity(UserEntity entity) =>
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
UserId = entity.UserId,
|
||||||
|
Username = entity.Username,
|
||||||
|
EmailAddressVerified = entity.EmailAddressVerified,
|
||||||
|
IconHash = entity.IconHash,
|
||||||
|
Biography = entity.Biography,
|
||||||
|
Location = entity.Location,
|
||||||
|
YayHash = entity.YayHash,
|
||||||
|
MehHash = entity.MehHash,
|
||||||
|
BooHash = entity.BooHash,
|
||||||
|
LastLogin = entity.LastLogin,
|
||||||
|
LastLogout = entity.LastLogin,
|
||||||
|
LevelVisibility = entity.LevelVisibility,
|
||||||
|
ProfileVisibility = entity.ProfileVisibility,
|
||||||
|
CommentsEnabled = entity.CommentsEnabled,
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.API.Responses;
|
|
||||||
|
|
||||||
public struct MinimalSlot
|
|
||||||
{
|
|
||||||
public int SlotId { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string IconHash { get; set; }
|
|
||||||
public bool TeamPick { get; set; }
|
|
||||||
public bool IsAdventure { 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,
|
|
||||||
IsAdventure = slot.IsAdventurePlanet,
|
|
||||||
GameVersion = slot.GameVersion,
|
|
||||||
#if DEBUG
|
|
||||||
FirstUploaded = slot.FirstUploaded,
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -41,7 +41,7 @@ public class ClientConfigurationController : ControllerBase
|
||||||
|
|
||||||
[HttpGet("t_conf")]
|
[HttpGet("t_conf")]
|
||||||
[Produces("text/xml")]
|
[Produces("text/xml")]
|
||||||
public IActionResult Conf() => this.Ok("<t_enable>false</t_enable>");
|
public IActionResult Conf() => this.Ok(new TelemetryConfigResponse());
|
||||||
|
|
||||||
[HttpGet("ChallengeConfig.xml")]
|
[HttpGet("ChallengeConfig.xml")]
|
||||||
[Produces("text/xml")]
|
[Produces("text/xml")]
|
||||||
|
@ -54,8 +54,8 @@ public class ClientConfigurationController : ControllerBase
|
||||||
[Produces("text/xml")]
|
[Produces("text/xml")]
|
||||||
public async Task<IActionResult> GetPrivacySettings()
|
public async Task<IActionResult> GetPrivacySettings()
|
||||||
{
|
{
|
||||||
User? user = await this.database.UserFromGameToken(this.GetToken());
|
UserEntity? user = await this.database.UserFromGameToken(this.GetToken());
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
PrivacySettings ps = new()
|
PrivacySettings ps = new()
|
||||||
{
|
{
|
||||||
|
@ -63,15 +63,15 @@ public class ClientConfigurationController : ControllerBase
|
||||||
ProfileVisibility = user.ProfileVisibility.ToSerializedString(),
|
ProfileVisibility = user.ProfileVisibility.ToSerializedString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.Ok(ps.Serialize());
|
return this.Ok(ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("privacySettings")]
|
[HttpPost("privacySettings")]
|
||||||
[Produces("text/xml")]
|
[Produces("text/xml")]
|
||||||
public async Task<IActionResult> SetPrivacySetting()
|
public async Task<IActionResult> SetPrivacySetting()
|
||||||
{
|
{
|
||||||
User? user = await this.database.UserFromGameToken(this.GetToken());
|
UserEntity? user = await this.database.UserFromGameToken(this.GetToken());
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
PrivacySettings? settings = await this.DeserializeBody<PrivacySettings>();
|
PrivacySettings? settings = await this.DeserializeBody<PrivacySettings>();
|
||||||
if (settings == null) return this.BadRequest();
|
if (settings == null) return this.BadRequest();
|
||||||
|
@ -100,6 +100,6 @@ public class ClientConfigurationController : ControllerBase
|
||||||
ProfileVisibility = user.ProfileVisibility.ToSerializedString(),
|
ProfileVisibility = user.ProfileVisibility.ToSerializedString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.Ok(ps.Serialize());
|
return this.Ok(ps);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,10 +2,10 @@
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -29,7 +29,7 @@ public class CommentController : ControllerBase
|
||||||
[HttpPost("rateComment/{slotType}/{slotId:int}")]
|
[HttpPost("rateComment/{slotType}/{slotId:int}")]
|
||||||
public async Task<IActionResult> RateComment([FromQuery] int commentId, [FromQuery] int rating, string? username, string? slotType, int slotId)
|
public async Task<IActionResult> RateComment([FromQuery] int commentId, [FromQuery] int rating, string? username, string? slotType, int slotId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
// Return bad request if both are true or both are false
|
// Return bad request if both are true or both are false
|
||||||
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
|
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
|
||||||
|
@ -44,7 +44,7 @@ public class CommentController : ControllerBase
|
||||||
[HttpGet("userComments/{username}")]
|
[HttpGet("userComments/{username}")]
|
||||||
public async Task<IActionResult> GetComments([FromQuery] int pageStart, [FromQuery] int pageSize, string? username, string? slotType, int slotId)
|
public async Task<IActionResult> GetComments([FromQuery] int pageStart, [FromQuery] int pageSize, string? username, string? slotType, int slotId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0 || pageStart < 0) return this.BadRequest();
|
if (pageSize <= 0 || pageStart < 0) return this.BadRequest();
|
||||||
|
|
||||||
|
@ -77,45 +77,37 @@ public class CommentController : ControllerBase
|
||||||
where blockedProfile.UserId == token.UserId
|
where blockedProfile.UserId == token.UserId
|
||||||
select blockedProfile.BlockedUserId).ToListAsync();
|
select blockedProfile.BlockedUserId).ToListAsync();
|
||||||
|
|
||||||
List<Comment> comments = await this.database.Comments.Where(p => p.TargetId == targetId && p.Type == type)
|
List<GameComment> comments = await this.database.Comments.Where(p => p.TargetId == targetId && p.Type == type)
|
||||||
.OrderByDescending(p => p.Timestamp)
|
.OrderByDescending(p => p.Timestamp)
|
||||||
.Where(p => !blockedUsers.Contains(p.PosterUserId))
|
.Where(p => !blockedUsers.Contains(p.PosterUserId))
|
||||||
.Include(c => c.Poster)
|
.Include(c => c.Poster)
|
||||||
.Where(p => p.Poster.PermissionLevel != PermissionLevel.Banned)
|
.Where(p => p.Poster.PermissionLevel != PermissionLevel.Banned)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30))
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(c => GameComment.CreateFromEntity(c, token.UserId))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
string outputXml = comments.Aggregate
|
return this.Ok(new CommentListResponse(comments));
|
||||||
(string.Empty, (current, comment) => current + comment.Serialize(this.getReaction(token.UserId, comment.CommentId).Result));
|
|
||||||
return this.Ok(LbpSerializer.StringElement("comments", outputXml));
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int> getReaction(int userId, int commentId)
|
|
||||||
{
|
|
||||||
return await this.database.Reactions.Where(r => r.UserId == userId)
|
|
||||||
.Where(r => r.TargetId == commentId)
|
|
||||||
.Select(r => r.Rating)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("postUserComment/{username}")]
|
[HttpPost("postUserComment/{username}")]
|
||||||
[HttpPost("postComment/{slotType}/{slotId:int}")]
|
[HttpPost("postComment/{slotType}/{slotId:int}")]
|
||||||
public async Task<IActionResult> PostComment(string? username, string? slotType, int slotId)
|
public async Task<IActionResult> PostComment(string? username, string? slotType, int slotId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Comment? comment = await this.DeserializeBody<Comment>();
|
GameComment? comment = await this.DeserializeBody<GameComment>();
|
||||||
if (comment == null) return this.BadRequest();
|
if (comment == null) return this.BadRequest();
|
||||||
|
|
||||||
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
|
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
|
||||||
|
|
||||||
|
if (slotType == "developer") slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
|
||||||
|
|
||||||
CommentType type = username == null ? CommentType.Level : CommentType.Profile;
|
CommentType type = username == null ? CommentType.Level : CommentType.Profile;
|
||||||
|
|
||||||
int targetId;
|
int targetId;
|
||||||
if (type == CommentType.Level)
|
if (type == CommentType.Level)
|
||||||
{
|
{
|
||||||
slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
|
|
||||||
targetId = await this.database.Slots.Where(s => s.SlotId == slotId)
|
targetId = await this.database.Slots.Where(s => s.SlotId == slotId)
|
||||||
.Where(s => s.CommentsEnabled && !s.Hidden)
|
.Where(s => s.CommentsEnabled && !s.Hidden)
|
||||||
.Select(s => s.SlotId)
|
.Select(s => s.SlotId)
|
||||||
|
@ -138,11 +130,11 @@ public class CommentController : ControllerBase
|
||||||
[HttpPost("deleteComment/{slotType}/{slotId:int}")]
|
[HttpPost("deleteComment/{slotType}/{slotId:int}")]
|
||||||
public async Task<IActionResult> DeleteComment([FromQuery] int commentId, string? username, string? slotType, int slotId)
|
public async Task<IActionResult> DeleteComment([FromQuery] int commentId, string? username, string? slotType, int slotId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
|
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
|
||||||
|
|
||||||
Comment? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
|
CommentEntity? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
|
||||||
if (comment == null) return this.NotFound();
|
if (comment == null) return this.NotFound();
|
||||||
|
|
||||||
if (comment.Deleted) return this.Ok();
|
if (comment.Deleted) return this.Ok();
|
||||||
|
@ -169,7 +161,7 @@ public class CommentController : ControllerBase
|
||||||
canDelete = comment.PosterUserId == token.UserId || slotCreator == token.UserId;
|
canDelete = comment.PosterUserId == token.UserId || slotCreator == token.UserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canDelete) return this.StatusCode(403, "");
|
if (!canDelete) return this.Forbid();
|
||||||
|
|
||||||
comment.Deleted = true;
|
comment.Deleted = true;
|
||||||
comment.DeletedBy = await this.database.UsernameFromGameToken(token);
|
comment.DeletedBy = await this.database.UsernameFromGameToken(token);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
|
@ -10,5 +11,5 @@ namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
public class DeveloperController : Controller
|
public class DeveloperController : Controller
|
||||||
{
|
{
|
||||||
[HttpGet("developer_videos")]
|
[HttpGet("developer_videos")]
|
||||||
public IActionResult DeveloperVideos() => this.Ok("<videos></videos>");
|
public IActionResult DeveloperVideos() => this.Ok(new GameDeveloperVideos());
|
||||||
}
|
}
|
|
@ -2,11 +2,11 @@
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users;
|
||||||
using LBPUnion.ProjectLighthouse.StorableLists.Stores;
|
using LBPUnion.ProjectLighthouse.StorableLists.Stores;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -29,17 +29,17 @@ public class FriendsController : ControllerBase
|
||||||
[HttpPost("npdata")]
|
[HttpPost("npdata")]
|
||||||
public async Task<IActionResult> NPData()
|
public async Task<IActionResult> NPData()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
NPData? npData = await this.DeserializeBody<NPData>();
|
NPData? npData = await this.DeserializeBody<NPData>();
|
||||||
if (npData == null) return this.BadRequest();
|
if (npData == null) return this.BadRequest();
|
||||||
|
|
||||||
SanitizationHelper.SanitizeStringsInClass(npData);
|
SanitizationHelper.SanitizeStringsInClass(npData);
|
||||||
|
|
||||||
List<User> friends = new();
|
List<UserEntity> friends = new();
|
||||||
foreach (string friendName in npData.Friends ?? new List<string>())
|
foreach (string friendName in npData.Friends ?? new List<string>())
|
||||||
{
|
{
|
||||||
User? friend = await this.database.Users.FirstOrDefaultAsync(u => u.Username == friendName);
|
UserEntity? friend = await this.database.Users.FirstOrDefaultAsync(u => u.Username == friendName);
|
||||||
if (friend == null) continue;
|
if (friend == null) continue;
|
||||||
|
|
||||||
friends.Add(friend);
|
friends.Add(friend);
|
||||||
|
@ -48,7 +48,7 @@ public class FriendsController : ControllerBase
|
||||||
List<int> blockedUsers = new();
|
List<int> blockedUsers = new();
|
||||||
foreach (string blockedUserName in npData.BlockedUsers ?? new List<string>())
|
foreach (string blockedUserName in npData.BlockedUsers ?? new List<string>())
|
||||||
{
|
{
|
||||||
User? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == blockedUserName);
|
UserEntity? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == blockedUserName);
|
||||||
if (blockedUser == null) continue;
|
if (blockedUser == null) continue;
|
||||||
|
|
||||||
blockedUsers.Add(blockedUser.UserId);
|
blockedUsers.Add(blockedUser.UserId);
|
||||||
|
@ -61,30 +61,35 @@ public class FriendsController : ControllerBase
|
||||||
|
|
||||||
UserFriendStore.UpdateFriendData(friendStore);
|
UserFriendStore.UpdateFriendData(friendStore);
|
||||||
|
|
||||||
string friendsSerialized = friends.Aggregate(string.Empty, (current, user1) => current + LbpSerializer.StringElement("npHandle", user1.Username));
|
List<MinimalUserProfile> minimalFriends =
|
||||||
|
friends.Select(u => new MinimalUserProfile
|
||||||
|
{
|
||||||
|
UserHandle = new NpHandle(u.Username, ""),
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
return this.Ok(LbpSerializer.StringElement("npdata", LbpSerializer.StringElement("friends", friendsSerialized)));
|
return this.Ok(new FriendResponse(minimalFriends));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("myFriends")]
|
[HttpGet("myFriends")]
|
||||||
public async Task<IActionResult> MyFriends()
|
public async Task<IActionResult> MyFriends()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
UserFriendData? friendStore = UserFriendStore.GetUserFriendData(token.UserId);
|
UserFriendData? friendStore = UserFriendStore.GetUserFriendData(token.UserId);
|
||||||
|
|
||||||
if (friendStore == null)
|
GenericUserResponse<GameUser> response = new("myFriends", new List<GameUser>());
|
||||||
return this.Ok(LbpSerializer.BlankElement("myFriends"));
|
|
||||||
|
if (friendStore == null)
|
||||||
|
return this.Ok(response);
|
||||||
|
|
||||||
string friends = "";
|
|
||||||
foreach (int friendId in friendStore.FriendIds)
|
foreach (int friendId in friendStore.FriendIds)
|
||||||
{
|
{
|
||||||
User? friend = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == friendId);
|
UserEntity? friend = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == friendId);
|
||||||
if (friend == null) continue;
|
if (friend == null) continue;
|
||||||
|
|
||||||
friends += friend.Serialize(token.GameVersion);
|
response.Users.Add(GameUser.CreateFromEntity(friend, token.GameVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.Ok(LbpSerializer.StringElement("myFriends", friends));
|
return this.Ok(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -64,12 +64,12 @@ public class LoginController : ControllerBase
|
||||||
if (username == null)
|
if (username == null)
|
||||||
{
|
{
|
||||||
Logger.Warn("Unable to determine username, rejecting login", LogArea.Login);
|
Logger.Warn("Unable to determine username, rejecting login", LogArea.Login);
|
||||||
return this.StatusCode(403, "");
|
return this.Forbid();
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.database.RemoveExpiredTokens();
|
await this.database.RemoveExpiredTokens();
|
||||||
|
|
||||||
User? user;
|
UserEntity? user;
|
||||||
|
|
||||||
switch (npTicket.Platform)
|
switch (npTicket.Platform)
|
||||||
{
|
{
|
||||||
|
@ -91,7 +91,7 @@ public class LoginController : ControllerBase
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
// Check if there is an account with that username already
|
// Check if there is an account with that username already
|
||||||
User? targetUsername = await this.database.Users.FirstOrDefaultAsync(u => u.Username == npTicket.Username);
|
UserEntity? targetUsername = await this.database.Users.FirstOrDefaultAsync(u => u.Username == npTicket.Username);
|
||||||
if (targetUsername != null)
|
if (targetUsername != null)
|
||||||
{
|
{
|
||||||
ulong targetPlatform = npTicket.Platform == Platform.RPCS3
|
ulong targetPlatform = npTicket.Platform == Platform.RPCS3
|
||||||
|
@ -102,7 +102,7 @@ public class LoginController : ControllerBase
|
||||||
if (targetPlatform != 0)
|
if (targetPlatform != 0)
|
||||||
{
|
{
|
||||||
Logger.Warn($"New user tried to login but their name is already taken, username={username}", LogArea.Login);
|
Logger.Warn($"New user tried to login but their name is already taken, username={username}", LogArea.Login);
|
||||||
return this.StatusCode(403, "");
|
return this.Forbid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is already a pending link request don't create another
|
// if there is already a pending link request don't create another
|
||||||
|
@ -111,9 +111,9 @@ public class LoginController : ControllerBase
|
||||||
p.PlatformId == npTicket.UserId &&
|
p.PlatformId == npTicket.UserId &&
|
||||||
p.UserId == targetUsername.UserId);
|
p.UserId == targetUsername.UserId);
|
||||||
|
|
||||||
if (linkAttemptExists) return this.StatusCode(403, "");
|
if (linkAttemptExists) return this.Forbid();
|
||||||
|
|
||||||
PlatformLinkAttempt linkAttempt = new()
|
PlatformLinkAttemptEntity linkAttempt = new()
|
||||||
{
|
{
|
||||||
Platform = npTicket.Platform,
|
Platform = npTicket.Platform,
|
||||||
UserId = targetUsername.UserId,
|
UserId = targetUsername.UserId,
|
||||||
|
@ -124,13 +124,13 @@ public class LoginController : ControllerBase
|
||||||
this.database.PlatformLinkAttempts.Add(linkAttempt);
|
this.database.PlatformLinkAttempts.Add(linkAttempt);
|
||||||
await this.database.SaveChangesAsync();
|
await this.database.SaveChangesAsync();
|
||||||
Logger.Success($"User '{npTicket.Username}' tried to login but platform isn't linked, platform={npTicket.Platform}", LogArea.Login);
|
Logger.Success($"User '{npTicket.Username}' tried to login but platform isn't linked, platform={npTicket.Platform}", LogArea.Login);
|
||||||
return this.StatusCode(403, "");
|
return this.Forbid();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ServerConfiguration.Instance.Authentication.AutomaticAccountCreation)
|
if (!ServerConfiguration.Instance.Authentication.AutomaticAccountCreation)
|
||||||
{
|
{
|
||||||
Logger.Warn($"Unknown user tried to connect username={username}", LogArea.Login);
|
Logger.Warn($"Unknown user tried to connect username={username}", LogArea.Login);
|
||||||
return this.StatusCode(403, "");
|
return this.Forbid();
|
||||||
}
|
}
|
||||||
// create account for user if they don't exist
|
// create account for user if they don't exist
|
||||||
user = await this.database.CreateUser(username, "$");
|
user = await this.database.CreateUser(username, "$");
|
||||||
|
@ -162,7 +162,7 @@ public class LoginController : ControllerBase
|
||||||
{
|
{
|
||||||
Logger.Warn($"{npTicket.Platform} user changed their name to a name that is already taken," +
|
Logger.Warn($"{npTicket.Platform} user changed their name to a name that is already taken," +
|
||||||
$" oldName='{user.Username}', newName='{npTicket.Username}'", LogArea.Login);
|
$" oldName='{user.Username}', newName='{npTicket.Username}'", LogArea.Login);
|
||||||
return this.StatusCode(403, "");
|
return this.Forbid();
|
||||||
}
|
}
|
||||||
Logger.Info($"User's username has changed, old='{user.Username}', new='{npTicket.Username}', platform={npTicket.Platform}", LogArea.Login);
|
Logger.Info($"User's username has changed, old='{user.Username}', new='{npTicket.Username}', platform={npTicket.Platform}", LogArea.Login);
|
||||||
user.Username = username;
|
user.Username = username;
|
||||||
|
@ -176,26 +176,26 @@ public class LoginController : ControllerBase
|
||||||
await this.database.SaveChangesAsync();
|
await this.database.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
GameToken? token = await this.database.GameTokens.Include(t => t.User)
|
GameTokenEntity? token = await this.database.GameTokens.Include(t => t.User)
|
||||||
.FirstOrDefaultAsync(t => t.UserLocation == ipAddress && t.User.Username == npTicket.Username && t.TicketHash == npTicket.TicketHash);
|
.FirstOrDefaultAsync(t => t.UserLocation == ipAddress && t.User.Username == npTicket.Username && t.TicketHash == npTicket.TicketHash);
|
||||||
|
|
||||||
if (token != null)
|
if (token != null)
|
||||||
{
|
{
|
||||||
Logger.Warn($"Rejecting duplicate ticket from {username}", LogArea.Login);
|
Logger.Warn($"Rejecting duplicate ticket from {username}", LogArea.Login);
|
||||||
return this.StatusCode(403, "");
|
return this.Forbid();
|
||||||
}
|
}
|
||||||
|
|
||||||
token = await this.database.AuthenticateUser(user, npTicket, ipAddress);
|
token = await this.database.AuthenticateUser(user, npTicket, ipAddress);
|
||||||
if (token == null)
|
if (token == null)
|
||||||
{
|
{
|
||||||
Logger.Warn($"Unable to find/generate a token for username {npTicket.Username}", LogArea.Login);
|
Logger.Warn($"Unable to find/generate a token for username {npTicket.Username}", LogArea.Login);
|
||||||
return this.StatusCode(403, "");
|
return this.Forbid();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.IsBanned)
|
if (user.IsBanned)
|
||||||
{
|
{
|
||||||
Logger.Error($"User {npTicket.Username} tried to login but is banned", LogArea.Login);
|
Logger.Error($"User {npTicket.Username} tried to login but is banned", LogArea.Login);
|
||||||
return this.StatusCode(403, "");
|
return this.Forbid();
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Success($"Successfully logged in user {user.Username} as {token.GameVersion} client", LogArea.Login);
|
Logger.Success($"Successfully logged in user {user.Username} as {token.GameVersion} client", LogArea.Login);
|
||||||
|
@ -214,7 +214,7 @@ public class LoginController : ControllerBase
|
||||||
AuthTicket = "MM_AUTH=" + token.UserToken,
|
AuthTicket = "MM_AUTH=" + token.UserToken,
|
||||||
ServerBrand = VersionHelper.EnvVer,
|
ServerBrand = VersionHelper.EnvVer,
|
||||||
TitleStorageUrl = ServerConfiguration.Instance.GameApiExternalUrl,
|
TitleStorageUrl = ServerConfiguration.Instance.GameApiExternalUrl,
|
||||||
}.Serialize()
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -25,10 +25,10 @@ public class LogoutController : ControllerBase
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> OnPost()
|
public async Task<IActionResult> OnPost()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
User? user = await this.database.UserFromGameToken(token);
|
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
user.LastLogout = TimeHelper.TimestampMillis;
|
user.LastLogout = TimeHelper.TimestampMillis;
|
||||||
|
|
||||||
|
|
|
@ -28,18 +28,18 @@ public class EnterLevelController : ControllerBase
|
||||||
[HttpPost("play/{slotType}/{slotId:int}")]
|
[HttpPost("play/{slotType}/{slotId:int}")]
|
||||||
public async Task<IActionResult> PlayLevel(string slotType, int slotId)
|
public async Task<IActionResult> PlayLevel(string slotType, int slotId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest();
|
if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest();
|
||||||
|
|
||||||
// don't count plays for developer slots
|
// don't count plays for developer slots
|
||||||
if (slotType == "developer") return this.Ok();
|
if (slotType == "developer") return this.Ok();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
||||||
if (slot == null) return this.StatusCode(403, "");
|
if (slot == null) return this.BadRequest();
|
||||||
|
|
||||||
IQueryable<VisitedLevel> visited = this.database.VisitedLevels.Where(s => s.SlotId == slotId && s.UserId == token.UserId);
|
IQueryable<VisitedLevelEntity> visited = this.database.VisitedLevels.Where(s => s.SlotId == slotId && s.UserId == token.UserId);
|
||||||
VisitedLevel? v;
|
VisitedLevelEntity? v;
|
||||||
if (!visited.Any())
|
if (!visited.Any())
|
||||||
{
|
{
|
||||||
switch (token.GameVersion)
|
switch (token.GameVersion)
|
||||||
|
@ -57,7 +57,7 @@ public class EnterLevelController : ControllerBase
|
||||||
default: return this.BadRequest();
|
default: return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
v = new VisitedLevel
|
v = new VisitedLevelEntity
|
||||||
{
|
{
|
||||||
SlotId = slotId,
|
SlotId = slotId,
|
||||||
UserId = token.UserId,
|
UserId = token.UserId,
|
||||||
|
@ -98,22 +98,22 @@ public class EnterLevelController : ControllerBase
|
||||||
[HttpPost("enterLevel/{slotType}/{slotId:int}")]
|
[HttpPost("enterLevel/{slotType}/{slotId:int}")]
|
||||||
public async Task<IActionResult> EnterLevel(string slotType, int slotId)
|
public async Task<IActionResult> EnterLevel(string slotType, int slotId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest();
|
if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest();
|
||||||
|
|
||||||
if (slotType == "developer") return this.Ok();
|
if (slotType == "developer") return this.Ok();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
||||||
if (slot == null) return this.NotFound();
|
if (slot == null) return this.NotFound();
|
||||||
|
|
||||||
IQueryable<VisitedLevel> visited = this.database.VisitedLevels.Where(s => s.SlotId == slotId && s.UserId == token.UserId);
|
IQueryable<VisitedLevelEntity> visited = this.database.VisitedLevels.Where(s => s.SlotId == slotId && s.UserId == token.UserId);
|
||||||
VisitedLevel? v;
|
VisitedLevelEntity? v;
|
||||||
if (!visited.Any())
|
if (!visited.Any())
|
||||||
{
|
{
|
||||||
slot.PlaysLBP1Unique++;
|
slot.PlaysLBP1Unique++;
|
||||||
|
|
||||||
v = new VisitedLevel
|
v = new VisitedLevelEntity
|
||||||
{
|
{
|
||||||
SlotId = slotId,
|
SlotId = slotId,
|
||||||
UserId = token.UserId,
|
UserId = token.UserId,
|
||||||
|
|
|
@ -37,10 +37,10 @@ public class MatchController : ControllerBase
|
||||||
[Produces("text/plain")]
|
[Produces("text/plain")]
|
||||||
public async Task<IActionResult> Match()
|
public async Task<IActionResult> Match()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
User? user = await this.database.UserFromGameToken(token);
|
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
#region Parse match data
|
#region Parse match data
|
||||||
|
|
||||||
|
@ -113,7 +113,7 @@ public class MatchController : ControllerBase
|
||||||
List<int> users = new();
|
List<int> users = new();
|
||||||
foreach (string playerUsername in createRoom.Players)
|
foreach (string playerUsername in createRoom.Players)
|
||||||
{
|
{
|
||||||
User? player = await this.database.Users.FirstOrDefaultAsync(u => u.Username == playerUsername);
|
UserEntity? player = await this.database.Users.FirstOrDefaultAsync(u => u.Username == playerUsername);
|
||||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||||
if (player != null) users.Add(player.UserId);
|
if (player != null) users.Add(player.UserId);
|
||||||
else return this.BadRequest();
|
else return this.BadRequest();
|
||||||
|
@ -129,10 +129,10 @@ public class MatchController : ControllerBase
|
||||||
|
|
||||||
if (room != null)
|
if (room != null)
|
||||||
{
|
{
|
||||||
List<User> users = new();
|
List<UserEntity> users = new();
|
||||||
foreach (string playerUsername in updatePlayersInRoom.Players)
|
foreach (string playerUsername in updatePlayersInRoom.Players)
|
||||||
{
|
{
|
||||||
User? player = await this.database.Users.FirstOrDefaultAsync(u => u.Username == playerUsername);
|
UserEntity? player = await this.database.Users.FirstOrDefaultAsync(u => u.Username == playerUsername);
|
||||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||||
if (player != null) users.Add(player);
|
if (player != null) users.Add(player);
|
||||||
else return this.BadRequest();
|
else return this.BadRequest();
|
||||||
|
|
|
@ -46,7 +46,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.";
|
||||||
[HttpGet("announce")]
|
[HttpGet("announce")]
|
||||||
public async Task<IActionResult> Announce()
|
public async Task<IActionResult> Announce()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
string username = await this.database.UsernameFromGameToken(token);
|
string username = await this.database.UsernameFromGameToken(token);
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.";
|
||||||
[HttpPost("filter")]
|
[HttpPost("filter")]
|
||||||
public async Task<IActionResult> Filter()
|
public async Task<IActionResult> Filter()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
string message = await this.ReadBodyAsync();
|
string message = await this.ReadBodyAsync();
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.";
|
||||||
|
|
||||||
if (await this.database.Users.AnyAsync(u => u.EmailAddress == email)) return this.Ok();
|
if (await this.database.Users.AnyAsync(u => u.EmailAddress == email)) return this.Ok();
|
||||||
|
|
||||||
User? user = await this.database.UserFromGameToken(token);
|
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||||
if (user == null || user.EmailAddressVerified) return this.Ok();
|
if (user == null || user.EmailAddressVerified) return this.Ok();
|
||||||
|
|
||||||
user.EmailAddress = email;
|
user.EmailAddress = email;
|
||||||
|
|
|
@ -8,6 +8,7 @@ using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Moderation;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Moderation;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Moderation.Reports;
|
using LBPUnion.ProjectLighthouse.Types.Moderation.Reports;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
@ -29,11 +30,11 @@ public class ReportController : ControllerBase
|
||||||
[HttpPost("grief")]
|
[HttpPost("grief")]
|
||||||
public async Task<IActionResult> Report()
|
public async Task<IActionResult> Report()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
string username = await this.database.UsernameFromGameToken(token);
|
string username = await this.database.UsernameFromGameToken(token);
|
||||||
|
|
||||||
GriefReport? report = await this.DeserializeBody<GriefReport>();
|
GameGriefReport? report = await this.DeserializeBody<GameGriefReport>();
|
||||||
if (report == null) return this.BadRequest();
|
if (report == null) return this.BadRequest();
|
||||||
|
|
||||||
SanitizationHelper.SanitizeStringsInClass(report);
|
SanitizationHelper.SanitizeStringsInClass(report);
|
||||||
|
@ -46,18 +47,20 @@ public class ReportController : ControllerBase
|
||||||
|
|
||||||
if (report.XmlPlayers.Any(p => !this.database.IsUsernameValid(p.Name))) return this.BadRequest();
|
if (report.XmlPlayers.Any(p => !this.database.IsUsernameValid(p.Name))) return this.BadRequest();
|
||||||
|
|
||||||
report.Bounds = JsonSerializer.Serialize(report.XmlBounds.Rect, typeof(Rectangle));
|
GriefReportEntity reportEntity = GameGriefReport.ConvertToEntity(report);
|
||||||
report.Players = JsonSerializer.Serialize(report.XmlPlayers, typeof(ReportPlayer[]));
|
|
||||||
report.Timestamp = TimeHelper.TimestampMillis;
|
|
||||||
report.ReportingPlayerId = token.UserId;
|
|
||||||
|
|
||||||
this.database.Reports.Add(report);
|
reportEntity.Bounds = JsonSerializer.Serialize(report.XmlBounds.Rect, typeof(Rectangle));
|
||||||
|
reportEntity.Players = JsonSerializer.Serialize(report.XmlPlayers, typeof(ReportPlayer[]));
|
||||||
|
reportEntity.Timestamp = TimeHelper.TimestampMillis;
|
||||||
|
reportEntity.ReportingPlayerId = token.UserId;
|
||||||
|
|
||||||
|
this.database.Reports.Add(reportEntity);
|
||||||
await this.database.SaveChangesAsync();
|
await this.database.SaveChangesAsync();
|
||||||
|
|
||||||
await WebhookHelper.SendWebhook(
|
await WebhookHelper.SendWebhook(
|
||||||
title: "New grief report",
|
title: "New grief report",
|
||||||
description: $"Submitted by {username}\n" +
|
description: $"Submitted by {username}\n" +
|
||||||
$"To view it, click [here]({ServerConfiguration.Instance.ExternalUrl}/moderation/report/{report.ReportId}).",
|
$"To view it, click [here]({ServerConfiguration.Instance.ExternalUrl}/moderation/report/{reportEntity.ReportId}).",
|
||||||
dest: WebhookHelper.WebhookDestination.Moderation
|
dest: WebhookHelper.WebhookDestination.Moderation
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,12 @@ using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Files;
|
using LBPUnion.ProjectLighthouse.Files;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -34,17 +34,17 @@ public class PhotosController : ControllerBase
|
||||||
[HttpPost("uploadPhoto")]
|
[HttpPost("uploadPhoto")]
|
||||||
public async Task<IActionResult> UploadPhoto()
|
public async Task<IActionResult> UploadPhoto()
|
||||||
{
|
{
|
||||||
User? user = await this.database.UserFromGameToken(this.GetToken());
|
UserEntity? user = await this.database.UserFromGameToken(this.GetToken());
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
if (user.PhotosByMe >= ServerConfiguration.Instance.UserGeneratedContentLimits.PhotosQuota) return this.BadRequest();
|
if (user.GetUploadedPhotoCount(this.database) >= ServerConfiguration.Instance.UserGeneratedContentLimits.PhotosQuota) return this.BadRequest();
|
||||||
|
|
||||||
Photo? photo = await this.DeserializeBody<Photo>();
|
GamePhoto? photo = await this.DeserializeBody<GamePhoto>();
|
||||||
if (photo == null) return this.BadRequest();
|
if (photo == null) return this.BadRequest();
|
||||||
|
|
||||||
SanitizationHelper.SanitizeStringsInClass(photo);
|
SanitizationHelper.SanitizeStringsInClass(photo);
|
||||||
|
|
||||||
foreach (Photo p in this.database.Photos.Where(p => p.CreatorId == user.UserId))
|
foreach (PhotoEntity p in this.database.Photos.Where(p => p.CreatorId == user.UserId))
|
||||||
{
|
{
|
||||||
if (p.LargeHash == photo.LargeHash) return this.Ok(); // photo already uplaoded
|
if (p.LargeHash == photo.LargeHash) return this.Ok(); // photo already uplaoded
|
||||||
if (p.MediumHash == photo.MediumHash) return this.Ok();
|
if (p.MediumHash == photo.MediumHash) return this.Ok();
|
||||||
|
@ -52,20 +52,28 @@ public class PhotosController : ControllerBase
|
||||||
if (p.PlanHash == photo.PlanHash) return this.Ok();
|
if (p.PlanHash == photo.PlanHash) return this.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
photo.CreatorId = user.UserId;
|
PhotoEntity photoEntity = new()
|
||||||
photo.Creator = user;
|
{
|
||||||
|
CreatorId = user.UserId,
|
||||||
|
Creator = user,
|
||||||
|
SmallHash = photo.SmallHash,
|
||||||
|
MediumHash = photo.MediumHash,
|
||||||
|
LargeHash = photo.LargeHash,
|
||||||
|
PlanHash = photo.PlanHash,
|
||||||
|
Timestamp = photo.Timestamp,
|
||||||
|
};
|
||||||
|
|
||||||
if (photo.XmlLevelInfo?.RootLevel != null)
|
if (photo.LevelInfo?.RootLevel != null)
|
||||||
{
|
{
|
||||||
bool validLevel = false;
|
bool validLevel = false;
|
||||||
PhotoSlot photoSlot = photo.XmlLevelInfo;
|
PhotoSlot photoSlot = photo.LevelInfo;
|
||||||
if (photoSlot.SlotType is SlotType.Pod or SlotType.Local) photoSlot.SlotId = 0;
|
if (photoSlot.SlotType is SlotType.Pod or SlotType.Local) photoSlot.SlotId = 0;
|
||||||
switch (photoSlot.SlotType)
|
switch (photoSlot.SlotType)
|
||||||
{
|
{
|
||||||
case SlotType.User:
|
case SlotType.User:
|
||||||
{
|
{
|
||||||
// We'll grab the slot by the RootLevel and see what happens from here.
|
// We'll grab the slot by the RootLevel and see what happens from here.
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.Type == SlotType.User && s.ResourceCollection.Contains(photoSlot.RootLevel));
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.Type == SlotType.User && s.ResourceCollection.Contains(photoSlot.RootLevel));
|
||||||
if (slot == null) break;
|
if (slot == null) break;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(slot.RootLevel)) validLevel = true;
|
if (!string.IsNullOrEmpty(slot.RootLevel)) validLevel = true;
|
||||||
|
@ -76,7 +84,7 @@ public class PhotosController : ControllerBase
|
||||||
case SlotType.Local:
|
case SlotType.Local:
|
||||||
case SlotType.Developer:
|
case SlotType.Developer:
|
||||||
{
|
{
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.Type == photoSlot.SlotType && s.InternalSlotId == photoSlot.SlotId);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.Type == photoSlot.SlotType && s.InternalSlotId == photoSlot.SlotId);
|
||||||
if (slot != null)
|
if (slot != null)
|
||||||
photoSlot.SlotId = slot.SlotId;
|
photoSlot.SlotId = slot.SlotId;
|
||||||
else
|
else
|
||||||
|
@ -92,23 +100,23 @@ public class PhotosController : ControllerBase
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validLevel) photo.SlotId = photo.XmlLevelInfo.SlotId;
|
if (validLevel) photoEntity.SlotId = photoSlot.SlotId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (photo.XmlSubjects?.Count > 4) return this.BadRequest();
|
if (photo.Subjects?.Count > 4) return this.BadRequest();
|
||||||
|
|
||||||
if (photo.Timestamp > TimeHelper.Timestamp) photo.Timestamp = TimeHelper.Timestamp;
|
if (photo.Timestamp > TimeHelper.Timestamp) photo.Timestamp = TimeHelper.Timestamp;
|
||||||
|
|
||||||
this.database.Photos.Add(photo);
|
this.database.Photos.Add(photoEntity);
|
||||||
|
|
||||||
// Save to get photo ID for the PhotoSubject foreign keys
|
// Save to get photo ID for the PhotoSubject foreign keys
|
||||||
await this.database.SaveChangesAsync();
|
await this.database.SaveChangesAsync();
|
||||||
|
|
||||||
if (photo.XmlSubjects != null)
|
if (photo.Subjects != null)
|
||||||
{
|
{
|
||||||
// Check for duplicate photo subjects
|
// Check for duplicate photo subjects
|
||||||
List<string> subjectUserIds = new(4);
|
List<string> subjectUserIds = new(4);
|
||||||
foreach (PhotoSubject subject in photo.PhotoSubjects)
|
foreach (GamePhotoSubject subject in photo.Subjects)
|
||||||
{
|
{
|
||||||
if (subjectUserIds.Contains(subject.Username) && !string.IsNullOrEmpty(subject.Username))
|
if (subjectUserIds.Contains(subject.Username) && !string.IsNullOrEmpty(subject.Username))
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
|
@ -116,17 +124,23 @@ public class PhotosController : ControllerBase
|
||||||
subjectUserIds.Add(subject.Username);
|
subjectUserIds.Add(subject.Username);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (PhotoSubject subject in photo.XmlSubjects.Where(subject => !string.IsNullOrEmpty(subject.Username)))
|
foreach (GamePhotoSubject subject in photo.Subjects.Where(subject => !string.IsNullOrEmpty(subject.Username)))
|
||||||
{
|
{
|
||||||
subject.User = await this.database.Users.FirstOrDefaultAsync(u => u.Username == subject.Username);
|
subject.UserId = await this.database.Users.Where(u => u.Username == subject.Username)
|
||||||
|
.Select(u => u.UserId)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
if (subject.User == null) continue;
|
if (subject.UserId == 0) continue;
|
||||||
|
|
||||||
|
PhotoSubjectEntity subjectEntity = new()
|
||||||
|
{
|
||||||
|
PhotoId = photoEntity.PhotoId,
|
||||||
|
UserId = subject.UserId,
|
||||||
|
};
|
||||||
|
|
||||||
subject.UserId = subject.User.UserId;
|
|
||||||
subject.PhotoId = photo.PhotoId;
|
|
||||||
Logger.Debug($"Adding PhotoSubject (userid {subject.UserId}) to db", LogArea.Photos);
|
Logger.Debug($"Adding PhotoSubject (userid {subject.UserId}) to db", LogArea.Photos);
|
||||||
|
|
||||||
this.database.PhotoSubjects.Add(subject);
|
this.database.PhotoSubjects.Add(subjectEntity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,16 +169,15 @@ public class PhotosController : ControllerBase
|
||||||
|
|
||||||
if (slotType == "developer") id = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
if (slotType == "developer") id = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
||||||
|
|
||||||
List<Photo> photos = await this.database.Photos.Include(p => p.Creator)
|
List<GamePhoto> photos = await this.database.Photos.Include(p => p.PhotoSubjects)
|
||||||
.Include(p => p.PhotoSubjects)
|
|
||||||
.ThenInclude(ps => ps.User)
|
|
||||||
.Where(p => p.SlotId == id)
|
.Where(p => p.SlotId == id)
|
||||||
.OrderByDescending(s => s.Timestamp)
|
.OrderByDescending(s => s.Timestamp)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30))
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(p => GamePhoto.CreateFromEntity(p))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
string response = photos.Aggregate(string.Empty, (s, photo) => s + photo.Serialize(id, SlotHelper.ParseType(slotType)));
|
|
||||||
return this.Ok(LbpSerializer.StringElement("photos", response));
|
return this.Ok(new PhotoListResponse(photos));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("photos/by")]
|
[HttpGet("photos/by")]
|
||||||
|
@ -175,16 +188,14 @@ public class PhotosController : ControllerBase
|
||||||
int targetUserId = await this.database.UserIdFromUsername(user);
|
int targetUserId = await this.database.UserIdFromUsername(user);
|
||||||
if (targetUserId == 0) return this.NotFound();
|
if (targetUserId == 0) return this.NotFound();
|
||||||
|
|
||||||
List<Photo> photos = await this.database.Photos.Include(p => p.Creator)
|
List<GamePhoto> photos = await this.database.Photos.Include(p => p.PhotoSubjects)
|
||||||
.Include(p => p.PhotoSubjects)
|
|
||||||
.ThenInclude(ps => ps.User)
|
|
||||||
.Where(p => p.CreatorId == targetUserId)
|
.Where(p => p.CreatorId == targetUserId)
|
||||||
.OrderByDescending(s => s.Timestamp)
|
.OrderByDescending(s => s.Timestamp)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30))
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(p => GamePhoto.CreateFromEntity(p))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
string response = photos.Aggregate(string.Empty, (s, photo) => s + photo.Serialize());
|
return this.Ok(new PhotoListResponse(photos));
|
||||||
return this.Ok(LbpSerializer.StringElement("photos", response));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("photos/with")]
|
[HttpGet("photos/with")]
|
||||||
|
@ -195,32 +206,30 @@ public class PhotosController : ControllerBase
|
||||||
int targetUserId = await this.database.UserIdFromUsername(user);
|
int targetUserId = await this.database.UserIdFromUsername(user);
|
||||||
if (targetUserId == 0) return this.NotFound();
|
if (targetUserId == 0) return this.NotFound();
|
||||||
|
|
||||||
List<Photo> photos = await this.database.Photos.Include(p => p.Creator)
|
List<GamePhoto> photos = await this.database.Photos.Include(p => p.PhotoSubjects)
|
||||||
.Include(p => p.PhotoSubjects)
|
|
||||||
.ThenInclude(ps => ps.User)
|
|
||||||
.Where(p => p.PhotoSubjects.Any(ps => ps.UserId == targetUserId))
|
.Where(p => p.PhotoSubjects.Any(ps => ps.UserId == targetUserId))
|
||||||
.OrderByDescending(s => s.Timestamp)
|
.OrderByDescending(s => s.Timestamp)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30))
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(p => GamePhoto.CreateFromEntity(p))
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
string response = photos.Aggregate(string.Empty, (current, photo) => current + photo.Serialize());
|
|
||||||
|
|
||||||
return this.Ok(LbpSerializer.StringElement("photos", response));
|
return this.Ok(new PhotoListResponse(photos));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("deletePhoto/{id:int}")]
|
[HttpPost("deletePhoto/{id:int}")]
|
||||||
public async Task<IActionResult> DeletePhoto(int id)
|
public async Task<IActionResult> DeletePhoto(int id)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Photo? photo = await this.database.Photos.FirstOrDefaultAsync(p => p.PhotoId == id);
|
PhotoEntity? photo = await this.database.Photos.FirstOrDefaultAsync(p => p.PhotoId == id);
|
||||||
if (photo == null) return this.NotFound();
|
if (photo == null) return this.NotFound();
|
||||||
|
|
||||||
// If user isn't photo creator then check if they own the level
|
// If user isn't photo creator then check if they own the level
|
||||||
if (photo.CreatorId != token.UserId)
|
if (photo.CreatorId != token.UserId)
|
||||||
{
|
{
|
||||||
Slot? photoSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == photo.SlotId && s.Type == SlotType.User);
|
SlotEntity? photoSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == photo.SlotId && s.Type == SlotType.User);
|
||||||
if (photoSlot == null || photoSlot.CreatorId != token.UserId) return this.StatusCode(401, "");
|
if (photoSlot == null || photoSlot.CreatorId != token.UserId) return this.Unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<string> photoResources = new(){photo.LargeHash, photo.SmallHash, photo.MediumHash, photo.PlanHash,};
|
HashSet<string> photoResources = new(){photo.LargeHash, photo.SmallHash, photo.MediumHash, photo.PlanHash,};
|
||||||
|
|
|
@ -4,7 +4,6 @@ using System.IO.Pipelines;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Files;
|
using LBPUnion.ProjectLighthouse.Files;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Misc;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Misc;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Resources;
|
using LBPUnion.ProjectLighthouse.Types.Resources;
|
||||||
|
@ -22,7 +21,7 @@ public class ResourcesController : ControllerBase
|
||||||
{
|
{
|
||||||
|
|
||||||
[HttpPost("showModerated")]
|
[HttpPost("showModerated")]
|
||||||
public IActionResult ShowModerated() => this.Ok(LbpSerializer.BlankElement("resources"));
|
public IActionResult ShowModerated() => this.Ok(new ResourceList());
|
||||||
|
|
||||||
[HttpPost("filterResources")]
|
[HttpPost("filterResources")]
|
||||||
[HttpPost("showNotUploaded")]
|
[HttpPost("showNotUploaded")]
|
||||||
|
@ -31,11 +30,9 @@ public class ResourcesController : ControllerBase
|
||||||
ResourceList? resourceList = await this.DeserializeBody<ResourceList>();
|
ResourceList? resourceList = await this.DeserializeBody<ResourceList>();
|
||||||
if (resourceList?.Resources == null) return this.BadRequest();
|
if (resourceList?.Resources == null) return this.BadRequest();
|
||||||
|
|
||||||
string resources = resourceList.Resources.Where
|
resourceList.Resources = resourceList.Resources.Where(r => !FileHelper.ResourceExists(r)).ToArray();
|
||||||
(s => !FileHelper.ResourceExists(s))
|
|
||||||
.Aggregate("", (current, hash) => current + LbpSerializer.StringElement("resource", hash));
|
|
||||||
|
|
||||||
return this.Ok(LbpSerializer.StringElement("resources", resources));
|
return this.Ok(resourceList);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("r/{hash}")]
|
[HttpGet("r/{hash}")]
|
||||||
|
|
|
@ -3,13 +3,13 @@ using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -32,16 +32,18 @@ public class CollectionController : ControllerBase
|
||||||
[HttpGet("playlists/{playlistId:int}/slots")]
|
[HttpGet("playlists/{playlistId:int}/slots")]
|
||||||
public async Task<IActionResult> GetPlaylistSlots(int playlistId)
|
public async Task<IActionResult> GetPlaylistSlots(int playlistId)
|
||||||
{
|
{
|
||||||
Playlist? targetPlaylist = await this.database.Playlists.FirstOrDefaultAsync(p => p.PlaylistId == playlistId);
|
PlaylistEntity? targetPlaylist = await this.database.Playlists.FirstOrDefaultAsync(p => p.PlaylistId == playlistId);
|
||||||
if (targetPlaylist == null) return this.BadRequest();
|
if (targetPlaylist == null) return this.BadRequest();
|
||||||
|
|
||||||
IQueryable<Slot> slots = this.database.Slots.Include(s => s.Creator)
|
GameTokenEntity token = this.GetToken();
|
||||||
.Where(s => targetPlaylist.SlotIds.Contains(s.SlotId));
|
|
||||||
|
List<SlotBase> slots = await this.database.Slots.Where(s => targetPlaylist.SlotIds.Contains(s.SlotId))
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = Enumerable.Aggregate(slots, string.Empty, (current, slot) => current + slot.Serialize());
|
|
||||||
int total = targetPlaylist.SlotIds.Length;
|
int total = targetPlaylist.SlotIds.Length;
|
||||||
|
|
||||||
return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "total", total));
|
return this.Ok(new GenericSlotResponse(slots, total, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("playlists/{playlistId:int}")]
|
[HttpPost("playlists/{playlistId:int}")]
|
||||||
|
@ -50,9 +52,9 @@ public class CollectionController : ControllerBase
|
||||||
[HttpPost("playlists/{playlistId:int}/order_slots")]
|
[HttpPost("playlists/{playlistId:int}/order_slots")]
|
||||||
public async Task<IActionResult> UpdatePlaylist(int playlistId, int slotId)
|
public async Task<IActionResult> UpdatePlaylist(int playlistId, int slotId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Playlist? targetPlaylist = await this.database.Playlists.FirstOrDefaultAsync(p => p.PlaylistId == playlistId);
|
PlaylistEntity? targetPlaylist = await this.database.Playlists.FirstOrDefaultAsync(p => p.PlaylistId == playlistId);
|
||||||
if (targetPlaylist == null) return this.BadRequest();
|
if (targetPlaylist == null) return this.BadRequest();
|
||||||
|
|
||||||
if (token.UserId != targetPlaylist.CreatorId) return this.BadRequest();
|
if (token.UserId != targetPlaylist.CreatorId) return this.BadRequest();
|
||||||
|
@ -65,7 +67,7 @@ public class CollectionController : ControllerBase
|
||||||
return this.Ok(this.GetUserPlaylists(token.UserId));
|
return this.Ok(this.GetUserPlaylists(token.UserId));
|
||||||
}
|
}
|
||||||
|
|
||||||
Playlist? newPlaylist = await this.DeserializeBody<Playlist>("playlist", "levels");
|
GamePlaylist? newPlaylist = await this.DeserializeBody<GamePlaylist>("playlist", "levels");
|
||||||
|
|
||||||
if (newPlaylist == null) return this.BadRequest();
|
if (newPlaylist == null) return this.BadRequest();
|
||||||
|
|
||||||
|
@ -97,41 +99,48 @@ public class CollectionController : ControllerBase
|
||||||
return this.Ok(this.GetUserPlaylists(token.UserId));
|
return this.Ok(this.GetUserPlaylists(token.UserId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetUserPlaylists(int userId)
|
private async Task<PlaylistResponse> GetUserPlaylists(int userId)
|
||||||
{
|
{
|
||||||
string response = Enumerable.Aggregate(
|
List<GamePlaylist> playlists = await this.database.Playlists.Include(p => p.Creator)
|
||||||
this.database.Playlists.Include(p => p.Creator).Where(p => p.CreatorId == userId),
|
.Where(p => p.CreatorId == userId)
|
||||||
string.Empty,
|
.Select(p => GamePlaylist.CreateFromEntity(p))
|
||||||
(current, slot) => current + slot.Serialize());
|
.ToListAsync();
|
||||||
int total = this.database.Playlists.Count(p => p.CreatorId == userId);
|
int total = this.database.Playlists.Count(p => p.CreatorId == userId);
|
||||||
|
|
||||||
return LbpSerializer.TaggedStringElement("playlists", response, new Dictionary<string, object>
|
return new PlaylistResponse
|
||||||
{
|
{
|
||||||
{"total", total},
|
Playlists = playlists,
|
||||||
{"hint_start", total+1},
|
Total = total,
|
||||||
});
|
HintStart = total+1,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("playlists")]
|
[HttpPost("playlists")]
|
||||||
public async Task<IActionResult> CreatePlaylist()
|
public async Task<IActionResult> CreatePlaylist()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
int playlistCount = await this.database.Playlists.CountAsync(p => p.CreatorId == token.UserId);
|
int playlistCount = await this.database.Playlists.CountAsync(p => p.CreatorId == token.UserId);
|
||||||
|
|
||||||
if (playlistCount > ServerConfiguration.Instance.UserGeneratedContentLimits.ListsQuota) return this.BadRequest();
|
if (playlistCount > ServerConfiguration.Instance.UserGeneratedContentLimits.ListsQuota) return this.BadRequest();
|
||||||
|
|
||||||
Playlist? playlist = await this.DeserializeBody<Playlist>("playlist");
|
GamePlaylist? playlist = await this.DeserializeBody<GamePlaylist>("playlist");
|
||||||
|
|
||||||
if (playlist == null) return this.BadRequest();
|
if (playlist == null) return this.BadRequest();
|
||||||
|
|
||||||
playlist.CreatorId = token.UserId;
|
PlaylistEntity playlistEntity = new()
|
||||||
|
{
|
||||||
|
CreatorId = token.UserId,
|
||||||
|
Description = playlist.Description,
|
||||||
|
Name = playlist.Name,
|
||||||
|
SlotIds = playlist.SlotIds,
|
||||||
|
};
|
||||||
|
|
||||||
this.database.Playlists.Add(playlist);
|
this.database.Playlists.Add(playlistEntity);
|
||||||
|
|
||||||
await this.database.SaveChangesAsync();
|
await this.database.SaveChangesAsync();
|
||||||
|
|
||||||
return this.Ok(this.GetUserPlaylists(token.UserId));
|
return this.Ok(await this.GetUserPlaylists(token.UserId));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("user/{username}/playlists")]
|
[HttpGet("user/{username}/playlists")]
|
||||||
|
@ -140,101 +149,60 @@ public class CollectionController : ControllerBase
|
||||||
int targetUserId = await this.database.UserIdFromUsername(username);
|
int targetUserId = await this.database.UserIdFromUsername(username);
|
||||||
if (targetUserId == 0) return this.BadRequest();
|
if (targetUserId == 0) return this.BadRequest();
|
||||||
|
|
||||||
return this.Ok(this.GetUserPlaylists(targetUserId));
|
return this.Ok(await this.GetUserPlaylists(targetUserId));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("searches")]
|
[HttpGet("searches")]
|
||||||
[HttpGet("genres")]
|
[HttpGet("genres")]
|
||||||
public async Task<IActionResult> GenresAndSearches()
|
public async Task<IActionResult> GenresAndSearches()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
User? user = await this.database.UserFromGameToken(token);
|
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
string categoriesSerialized = CategoryHelper.Categories.Aggregate
|
List<GameCategory> categories = new();
|
||||||
(
|
|
||||||
string.Empty,
|
|
||||||
(current, category) =>
|
|
||||||
{
|
|
||||||
string serialized;
|
|
||||||
|
|
||||||
if (category is CategoryWithUser categoryWithUser) serialized = categoryWithUser.Serialize(this.database, user);
|
foreach (Category category in CategoryHelper.Categories.ToList())
|
||||||
else serialized = category.Serialize(this.database);
|
{
|
||||||
|
if(category is CategoryWithUser categoryWithUser) categories.Add(categoryWithUser.Serialize(this.database, user));
|
||||||
|
else categories.Add(category.Serialize(this.database));
|
||||||
|
}
|
||||||
|
|
||||||
return current + serialized;
|
return this.Ok(new CategoryListResponse(categories, CategoryHelper.Categories.Count, 0, 1));
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
categoriesSerialized += LbpSerializer.StringElement("text_search", LbpSerializer.StringElement("url", "/slots/searchLBP3"));
|
|
||||||
|
|
||||||
return this.Ok
|
|
||||||
(
|
|
||||||
LbpSerializer.TaggedStringElement
|
|
||||||
(
|
|
||||||
"categories",
|
|
||||||
categoriesSerialized,
|
|
||||||
new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"hint", ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hint_start", 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"total", CategoryHelper.Categories.Count
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("searches/{endpointName}")]
|
[HttpGet("searches/{endpointName}")]
|
||||||
public async Task<IActionResult> GetCategorySlots(string endpointName, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> GetCategorySlots(string endpointName, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
User? user = await this.database.UserFromGameToken(token);
|
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
Category? category = CategoryHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName);
|
Category? category = CategoryHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName);
|
||||||
if (category == null) return this.NotFound();
|
if (category == null) return this.NotFound();
|
||||||
|
|
||||||
Logger.Debug("Found category " + category, LogArea.Category);
|
Logger.Debug("Found category " + category, LogArea.Category);
|
||||||
|
|
||||||
List<Slot> slots;
|
List<SlotBase> slots;
|
||||||
int totalSlots;
|
int totalSlots;
|
||||||
|
|
||||||
if (category is CategoryWithUser categoryWithUser)
|
if (category is CategoryWithUser categoryWithUser)
|
||||||
{
|
{
|
||||||
slots = categoryWithUser.GetSlots(this.database, user, pageStart, pageSize).ToList();
|
slots = categoryWithUser.GetSlots(this.database, user, pageStart, pageSize)
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToList();
|
||||||
totalSlots = categoryWithUser.GetTotalSlots(this.database, user);
|
totalSlots = categoryWithUser.GetTotalSlots(this.database, user);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
slots = category.GetSlots(this.database, pageStart, pageSize).ToList();
|
slots = category.GetSlots(this.database, pageStart, pageSize)
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToList();
|
||||||
totalSlots = category.GetTotalSlots(this.database);
|
totalSlots = category.GetTotalSlots(this.database);
|
||||||
}
|
}
|
||||||
|
|
||||||
string slotsSerialized = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(token.GameVersion));
|
return this.Ok(new GenericSlotResponse("results", slots, totalSlots, pageStart + pageSize));
|
||||||
|
|
||||||
return this.Ok
|
|
||||||
(
|
|
||||||
LbpSerializer.TaggedStringElement
|
|
||||||
(
|
|
||||||
"results",
|
|
||||||
slotsSerialized,
|
|
||||||
new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"total", totalSlots
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hint_start", pageStart + pageSize
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,9 +43,9 @@ public class LevelTagsController : ControllerBase
|
||||||
[HttpPost("tag/{slotType}/{id:int}")]
|
[HttpPost("tag/{slotType}/{id:int}")]
|
||||||
public async Task<IActionResult> PostTag([FromForm(Name = "t")] string tagName, [FromRoute] string slotType, [FromRoute] int id)
|
public async Task<IActionResult> PostTag([FromForm(Name = "t")] string tagName, [FromRoute] string slotType, [FromRoute] int id)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.Where(s => s.SlotId == id).FirstOrDefaultAsync();
|
SlotEntity? slot = await this.database.Slots.Where(s => s.SlotId == id).FirstOrDefaultAsync();
|
||||||
if (slot == null) return this.BadRequest();
|
if (slot == null) return this.BadRequest();
|
||||||
|
|
||||||
if (!LabelHelper.IsValidTag(tagName)) return this.BadRequest();
|
if (!LabelHelper.IsValidTag(tagName)) return this.BadRequest();
|
||||||
|
@ -56,7 +56,7 @@ public class LevelTagsController : ControllerBase
|
||||||
|
|
||||||
if (slotType != "user") return this.BadRequest();
|
if (slotType != "user") return this.BadRequest();
|
||||||
|
|
||||||
RatedLevel? rating = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.UserId == token.UserId && r.SlotId == slot.SlotId);
|
RatedLevelEntity? rating = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.UserId == token.UserId && r.SlotId == slot.SlotId);
|
||||||
if (rating == null) return this.BadRequest();
|
if (rating == null) return this.BadRequest();
|
||||||
|
|
||||||
rating.TagLBP1 = tagName;
|
rating.TagLBP1 = tagName;
|
||||||
|
|
|
@ -2,12 +2,12 @@
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -43,35 +43,27 @@ public class ListController : ControllerBase
|
||||||
[FromQuery] string? dateFilterType = null
|
[FromQuery] string? dateFilterType = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
List<SlotBase> queuedLevels = await this.filterListByRequest(gameFilterType, dateFilterType, token.GameVersion, username, ListFilterType.Queue)
|
||||||
|
|
||||||
IEnumerable<Slot> queuedLevels = this.filterListByRequest(gameFilterType, dateFilterType, token.GameVersion, username, ListFilterType.Queue)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30))
|
.Take(Math.Min(pageSize, 30))
|
||||||
.AsEnumerable();
|
.Select(s => SlotBase.CreateFromEntity(s, token)).ToListAsync();
|
||||||
|
|
||||||
string response = queuedLevels.Aggregate(string.Empty, (current, q) => current + q.Serialize(gameVersion));
|
int total = await this.database.QueuedLevels.CountAsync(q => q.UserId == token.UserId);
|
||||||
|
int start = pageStart + Math.Min(pageSize, 30);
|
||||||
|
|
||||||
return this.Ok
|
return this.Ok(new GenericSlotResponse(queuedLevels, total, start));
|
||||||
(
|
|
||||||
LbpSerializer.TaggedStringElement("slots", response, new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{ "total", await this.database.QueuedLevels.CountAsync(q => q.UserId == token.UserId) },
|
|
||||||
{ "hint_start", pageStart + Math.Min(pageSize, 30) },
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("lolcatftw/add/user/{id:int}")]
|
[HttpPost("lolcatftw/add/user/{id:int}")]
|
||||||
public async Task<IActionResult> AddQueuedLevel(int id)
|
public async Task<IActionResult> AddQueuedLevel(int id)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (slot == null) return this.NotFound();
|
if (slot == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.QueueLevel(token.UserId, slot);
|
await this.database.QueueLevel(token.UserId, slot);
|
||||||
|
@ -82,9 +74,9 @@ public class ListController : ControllerBase
|
||||||
[HttpPost("lolcatftw/remove/user/{id:int}")]
|
[HttpPost("lolcatftw/remove/user/{id:int}")]
|
||||||
public async Task<IActionResult> RemoveQueuedLevel(int id)
|
public async Task<IActionResult> RemoveQueuedLevel(int id)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (slot == null) return this.NotFound();
|
if (slot == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.UnqueueLevel(token.UserId, slot);
|
await this.database.UnqueueLevel(token.UserId, slot);
|
||||||
|
@ -95,7 +87,7 @@ public class ListController : ControllerBase
|
||||||
[HttpPost("lolcatftw/clear")]
|
[HttpPost("lolcatftw/clear")]
|
||||||
public async Task<IActionResult> ClearQueuedLevels()
|
public async Task<IActionResult> ClearQueuedLevels()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
this.database.QueuedLevels.RemoveRange(this.database.QueuedLevels.Where(q => q.UserId == token.UserId));
|
this.database.QueuedLevels.RemoveRange(this.database.QueuedLevels.Where(q => q.UserId == token.UserId));
|
||||||
|
|
||||||
|
@ -120,30 +112,23 @@ public class ListController : ControllerBase
|
||||||
[FromQuery] string? dateFilterType = null
|
[FromQuery] string? dateFilterType = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
UserEntity? targetUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
|
if (targetUser == null) return this.Forbid();
|
||||||
|
|
||||||
User? targetUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
List<SlotBase> heartedLevels = await this.filterListByRequest(gameFilterType, dateFilterType, token.GameVersion, username, ListFilterType.FavouriteSlots)
|
||||||
if (targetUser == null) return this.StatusCode(403, "");
|
|
||||||
|
|
||||||
IEnumerable<Slot> heartedLevels = this.filterListByRequest(gameFilterType, dateFilterType, token.GameVersion, username, ListFilterType.FavouriteSlots)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30))
|
.Take(Math.Min(pageSize, 30))
|
||||||
.AsEnumerable();
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = heartedLevels.Aggregate(string.Empty, (current, q) => current + q.Serialize(gameVersion));
|
int total = await this.database.HeartedLevels.CountAsync(q => q.UserId == targetUser.UserId);
|
||||||
|
int start = pageStart + Math.Min(pageSize, 30);
|
||||||
|
|
||||||
return this.Ok
|
return this.Ok(new GenericSlotResponse("favouriteSlots", heartedLevels, total, start));
|
||||||
(
|
|
||||||
LbpSerializer.TaggedStringElement("favouriteSlots", response, new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{ "total", await this.database.HeartedLevels.CountAsync(q => q.UserId == targetUser.UserId) },
|
|
||||||
{ "hint_start", pageStart + Math.Min(pageSize, 30) },
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private const int FirstLbp2DeveloperSlotId = 124806; // This is the first known level slot GUID in LBP2. Feel free to change it if a lower one is found.
|
private const int FirstLbp2DeveloperSlotId = 124806; // This is the first known level slot GUID in LBP2. Feel free to change it if a lower one is found.
|
||||||
|
@ -151,13 +136,13 @@ public class ListController : ControllerBase
|
||||||
[HttpPost("favourite/slot/{slotType}/{id:int}")]
|
[HttpPost("favourite/slot/{slotType}/{id:int}")]
|
||||||
public async Task<IActionResult> AddFavouriteSlot(string slotType, int id)
|
public async Task<IActionResult> AddFavouriteSlot(string slotType, int id)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest();
|
if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest();
|
||||||
|
|
||||||
if (slotType == "developer") id = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
if (slotType == "developer") id = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (slot == null) return this.NotFound();
|
if (slot == null) return this.NotFound();
|
||||||
|
|
||||||
if (slotType == "developer")
|
if (slotType == "developer")
|
||||||
|
@ -174,13 +159,13 @@ public class ListController : ControllerBase
|
||||||
[HttpPost("unfavourite/slot/{slotType}/{id:int}")]
|
[HttpPost("unfavourite/slot/{slotType}/{id:int}")]
|
||||||
public async Task<IActionResult> RemoveFavouriteSlot(string slotType, int id)
|
public async Task<IActionResult> RemoveFavouriteSlot(string slotType, int id)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest();
|
if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest();
|
||||||
|
|
||||||
if (slotType == "developer") id = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
if (slotType == "developer") id = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (slot == null) return this.NotFound();
|
if (slot == null) return this.NotFound();
|
||||||
|
|
||||||
if (slotType == "developer")
|
if (slotType == "developer")
|
||||||
|
@ -204,29 +189,31 @@ public class ListController : ControllerBase
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
int targetUserId = await this.database.UserIdFromUsername(username);
|
int targetUserId = await this.database.UserIdFromUsername(username);
|
||||||
if (targetUserId == 0) return this.StatusCode(403, "");
|
if (targetUserId == 0) return this.Forbid();
|
||||||
|
|
||||||
IEnumerable<Playlist> heartedPlaylists = this.database.HeartedPlaylists.Where(p => p.UserId == targetUserId)
|
List<GamePlaylist> heartedPlaylists = await 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);
|
.Include(p => p.Playlist)
|
||||||
|
.Include(p => p.Playlist.Creator)
|
||||||
|
.OrderByDescending(p => p.HeartedPlaylistId)
|
||||||
|
.Select(p => p.Playlist)
|
||||||
|
.Select(p => GamePlaylist.CreateFromEntity(p))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = heartedPlaylists.Aggregate(string.Empty, (current, p) => current + p.Serialize());
|
int total = await this.database.HeartedPlaylists.CountAsync(p => p.UserId == targetUserId);
|
||||||
|
|
||||||
return this.Ok
|
return this.Ok(new GenericPlaylistResponse<GamePlaylist>("favouritePlaylists", heartedPlaylists)
|
||||||
(
|
{
|
||||||
LbpSerializer.TaggedStringElement("favouritePlaylists", response, new Dictionary<string, object>
|
Total = total,
|
||||||
{
|
HintStart = pageStart + Math.Min(pageSize, 30),
|
||||||
{ "total", this.database.HeartedPlaylists.Count(p => p.UserId == targetUserId) },
|
});
|
||||||
{ "hint_start", pageStart + Math.Min(pageSize, 30) },
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("favourite/playlist/{playlistId:int}")]
|
[HttpPost("favourite/playlist/{playlistId:int}")]
|
||||||
public async Task<IActionResult> AddFavouritePlaylist(int playlistId)
|
public async Task<IActionResult> AddFavouritePlaylist(int playlistId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Playlist? playlist = await this.database.Playlists.FirstOrDefaultAsync(s => s.PlaylistId == playlistId);
|
PlaylistEntity? playlist = await this.database.Playlists.FirstOrDefaultAsync(s => s.PlaylistId == playlistId);
|
||||||
if (playlist == null) return this.NotFound();
|
if (playlist == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.HeartPlaylist(token.UserId, playlist);
|
await this.database.HeartPlaylist(token.UserId, playlist);
|
||||||
|
@ -237,9 +224,9 @@ public class ListController : ControllerBase
|
||||||
[HttpPost("unfavourite/playlist/{playlistId:int}")]
|
[HttpPost("unfavourite/playlist/{playlistId:int}")]
|
||||||
public async Task<IActionResult> RemoveFavouritePlaylist(int playlistId)
|
public async Task<IActionResult> RemoveFavouritePlaylist(int playlistId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Playlist? playlist = await this.database.Playlists.FirstOrDefaultAsync(s => s.PlaylistId == playlistId);
|
PlaylistEntity? playlist = await this.database.Playlists.FirstOrDefaultAsync(s => s.PlaylistId == playlistId);
|
||||||
if (playlist == null) return this.NotFound();
|
if (playlist == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.UnheartPlaylist(token.UserId, playlist);
|
await this.database.UnheartPlaylist(token.UserId, playlist);
|
||||||
|
@ -256,40 +243,34 @@ public class ListController : ControllerBase
|
||||||
[HttpGet("favouriteUsers/{username}")]
|
[HttpGet("favouriteUsers/{username}")]
|
||||||
public async Task<IActionResult> GetFavouriteUsers(string username, [FromQuery] int pageSize, [FromQuery] int pageStart)
|
public async Task<IActionResult> GetFavouriteUsers(string username, [FromQuery] int pageSize, [FromQuery] int pageStart)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
User? targetUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
UserEntity? targetUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
if (targetUser == null) return this.StatusCode(403, "");
|
if (targetUser == null) return this.Forbid();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
IEnumerable<User> heartedProfiles = this.database.HeartedProfiles.Include
|
List<GameUser> heartedProfiles = await this.database.HeartedProfiles.Include
|
||||||
(q => q.HeartedUser)
|
(h => h.HeartedUser)
|
||||||
.OrderBy(q => q.HeartedProfileId)
|
.OrderBy(h => h.HeartedProfileId)
|
||||||
.Where(q => q.UserId == targetUser.UserId)
|
.Where(h => h.UserId == targetUser.UserId)
|
||||||
.Select(q => q.HeartedUser)
|
.Select(h => h.HeartedUser)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30))
|
.Take(Math.Min(pageSize, 30))
|
||||||
.AsEnumerable();
|
.Select(h => GameUser.CreateFromEntity(h, token.GameVersion))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = heartedProfiles.Aggregate(string.Empty, (current, u) => current + u.Serialize(token.GameVersion));
|
int total = await this.database.HeartedProfiles.CountAsync(h => h.UserId == targetUser.UserId);
|
||||||
|
|
||||||
return this.Ok
|
return this.Ok(new GenericUserResponse<GameUser>("favouriteUsers", heartedProfiles, total, pageStart + Math.Min(pageSize, 30)));
|
||||||
(
|
|
||||||
LbpSerializer.TaggedStringElement("favouriteUsers", response, new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{ "total", await this.database.HeartedProfiles.CountAsync(q => q.UserId == targetUser.UserId) },
|
|
||||||
{ "hint_start", pageStart + Math.Min(pageSize, 30) },
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("favourite/user/{username}")]
|
[HttpPost("favourite/user/{username}")]
|
||||||
public async Task<IActionResult> AddFavouriteUser(string username)
|
public async Task<IActionResult> AddFavouriteUser(string username)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
UserEntity? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
if (heartedUser == null) return this.NotFound();
|
if (heartedUser == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.HeartUser(token.UserId, heartedUser);
|
await this.database.HeartUser(token.UserId, heartedUser);
|
||||||
|
@ -300,9 +281,9 @@ public class ListController : ControllerBase
|
||||||
[HttpPost("unfavourite/user/{username}")]
|
[HttpPost("unfavourite/user/{username}")]
|
||||||
public async Task<IActionResult> RemoveFavouriteUser(string username)
|
public async Task<IActionResult> RemoveFavouriteUser(string username)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
UserEntity? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
if (heartedUser == null) return this.NotFound();
|
if (heartedUser == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.UnheartUser(token.UserId, heartedUser);
|
await this.database.UnheartUser(token.UserId, heartedUser);
|
||||||
|
@ -313,7 +294,7 @@ public class ListController : ControllerBase
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Filtering
|
#region Filtering
|
||||||
enum ListFilterType // used to collapse code that would otherwise be two separate functions
|
internal enum ListFilterType // used to collapse code that would otherwise be two separate functions
|
||||||
{
|
{
|
||||||
Queue,
|
Queue,
|
||||||
FavouriteSlots,
|
FavouriteSlots,
|
||||||
|
@ -337,7 +318,7 @@ public class ListController : ControllerBase
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private IQueryable<Slot> filterListByRequest(string? gameFilterType, string? dateFilterType, GameVersion version, string username, ListFilterType filterType)
|
private IQueryable<SlotEntity> filterListByRequest(string? gameFilterType, string? dateFilterType, GameVersion version, string username, ListFilterType filterType)
|
||||||
{
|
{
|
||||||
if (version is GameVersion.LittleBigPlanetPSP or GameVersion.Unknown)
|
if (version is GameVersion.LittleBigPlanetPSP or GameVersion.Unknown)
|
||||||
{
|
{
|
||||||
|
@ -358,7 +339,7 @@ public class ListController : ControllerBase
|
||||||
|
|
||||||
if (filterType == ListFilterType.Queue)
|
if (filterType == ListFilterType.Queue)
|
||||||
{
|
{
|
||||||
IQueryable<QueuedLevel> whereQueuedLevels;
|
IQueryable<QueuedLevelEntity> whereQueuedLevels;
|
||||||
|
|
||||||
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
||||||
if (gameFilterType == "both")
|
if (gameFilterType == "both")
|
||||||
|
@ -374,7 +355,7 @@ public class ListController : ControllerBase
|
||||||
return whereQueuedLevels.OrderByDescending(q => q.QueuedLevelId).Include(q => q.Slot.Creator).Select(q => q.Slot).ByGameVersion(gameVersion, false, false, true);
|
return whereQueuedLevels.OrderByDescending(q => q.QueuedLevelId).Include(q => q.Slot.Creator).Select(q => q.Slot).ByGameVersion(gameVersion, false, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
IQueryable<HeartedLevel> whereHeartedLevels;
|
IQueryable<HeartedLevelEntity> whereHeartedLevels;
|
||||||
|
|
||||||
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
||||||
if (gameFilterType == "both")
|
if (gameFilterType == "both")
|
||||||
|
|
|
@ -5,12 +5,12 @@ using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Files;
|
using LBPUnion.ProjectLighthouse.Files;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Resources;
|
using LBPUnion.ProjectLighthouse.Types.Resources;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -37,12 +37,12 @@ public class PublishController : ControllerBase
|
||||||
[HttpPost("startPublish")]
|
[HttpPost("startPublish")]
|
||||||
public async Task<IActionResult> StartPublish()
|
public async Task<IActionResult> StartPublish()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
User? user = await this.database.UserFromGameToken(token);
|
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
Slot? slot = await this.DeserializeBody<Slot>();
|
GameUserSlot? slot = await this.DeserializeBody<GameUserSlot>();
|
||||||
if (slot == null)
|
if (slot == null)
|
||||||
{
|
{
|
||||||
Logger.Warn("Rejecting level upload, slot is null", LogArea.Publish);
|
Logger.Warn("Rejecting level upload, slot is null", LogArea.Publish);
|
||||||
|
@ -55,7 +55,7 @@ public class PublishController : ControllerBase
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(slot.ResourceCollection)) slot.ResourceCollection = slot.RootLevel;
|
if (slot.Resources?.Length == 0) slot.Resources = new[]{slot.RootLevel,};
|
||||||
|
|
||||||
if (slot.Resources == null)
|
if (slot.Resources == null)
|
||||||
{
|
{
|
||||||
|
@ -63,10 +63,12 @@ public class PublishController : ControllerBase
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int usedSlots = await this.database.Slots.CountAsync(s => s.CreatorId == token.UserId && s.GameVersion == token.GameVersion);
|
||||||
|
|
||||||
// Republish logic
|
// Republish logic
|
||||||
if (slot.SlotId != 0)
|
if (slot.SlotId != 0)
|
||||||
{
|
{
|
||||||
Slot? oldSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slot.SlotId);
|
SlotEntity? oldSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slot.SlotId);
|
||||||
if (oldSlot == null)
|
if (oldSlot == null)
|
||||||
{
|
{
|
||||||
Logger.Warn("Rejecting level republish, could not find old slot", LogArea.Publish);
|
Logger.Warn("Rejecting level republish, could not find old slot", LogArea.Publish);
|
||||||
|
@ -78,18 +80,18 @@ public class PublishController : ControllerBase
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (user.GetUsedSlotsForGame(token.GameVersion) > user.EntitledSlots)
|
else if (usedSlots > user.EntitledSlots)
|
||||||
{
|
{
|
||||||
return this.StatusCode(403, "");
|
return this.Forbid();
|
||||||
}
|
}
|
||||||
|
|
||||||
slot.ResourceCollection += "," + slot.IconHash; // tells LBP to upload icon after we process resources here
|
HashSet<string> resources = new(slot.Resources)
|
||||||
|
{
|
||||||
|
slot.IconHash,
|
||||||
|
};
|
||||||
|
resources = resources.Where(hash => !FileHelper.ResourceExists(hash)).ToHashSet();
|
||||||
|
|
||||||
string resources = slot.Resources.Where
|
return this.Ok(new SlotResourceResponse(resources.ToList()));
|
||||||
(hash => !FileHelper.ResourceExists(hash))
|
|
||||||
.Aggregate("", (current, hash) => current + LbpSerializer.StringElement("resource", hash));
|
|
||||||
|
|
||||||
return this.Ok(LbpSerializer.TaggedStringElement("slot", resources, "type", "user"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -98,12 +100,12 @@ public class PublishController : ControllerBase
|
||||||
[HttpPost("publish")]
|
[HttpPost("publish")]
|
||||||
public async Task<IActionResult> Publish([FromQuery] string? game)
|
public async Task<IActionResult> Publish([FromQuery] string? game)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
User? user = await this.database.UserFromGameToken(token);
|
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
Slot? slot = await this.DeserializeBody<Slot>();
|
GameUserSlot? slot = await this.DeserializeBody<GameUserSlot>();
|
||||||
|
|
||||||
if (slot == null)
|
if (slot == null)
|
||||||
{
|
{
|
||||||
|
@ -111,6 +113,12 @@ public class PublishController : ControllerBase
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (slot.Resources == null)
|
||||||
|
{
|
||||||
|
Logger.Warn("Rejecting level upload, resource list is null", LogArea.Publish);
|
||||||
|
return this.BadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
slot.Description = CensorHelper.FilterMessage(slot.Description);
|
slot.Description = CensorHelper.FilterMessage(slot.Description);
|
||||||
|
|
||||||
if (slot.Description.Length > 512)
|
if (slot.Description.Length > 512)
|
||||||
|
@ -168,7 +176,7 @@ public class PublishController : ControllerBase
|
||||||
// Republish logic
|
// Republish logic
|
||||||
if (slot.SlotId != 0)
|
if (slot.SlotId != 0)
|
||||||
{
|
{
|
||||||
Slot? oldSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slot.SlotId);
|
SlotEntity? oldSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slot.SlotId);
|
||||||
if (oldSlot == null)
|
if (oldSlot == null)
|
||||||
{
|
{
|
||||||
Logger.Warn("Rejecting level republish, wasn't able to find old slot", LogArea.Publish);
|
Logger.Warn("Rejecting level republish, wasn't able to find old slot", LogArea.Publish);
|
||||||
|
@ -190,36 +198,32 @@ public class PublishController : ControllerBase
|
||||||
// Delete the useless rootLevel that lbp3 just uploaded
|
// Delete the useless rootLevel that lbp3 just uploaded
|
||||||
if (slotVersion == GameVersion.LittleBigPlanet3)
|
if (slotVersion == GameVersion.LittleBigPlanet3)
|
||||||
FileHelper.DeleteResource(slot.RootLevel);
|
FileHelper.DeleteResource(slot.RootLevel);
|
||||||
|
else
|
||||||
slot.GameVersion = oldSlot.GameVersion;
|
{
|
||||||
slot.RootLevel = oldSlot.RootLevel;
|
oldSlot.GameVersion = slot.GameVersion;
|
||||||
slot.ResourceCollection = oldSlot.ResourceCollection;
|
oldSlot.RootLevel = slot.RootLevel;
|
||||||
|
oldSlot.Resources = slot.Resources;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
slot.CreatorId = oldSlot.CreatorId;
|
oldSlot.Name = slot.Name;
|
||||||
slot.SlotId = oldSlot.SlotId;
|
oldSlot.Description = slot.Description;
|
||||||
|
oldSlot.Location = slot.Location;
|
||||||
|
oldSlot.IconHash = slot.IconHash;
|
||||||
|
oldSlot.BackgroundHash = slot.BackgroundHash;
|
||||||
|
oldSlot.AuthorLabels = slot.AuthorLabels;
|
||||||
|
oldSlot.Shareable = slot.IsShareable;
|
||||||
|
oldSlot.Resources = slot.Resources;
|
||||||
|
oldSlot.InitiallyLocked = slot.InitiallyLocked;
|
||||||
|
oldSlot.Lbp1Only = slot.IsLbp1Only;
|
||||||
|
oldSlot.IsAdventurePlanet = slot.IsAdventurePlanet;
|
||||||
|
oldSlot.LevelType = slot.LevelType;
|
||||||
|
oldSlot.SubLevel = slot.IsSubLevel;
|
||||||
|
oldSlot.MoveRequired = slot.IsMoveRequired;
|
||||||
|
oldSlot.CrossControllerRequired = slot.IsCrossControlRequired;
|
||||||
|
|
||||||
#region Set plays
|
oldSlot.LastUpdated = TimeHelper.TimestampMillis;
|
||||||
|
|
||||||
slot.PlaysLBP1 = oldSlot.PlaysLBP1;
|
|
||||||
slot.PlaysLBP1Complete = oldSlot.PlaysLBP1Complete;
|
|
||||||
slot.PlaysLBP1Unique = oldSlot.PlaysLBP1Unique;
|
|
||||||
|
|
||||||
slot.PlaysLBP2 = oldSlot.PlaysLBP2;
|
|
||||||
slot.PlaysLBP2Complete = oldSlot.PlaysLBP2Complete;
|
|
||||||
slot.PlaysLBP2Unique = oldSlot.PlaysLBP2Unique;
|
|
||||||
|
|
||||||
slot.PlaysLBP3 = oldSlot.PlaysLBP3;
|
|
||||||
slot.PlaysLBP3Complete = oldSlot.PlaysLBP3Complete;
|
|
||||||
slot.PlaysLBP3Unique = oldSlot.PlaysLBP3Unique;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
slot.FirstUploaded = oldSlot.FirstUploaded;
|
|
||||||
slot.LastUpdated = TimeHelper.TimestampMillis;
|
|
||||||
|
|
||||||
slot.TeamPick = oldSlot.TeamPick;
|
|
||||||
|
|
||||||
if (slot.MinimumPlayers == 0 || slot.MaximumPlayers == 0)
|
if (slot.MinimumPlayers == 0 || slot.MaximumPlayers == 0)
|
||||||
{
|
{
|
||||||
|
@ -227,20 +231,23 @@ public class PublishController : ControllerBase
|
||||||
slot.MaximumPlayers = 4;
|
slot.MaximumPlayers = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
slot.MinimumPlayers = Math.Clamp(slot.MinimumPlayers, 1, 4);
|
oldSlot.MinimumPlayers = Math.Clamp(slot.MinimumPlayers, 1, 4);
|
||||||
slot.MaximumPlayers = Math.Clamp(slot.MaximumPlayers, 1, 4);
|
oldSlot.MaximumPlayers = Math.Clamp(slot.MaximumPlayers, 1, 4);
|
||||||
|
|
||||||
this.database.Entry(oldSlot).CurrentValues.SetValues(slot);
|
|
||||||
await this.database.SaveChangesAsync();
|
await this.database.SaveChangesAsync();
|
||||||
return this.Ok(oldSlot.Serialize(token.GameVersion));
|
return this.Ok(SlotBase.CreateFromEntity(oldSlot, this.GetToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.GetUsedSlotsForGame(slotVersion) > user.EntitledSlots)
|
int usedSlots = await this.database.Slots.CountAsync(s => s.CreatorId == token.UserId && s.GameVersion == slotVersion);
|
||||||
|
|
||||||
|
if (usedSlots > user.EntitledSlots)
|
||||||
{
|
{
|
||||||
Logger.Warn("Rejecting level upload, too many published slots", LogArea.Publish);
|
Logger.Warn("Rejecting level upload, too many published slots", LogArea.Publish);
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SlotEntity slotEntity = SlotBase.ConvertToEntity(slot);
|
||||||
|
|
||||||
slot.CreatorId = user.UserId;
|
slot.CreatorId = user.UserId;
|
||||||
slot.FirstUploaded = TimeHelper.TimestampMillis;
|
slot.FirstUploaded = TimeHelper.TimestampMillis;
|
||||||
slot.LastUpdated = TimeHelper.TimestampMillis;
|
slot.LastUpdated = TimeHelper.TimestampMillis;
|
||||||
|
@ -254,7 +261,7 @@ public class PublishController : ControllerBase
|
||||||
slot.MinimumPlayers = Math.Clamp(slot.MinimumPlayers, 1, 4);
|
slot.MinimumPlayers = Math.Clamp(slot.MinimumPlayers, 1, 4);
|
||||||
slot.MaximumPlayers = Math.Clamp(slot.MaximumPlayers, 1, 4);
|
slot.MaximumPlayers = Math.Clamp(slot.MaximumPlayers, 1, 4);
|
||||||
|
|
||||||
this.database.Slots.Add(slot);
|
this.database.Slots.Add(slotEntity);
|
||||||
await this.database.SaveChangesAsync();
|
await this.database.SaveChangesAsync();
|
||||||
|
|
||||||
if (user.LevelVisibility == PrivacyType.All)
|
if (user.LevelVisibility == PrivacyType.All)
|
||||||
|
@ -265,18 +272,18 @@ public class PublishController : ControllerBase
|
||||||
|
|
||||||
Logger.Success($"Successfully published level {slot.Name} (id: {slot.SlotId}) by {user.Username} (id: {user.UserId})", LogArea.Publish);
|
Logger.Success($"Successfully published level {slot.Name} (id: {slot.SlotId}) by {user.Username} (id: {user.UserId})", LogArea.Publish);
|
||||||
|
|
||||||
return this.Ok(slot.Serialize(token.GameVersion));
|
return this.Ok(SlotBase.CreateFromEntity(slotEntity, this.GetToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("unpublish/{id:int}")]
|
[HttpPost("unpublish/{id:int}")]
|
||||||
public async Task<IActionResult> Unpublish(int id)
|
public async Task<IActionResult> Unpublish(int id)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (slot == null) return this.NotFound();
|
if (slot == null) return this.NotFound();
|
||||||
|
|
||||||
if (slot.CreatorId != token.UserId) return this.StatusCode(403, "");
|
if (slot.CreatorId != token.UserId) return this.Forbid();
|
||||||
|
|
||||||
this.database.Slots.Remove(slot);
|
this.database.Slots.Remove(slot);
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -30,15 +30,15 @@ public class ReviewController : ControllerBase
|
||||||
[HttpPost("rate/user/{slotId:int}")]
|
[HttpPost("rate/user/{slotId:int}")]
|
||||||
public async Task<IActionResult> Rate(int slotId, [FromQuery] int rating)
|
public async Task<IActionResult> Rate(int slotId, [FromQuery] int rating)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.Include(s => s.Creator).FirstOrDefaultAsync(s => s.SlotId == slotId);
|
SlotEntity? slot = await this.database.Slots.Include(s => s.Creator).FirstOrDefaultAsync(s => s.SlotId == slotId);
|
||||||
if (slot == null) return this.StatusCode(403, "");
|
if (slot == null) return this.Forbid();
|
||||||
|
|
||||||
RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == token.UserId);
|
RatedLevelEntity? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == token.UserId);
|
||||||
if (ratedLevel == null)
|
if (ratedLevel == null)
|
||||||
{
|
{
|
||||||
ratedLevel = new RatedLevel
|
ratedLevel = new RatedLevelEntity
|
||||||
{
|
{
|
||||||
SlotId = slotId,
|
SlotId = slotId,
|
||||||
UserId = token.UserId,
|
UserId = token.UserId,
|
||||||
|
@ -59,15 +59,15 @@ public class ReviewController : ControllerBase
|
||||||
[HttpPost("dpadrate/user/{slotId:int}")]
|
[HttpPost("dpadrate/user/{slotId:int}")]
|
||||||
public async Task<IActionResult> DPadRate(int slotId, [FromQuery] int rating)
|
public async Task<IActionResult> DPadRate(int slotId, [FromQuery] int rating)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
||||||
if (slot == null) return this.StatusCode(403, "");
|
if (slot == null) return this.Forbid();
|
||||||
|
|
||||||
RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == token.UserId);
|
RatedLevelEntity? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == token.UserId);
|
||||||
if (ratedLevel == null)
|
if (ratedLevel == null)
|
||||||
{
|
{
|
||||||
ratedLevel = new RatedLevel
|
ratedLevel = new RatedLevelEntity
|
||||||
{
|
{
|
||||||
SlotId = slotId,
|
SlotId = slotId,
|
||||||
UserId = token.UserId,
|
UserId = token.UserId,
|
||||||
|
@ -79,7 +79,7 @@ public class ReviewController : ControllerBase
|
||||||
|
|
||||||
ratedLevel.Rating = Math.Clamp(rating, -1, 1);
|
ratedLevel.Rating = Math.Clamp(rating, -1, 1);
|
||||||
|
|
||||||
Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == token.UserId);
|
ReviewEntity? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == token.UserId);
|
||||||
if (review != null) review.Thumb = ratedLevel.Rating;
|
if (review != null) review.Thumb = ratedLevel.Rating;
|
||||||
|
|
||||||
await this.database.SaveChangesAsync();
|
await this.database.SaveChangesAsync();
|
||||||
|
@ -90,20 +90,20 @@ public class ReviewController : ControllerBase
|
||||||
[HttpPost("postReview/user/{slotId:int}")]
|
[HttpPost("postReview/user/{slotId:int}")]
|
||||||
public async Task<IActionResult> PostReview(int slotId)
|
public async Task<IActionResult> PostReview(int slotId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
Review? newReview = await this.DeserializeBody<Review>();
|
GameReview? newReview = await this.DeserializeBody<GameReview>();
|
||||||
if (newReview == null) return this.BadRequest();
|
if (newReview == null) return this.BadRequest();
|
||||||
|
|
||||||
newReview.Text = CensorHelper.FilterMessage(newReview.Text);
|
newReview.Text = CensorHelper.FilterMessage(newReview.Text);
|
||||||
|
|
||||||
if (newReview.Text.Length > 512) return this.BadRequest();
|
if (newReview.Text.Length > 512) return this.BadRequest();
|
||||||
|
|
||||||
Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == token.UserId);
|
ReviewEntity? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == token.UserId);
|
||||||
|
|
||||||
if (review == null)
|
if (review == null)
|
||||||
{
|
{
|
||||||
review = new Review
|
review = new ReviewEntity
|
||||||
{
|
{
|
||||||
SlotId = slotId,
|
SlotId = slotId,
|
||||||
ReviewerId = token.UserId,
|
ReviewerId = token.UserId,
|
||||||
|
@ -121,10 +121,10 @@ public class ReviewController : ControllerBase
|
||||||
review.Timestamp = TimeHelper.TimestampMillis;
|
review.Timestamp = TimeHelper.TimestampMillis;
|
||||||
|
|
||||||
// sometimes the game posts/updates a review rating without also calling dpadrate/user/etc (why??)
|
// sometimes the game posts/updates a review rating without also calling dpadrate/user/etc (why??)
|
||||||
RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == token.UserId);
|
RatedLevelEntity? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == token.UserId);
|
||||||
if (ratedLevel == null)
|
if (ratedLevel == null)
|
||||||
{
|
{
|
||||||
ratedLevel = new RatedLevel
|
ratedLevel = new RatedLevelEntity
|
||||||
{
|
{
|
||||||
SlotId = slotId,
|
SlotId = slotId,
|
||||||
UserId = token.UserId,
|
UserId = token.UserId,
|
||||||
|
@ -144,58 +144,32 @@ public class ReviewController : ControllerBase
|
||||||
[HttpGet("reviewsFor/user/{slotId:int}")]
|
[HttpGet("reviewsFor/user/{slotId:int}")]
|
||||||
public async Task<IActionResult> ReviewsFor(int slotId, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10)
|
public async Task<IActionResult> ReviewsFor(int slotId, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
GameVersion gameVersion = token.GameVersion;
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
||||||
if (slot == null) return this.BadRequest();
|
if (slot == null) return this.BadRequest();
|
||||||
|
|
||||||
IQueryable<Review?> reviews = this.database.Reviews.ByGameVersion(gameVersion, true)
|
List<GameReview> reviews = await this.database.Reviews.ByGameVersion(gameVersion, true)
|
||||||
.Where(r => r.SlotId == slotId)
|
.Where(r => r.SlotId == slotId)
|
||||||
.Include(r => r.Reviewer)
|
|
||||||
.Include(r => r.Slot)
|
|
||||||
.OrderByDescending(r => r.ThumbsUp - r.ThumbsDown)
|
.OrderByDescending(r => r.ThumbsUp - r.ThumbsDown)
|
||||||
.ThenByDescending(r => r.Timestamp)
|
.ThenByDescending(r => r.Timestamp)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(pageSize);
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(r => GameReview.CreateFromEntity(r, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
List<Review?> reviewList = reviews.ToList();
|
|
||||||
|
|
||||||
string inner = reviewList.Aggregate
|
return this.Ok(new ReviewResponse(reviews, reviews.LastOrDefault()?.Timestamp ?? TimeHelper.TimestampMillis, pageStart + Math.Min(pageSize, 30)));
|
||||||
(
|
|
||||||
string.Empty,
|
|
||||||
(current, review) =>
|
|
||||||
{
|
|
||||||
if (review == null) return current;
|
|
||||||
|
|
||||||
RatedReview? yourThumb = this.database.RatedReviews.FirstOrDefault(r => r.ReviewId == review.ReviewId && r.UserId == token.UserId);
|
|
||||||
return current + review.Serialize(yourThumb);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
string response = LbpSerializer.TaggedStringElement
|
|
||||||
(
|
|
||||||
"reviews",
|
|
||||||
inner,
|
|
||||||
new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"hint_start", pageStart + pageSize
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hint", reviewList.LastOrDefault()?.Timestamp ?? 0
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return this.Ok(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("reviewsBy/{username}")]
|
[HttpGet("reviewsBy/{username}")]
|
||||||
public async Task<IActionResult> ReviewsBy(string username, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10)
|
public async Task<IActionResult> ReviewsBy(string username, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
|
@ -205,61 +179,32 @@ public class ReviewController : ControllerBase
|
||||||
|
|
||||||
if (targetUserId == 0) return this.BadRequest();
|
if (targetUserId == 0) return this.BadRequest();
|
||||||
|
|
||||||
IEnumerable<Review?> reviews = this.database.Reviews.ByGameVersion(gameVersion, true)
|
List<GameReview> reviews = await this.database.Reviews.ByGameVersion(gameVersion, true)
|
||||||
.Include(r => r.Reviewer)
|
|
||||||
.Include(r => r.Slot)
|
|
||||||
.Where(r => r.ReviewerId == targetUserId)
|
.Where(r => r.ReviewerId == targetUserId)
|
||||||
.OrderByDescending(r => r.Timestamp)
|
.OrderByDescending(r => r.Timestamp)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(pageSize);
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(r => GameReview.CreateFromEntity(r, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
List<Review?> reviewList = reviews.ToList();
|
return this.Ok(new ReviewResponse(reviews, reviews.LastOrDefault()?.Timestamp ?? TimeHelper.TimestampMillis, pageStart));
|
||||||
|
|
||||||
string inner = reviewList.Aggregate
|
|
||||||
(
|
|
||||||
string.Empty,
|
|
||||||
(current, review) =>
|
|
||||||
{
|
|
||||||
if (review == null) return current;
|
|
||||||
|
|
||||||
RatedReview? ratedReview = this.database.RatedReviews.FirstOrDefault(r => r.ReviewId == review.ReviewId && r.UserId == token.UserId);
|
|
||||||
return current + review.Serialize(ratedReview);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
string response = LbpSerializer.TaggedStringElement
|
|
||||||
(
|
|
||||||
"reviews",
|
|
||||||
inner,
|
|
||||||
new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"hint_start", pageStart
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hint", reviewList.LastOrDefault()?.Timestamp ?? 0 // Seems to be the timestamp of oldest
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return this.Ok(response);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("rateReview/user/{slotId:int}/{username}")]
|
[HttpPost("rateReview/user/{slotId:int}/{username}")]
|
||||||
public async Task<IActionResult> RateReview(int slotId, string username, [FromQuery] int rating = 0)
|
public async Task<IActionResult> RateReview(int slotId, string username, [FromQuery] int rating = 0)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
int reviewerId = await this.database.UserIdFromUsername(username);
|
int reviewerId = await this.database.UserIdFromUsername(username);
|
||||||
if (reviewerId == 0) return this.StatusCode(400, "");
|
if (reviewerId == 0) return this.BadRequest();
|
||||||
|
|
||||||
Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == reviewerId);
|
ReviewEntity? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == reviewerId);
|
||||||
if (review == null) return this.StatusCode(400, "");
|
if (review == null) return this.BadRequest();
|
||||||
|
|
||||||
RatedReview? ratedReview = await this.database.RatedReviews.FirstOrDefaultAsync(r => r.ReviewId == review.ReviewId && r.UserId == token.UserId);
|
RatedReviewEntity? ratedReview = await this.database.RatedReviews.FirstOrDefaultAsync(r => r.ReviewId == review.ReviewId && r.UserId == token.UserId);
|
||||||
if (ratedReview == null)
|
if (ratedReview == null)
|
||||||
{
|
{
|
||||||
ratedReview = new RatedReview
|
ratedReview = new RatedReviewEntity
|
||||||
{
|
{
|
||||||
ReviewId = review.ReviewId,
|
ReviewId = review.ReviewId,
|
||||||
UserId = token.UserId,
|
UserId = token.UserId,
|
||||||
|
@ -301,18 +246,18 @@ public class ReviewController : ControllerBase
|
||||||
[HttpPost("deleteReview/user/{slotId:int}/{username}")]
|
[HttpPost("deleteReview/user/{slotId:int}/{username}")]
|
||||||
public async Task<IActionResult> DeleteReview(int slotId, string username)
|
public async Task<IActionResult> DeleteReview(int slotId, string username)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
int creatorId = await this.database.Slots.Where(s => s.SlotId == slotId).Select(s => s.CreatorId).FirstOrDefaultAsync();
|
int creatorId = await this.database.Slots.Where(s => s.SlotId == slotId).Select(s => s.CreatorId).FirstOrDefaultAsync();
|
||||||
if (creatorId == 0) return this.StatusCode(400, "");
|
if (creatorId == 0) return this.BadRequest();
|
||||||
|
|
||||||
if (token.UserId != creatorId) return this.StatusCode(403, "");
|
if (token.UserId != creatorId) return this.Unauthorized();
|
||||||
|
|
||||||
int reviewerId = await this.database.UserIdFromUsername(username);
|
int reviewerId = await this.database.UserIdFromUsername(username);
|
||||||
if (reviewerId == 0) return this.StatusCode(400, "");
|
if (reviewerId == 0) return this.BadRequest();
|
||||||
|
|
||||||
Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == reviewerId);
|
ReviewEntity? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == reviewerId);
|
||||||
if (review == null) return this.StatusCode(400, "");
|
if (review == null) return this.BadRequest();
|
||||||
|
|
||||||
review.Deleted = true;
|
review.Deleted = true;
|
||||||
review.DeletedBy = DeletedBy.LevelAuthor;
|
review.DeletedBy = DeletedBy.LevelAuthor;
|
||||||
|
|
|
@ -4,12 +4,12 @@ using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.StorableLists.Stores;
|
using LBPUnion.ProjectLighthouse.StorableLists.Stores;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -34,7 +34,7 @@ public class ScoreController : ControllerBase
|
||||||
[HttpPost("scoreboard/{slotType}/{id:int}/{childId:int}")]
|
[HttpPost("scoreboard/{slotType}/{id:int}/{childId:int}")]
|
||||||
public async Task<IActionResult> SubmitScore(string slotType, int id, int childId)
|
public async Task<IActionResult> SubmitScore(string slotType, int id, int childId)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
string username = await this.database.UsernameFromGameToken(token);
|
string username = await this.database.UsernameFromGameToken(token);
|
||||||
|
|
||||||
|
@ -44,16 +44,15 @@ public class ScoreController : ControllerBase
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
Score? score = await this.DeserializeBody<Score>();
|
GameScore? score = await this.DeserializeBody<GameScore>();
|
||||||
if (score == null)
|
if (score == null)
|
||||||
{
|
{
|
||||||
Logger.Warn($"Rejecting score upload, score is null (slotType={slotType}, slotId={id}, user={username})", LogArea.Score);
|
Logger.Warn($"Rejecting score upload, score is null (slotType={slotType}, slotId={id}, user={username})", LogArea.Score);
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This only seems to happens on lbp2 versus levels, not sure why
|
// Workaround for parsing player ids of versus levels
|
||||||
if (score.PlayerIdCollection.Contains(':'))
|
if (score.PlayerIds.Length == 1 && score.PlayerIds[0].Contains(':')) score.PlayerIds = score.PlayerIds[0].Split(":");
|
||||||
score.PlayerIdCollection = score.PlayerIdCollection.Replace(':', ',');
|
|
||||||
|
|
||||||
if (score.PlayerIds.Length == 0)
|
if (score.PlayerIds.Length == 0)
|
||||||
{
|
{
|
||||||
|
@ -89,15 +88,14 @@ public class ScoreController : ControllerBase
|
||||||
|
|
||||||
SanitizationHelper.SanitizeStringsInClass(score);
|
SanitizationHelper.SanitizeStringsInClass(score);
|
||||||
|
|
||||||
if (slotType == "developer") id = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
int slotId = id;
|
||||||
|
|
||||||
score.SlotId = id;
|
if (slotType == "developer") slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
|
||||||
score.ChildSlotId = childId;
|
|
||||||
|
|
||||||
Slot? slot = this.database.Slots.FirstOrDefault(s => s.SlotId == score.SlotId);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (slot == null)
|
if (slot == null)
|
||||||
{
|
{
|
||||||
Logger.Warn($"Rejecting score upload, slot is null (slotId={score.SlotId}, slotType={slotType}, reqId={id}, user={username})", LogArea.Score);
|
Logger.Warn($"Rejecting score upload, slot is null (slotId={slotId}, slotType={slotType}, reqId={id}, user={username})", LogArea.Score);
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,46 +113,56 @@ public class ScoreController : ControllerBase
|
||||||
break;
|
break;
|
||||||
case GameVersion.LittleBigPlanetPSP:
|
case GameVersion.LittleBigPlanetPSP:
|
||||||
case GameVersion.Unknown:
|
case GameVersion.Unknown:
|
||||||
default: throw new ArgumentOutOfRangeException();
|
default:
|
||||||
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
Score playerScore = new()
|
await this.database.SaveChangesAsync();
|
||||||
{
|
|
||||||
PlayerIdCollection = string.Join(',', score.PlayerIds),
|
|
||||||
Type = score.Type,
|
|
||||||
Points = score.Points,
|
|
||||||
SlotId = score.SlotId,
|
|
||||||
ChildSlotId = score.ChildSlotId,
|
|
||||||
};
|
|
||||||
|
|
||||||
IQueryable<Score> existingScore = this.database.Scores.Where(s => s.SlotId == playerScore.SlotId)
|
string playerIdCollection = string.Join(',', score.PlayerIds);
|
||||||
|
|
||||||
|
ScoreEntity? existingScore = await this.database.Scores.Where(s => s.SlotId == slot.SlotId)
|
||||||
.Where(s => s.ChildSlotId == 0 || s.ChildSlotId == childId)
|
.Where(s => s.ChildSlotId == 0 || s.ChildSlotId == childId)
|
||||||
.Where(s => s.PlayerIdCollection == playerScore.PlayerIdCollection)
|
.Where(s => s.PlayerIdCollection == playerIdCollection)
|
||||||
.Where(s => s.Type == playerScore.Type);
|
.Where(s => s.Type == score.Type)
|
||||||
if (existingScore.Any())
|
.FirstOrDefaultAsync();
|
||||||
|
if (existingScore != null)
|
||||||
{
|
{
|
||||||
Score first = existingScore.First(s => s.SlotId == playerScore.SlotId);
|
existingScore.Points = Math.Max(existingScore.Points, score.Points);
|
||||||
playerScore.ScoreId = first.ScoreId;
|
|
||||||
playerScore.Points = Math.Max(first.Points, playerScore.Points);
|
|
||||||
this.database.Entry(first).CurrentValues.SetValues(playerScore);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
ScoreEntity playerScore = new()
|
||||||
|
{
|
||||||
|
PlayerIdCollection = playerIdCollection,
|
||||||
|
Type = score.Type,
|
||||||
|
Points = score.Points,
|
||||||
|
SlotId = slotId,
|
||||||
|
ChildSlotId = childId,
|
||||||
|
};
|
||||||
this.database.Scores.Add(playerScore);
|
this.database.Scores.Add(playerScore);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.database.SaveChangesAsync();
|
await this.database.SaveChangesAsync();
|
||||||
|
|
||||||
string myRanking = this.getScores(score.SlotId, score.Type, username, -1, 5, "scoreboardSegment", childId: score.ChildSlotId);
|
return this.Ok(this.getScores(new LeaderboardOptions
|
||||||
|
{
|
||||||
return this.Ok(myRanking);
|
RootName = "scoreboardSegment",
|
||||||
|
PageSize = 5,
|
||||||
|
PageStart = -1,
|
||||||
|
SlotId = slotId,
|
||||||
|
ChildSlotId = childId,
|
||||||
|
ScoreType = score.Type,
|
||||||
|
TargetUsername = username,
|
||||||
|
TargetPlayerIds = null,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("friendscores/{slotType}/{slotId:int}/{type:int}")]
|
[HttpGet("friendscores/{slotType}/{slotId:int}/{type:int}")]
|
||||||
[HttpGet("friendscores/{slotType}/{slotId:int}/{childId:int}/{type:int}")]
|
[HttpGet("friendscores/{slotType}/{slotId:int}/{childId:int}/{type:int}")]
|
||||||
public async Task<IActionResult> FriendScores(string slotType, int slotId, int? childId, int type, [FromQuery] int pageStart = -1, [FromQuery] int pageSize = 5)
|
public async Task<IActionResult> FriendScores(string slotType, int slotId, int? childId, int type, [FromQuery] int pageStart = -1, [FromQuery] int pageSize = 5)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
|
@ -180,7 +188,17 @@ public class ScoreController : ControllerBase
|
||||||
if (friendUsername != null) friendNames.Add(friendUsername);
|
if (friendUsername != null) friendNames.Add(friendUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.Ok(this.getScores(slotId, type, username, pageStart, pageSize, "scores", friendNames.ToArray(), childId));
|
return this.Ok(this.getScores(new LeaderboardOptions
|
||||||
|
{
|
||||||
|
RootName = "scores",
|
||||||
|
PageSize = pageSize,
|
||||||
|
PageStart = pageStart,
|
||||||
|
SlotId = slotId,
|
||||||
|
ChildSlotId = childId,
|
||||||
|
ScoreType = type,
|
||||||
|
TargetUsername = username,
|
||||||
|
TargetPlayerIds = friendNames.ToArray(),
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("topscores/{slotType}/{slotId:int}/{type:int}")]
|
[HttpGet("topscores/{slotType}/{slotId:int}/{type:int}")]
|
||||||
|
@ -188,7 +206,7 @@ public class ScoreController : ControllerBase
|
||||||
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
|
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
|
||||||
public async Task<IActionResult> TopScores(string slotType, int slotId, int? childId, int type, [FromQuery] int pageStart = -1, [FromQuery] int pageSize = 5)
|
public async Task<IActionResult> TopScores(string slotType, int slotId, int? childId, int type, [FromQuery] int pageStart = -1, [FromQuery] int pageSize = 5)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
|
@ -198,79 +216,60 @@ public class ScoreController : ControllerBase
|
||||||
|
|
||||||
if (slotType == "developer") slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
|
if (slotType == "developer") slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
|
||||||
|
|
||||||
return this.Ok(this.getScores(slotId, type, username, pageStart, pageSize, childId: childId));
|
return this.Ok(this.getScores(new LeaderboardOptions
|
||||||
|
{
|
||||||
|
RootName = "scores",
|
||||||
|
PageSize = pageSize,
|
||||||
|
PageStart = pageStart,
|
||||||
|
SlotId = slotId,
|
||||||
|
ChildSlotId = childId,
|
||||||
|
ScoreType = type,
|
||||||
|
TargetUsername = username,
|
||||||
|
TargetPlayerIds = null,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
|
private class LeaderboardOptions
|
||||||
private string getScores
|
{
|
||||||
(
|
public int SlotId { get; set; }
|
||||||
int slotId,
|
public int ScoreType { get; set; }
|
||||||
int type,
|
public string TargetUsername { get; set; } = "";
|
||||||
string username,
|
public int PageStart { get; set; } = -1;
|
||||||
int pageStart = -1,
|
public int PageSize { get; set; } = 5;
|
||||||
int pageSize = 5,
|
public string RootName { get; set; } = "scores";
|
||||||
string rootName = "scores",
|
public string[]? TargetPlayerIds;
|
||||||
string[]? playerIds = null,
|
public int? ChildSlotId;
|
||||||
int? childId = 0
|
}
|
||||||
)
|
|
||||||
|
private ScoreboardResponse getScores(LeaderboardOptions options)
|
||||||
{
|
{
|
||||||
|
|
||||||
// This is hella ugly but it technically assigns the proper rank to a score
|
// This is hella ugly but it technically assigns the proper rank to a score
|
||||||
// var needed for Anonymous type returned from SELECT
|
// var needed for Anonymous type returned from SELECT
|
||||||
var rankedScores = this.database.Scores
|
var rankedScores = this.database.Scores.Where(s => s.SlotId == options.SlotId && s.Type == options.ScoreType)
|
||||||
.Where(s => s.SlotId == slotId && s.Type == type)
|
.Where(s => s.ChildSlotId == 0 || s.ChildSlotId == options.ChildSlotId)
|
||||||
.Where(s => s.ChildSlotId == 0 || s.ChildSlotId == childId)
|
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
.Where(s => playerIds == null || playerIds.Any(id => s.PlayerIdCollection.Split(",").Contains(id)))
|
.Where(s => options.TargetPlayerIds == null ||
|
||||||
|
options.TargetPlayerIds.Any(id => s.PlayerIdCollection.Split(",").Contains(id)))
|
||||||
.OrderByDescending(s => s.Points)
|
.OrderByDescending(s => s.Points)
|
||||||
.ThenBy(s => s.ScoreId)
|
.ThenBy(s => s.ScoreId)
|
||||||
.ToList()
|
.ToList()
|
||||||
.Select
|
.Select((s, rank) => new
|
||||||
(
|
{
|
||||||
(s, rank) => new
|
Score = s,
|
||||||
{
|
Rank = rank + 1,
|
||||||
Score = s,
|
})
|
||||||
Rank = rank + 1,
|
.ToList();
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Find your score, since even if you aren't in the top list your score is pinned
|
// Find your score, since even if you aren't in the top list your score is pinned
|
||||||
var myScore = rankedScores.Where(rs => rs.Score.PlayerIdCollection.Split(",").Contains(username)).MaxBy(rs => rs.Score.Points);
|
var myScore = rankedScores.Where(rs => rs.Score.PlayerIdCollection.Split(",").Contains(options.TargetUsername)).MaxBy(rs => rs.Score.Points);
|
||||||
|
|
||||||
// Paginated viewing: if not requesting pageStart, get results around user
|
// Paginated viewing: if not requesting pageStart, get results around user
|
||||||
var pagedScores = rankedScores.Skip(pageStart != -1 || myScore == null ? pageStart - 1 : myScore.Rank - 3).Take(Math.Min(pageSize, 30));
|
var pagedScores = rankedScores.Skip(options.PageStart != -1 || myScore == null ? options.PageStart - 1 : myScore.Rank - 3).Take(Math.Min(options.PageSize, 30));
|
||||||
|
|
||||||
string serializedScores = pagedScores.Aggregate
|
List<GameScore> gameScores = pagedScores.Select(ps => GameScore.CreateFromEntity(ps.Score, ps.Rank)).ToList();
|
||||||
(
|
|
||||||
string.Empty,
|
|
||||||
(current, rs) =>
|
|
||||||
{
|
|
||||||
rs.Score.Rank = rs.Rank;
|
|
||||||
return current + rs.Score.Serialize();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
string res;
|
return new ScoreboardResponse(options.RootName, gameScores, myScore?.Score.Points ?? 0, myScore?.Rank ?? 0, rankedScores.Count);
|
||||||
if (myScore == null) res = LbpSerializer.StringElement(rootName, serializedScores);
|
|
||||||
else
|
|
||||||
res = LbpSerializer.TaggedStringElement
|
|
||||||
(
|
|
||||||
rootName,
|
|
||||||
serializedScores,
|
|
||||||
new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"yourScore", myScore.Score.Points
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"yourRank", myScore.Rank
|
|
||||||
}, //This is the numerator of your position globally in the side menu.
|
|
||||||
{
|
|
||||||
"totalNumScores", rankedScores.Count()
|
|
||||||
}, // This is the denominator of your position globally in the side menu.
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -35,7 +35,7 @@ public class SearchController : ControllerBase
|
||||||
string? keyName = "slots"
|
string? keyName = "slots"
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ public class SearchController : ControllerBase
|
||||||
|
|
||||||
string[] keywords = query.Split(" ");
|
string[] keywords = query.Split(" ");
|
||||||
|
|
||||||
IQueryable<Slot> dbQuery = this.database.Slots.ByGameVersion(token.GameVersion, false, true)
|
IQueryable<SlotEntity> dbQuery = this.database.Slots.ByGameVersion(token.GameVersion, false, true)
|
||||||
.Where(s => s.Type == SlotType.User)
|
.Where(s => s.Type == SlotType.User)
|
||||||
.OrderBy(s => !s.TeamPick)
|
.OrderBy(s => !s.TeamPick)
|
||||||
.ThenByDescending(s => s.FirstUploaded)
|
.ThenByDescending(s => s.FirstUploaded)
|
||||||
|
@ -61,11 +61,12 @@ public class SearchController : ControllerBase
|
||||||
s.SlotId.ToString().Equals(keyword)
|
s.SlotId.ToString().Equals(keyword)
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Slot> slots = await dbQuery.Skip(Math.Max(0, pageStart - 1)).Take(Math.Min(pageSize, 30)).ToListAsync();
|
List<SlotBase> slots = await dbQuery.Skip(Math.Max(0, pageStart - 1))
|
||||||
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, this.GetToken()))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = slots.Aggregate("", (current, slot) => current + slot.Serialize(token.GameVersion));
|
return this.Ok(new GenericSlotResponse(keyName, slots, await dbQuery.CountAsync(), 0));
|
||||||
|
|
||||||
return this.Ok(LbpSerializer.TaggedStringElement(keyName, response, "total", dbQuery.Count()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /LITTLEBIGPLANETPS3_XML?pageStart=1&pageSize=10&resultTypes[]=slot&resultTypes[]=playlist&resultTypes[]=user&adventure=dontCare&textFilter=qwer
|
// /LITTLEBIGPLANETPS3_XML?pageStart=1&pageSize=10&resultTypes[]=slot&resultTypes[]=playlist&resultTypes[]=user&adventure=dontCare&textFilter=qwer
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
using System.Security.Cryptography;
|
||||||
using LBPUnion.ProjectLighthouse.Configuration;
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms;
|
using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -28,113 +28,102 @@ public class SlotsController : ControllerBase
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string generateSlotsResponse(string slotAggregate, int start, int total) =>
|
|
||||||
LbpSerializer.TaggedStringElement("slots",
|
|
||||||
slotAggregate,
|
|
||||||
new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"hint_start", start
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"total", total
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
[HttpGet("slots/by")]
|
[HttpGet("slots/by")]
|
||||||
public async Task<IActionResult> SlotsBy([FromQuery(Name="u")] string username, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> SlotsBy([FromQuery(Name = "u")] string username, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
|
||||||
|
|
||||||
int targetUserId = await this.database.UserIdFromUsername(username);
|
int targetUserId = await this.database.UserIdFromUsername(username);
|
||||||
if (targetUserId == 0) return this.NotFound();
|
if (targetUserId == 0) return this.NotFound();
|
||||||
|
|
||||||
int usedSlots = this.database.Slots.Count(s => s.CreatorId == targetUserId);
|
int usedSlots = this.database.Slots.Count(s => s.CreatorId == targetUserId);
|
||||||
|
|
||||||
string response = Enumerable.Aggregate
|
List<SlotBase> slots = await this.database.Slots.Where(s => s.CreatorId == targetUserId)
|
||||||
(
|
.ByGameVersion(token.GameVersion, token.UserId == targetUserId)
|
||||||
this.database.Slots.Where(s => s.CreatorId == targetUserId)
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.ByGameVersion(gameVersion, token.UserId == targetUserId, true)
|
.Take(Math.Min(pageSize, usedSlots))
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
.Take(Math.Min(pageSize, usedSlots)),
|
.ToListAsync();
|
||||||
string.Empty,
|
|
||||||
(current, slot) => current + slot.Serialize(token.GameVersion)
|
|
||||||
);
|
|
||||||
int start = pageStart + Math.Min(pageSize, usedSlots);
|
int start = pageStart + Math.Min(pageSize, usedSlots);
|
||||||
int total = await this.database.Slots.CountAsync(s => s.CreatorId == targetUserId);
|
int total = await this.database.Slots.CountAsync(s => s.CreatorId == targetUserId);
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
|
||||||
|
return this.Ok(new GenericSlotResponse("slots", slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slotList")]
|
[HttpGet("slotList")]
|
||||||
public async Task<IActionResult> GetSlotListAlt([FromQuery] int[] s)
|
public async Task<IActionResult> GetSlotListAlt([FromQuery(Name = "s")] int[] slotIds)
|
||||||
{
|
{
|
||||||
List<string?> serializedSlots = new();
|
GameTokenEntity token = this.GetToken();
|
||||||
foreach (int slotId in s)
|
|
||||||
|
List<SlotBase> slots = new();
|
||||||
|
foreach (int slotId in slotIds)
|
||||||
{
|
{
|
||||||
Slot? slot = await this.database.Slots.Include(t => t.Creator).Where(t => t.SlotId == slotId && t.Type == SlotType.User).FirstOrDefaultAsync();
|
SlotEntity? slot = await this.database.Slots.Include(t => t.Creator).Where(t => t.SlotId == slotId && t.Type == SlotType.User).FirstOrDefaultAsync();
|
||||||
if (slot == null)
|
if (slot == null)
|
||||||
{
|
{
|
||||||
slot = await this.database.Slots.Where(t => t.InternalSlotId == slotId && t.Type == SlotType.Developer).FirstOrDefaultAsync();
|
slot = await this.database.Slots.Where(t => t.InternalSlotId == slotId && t.Type == SlotType.Developer).FirstOrDefaultAsync();
|
||||||
if (slot == null)
|
if (slot == null)
|
||||||
{
|
{
|
||||||
serializedSlots.Add($"<slot type=\"developer\"><id>{slotId}</id></slot>");
|
slots.Add(new GameDeveloperSlot
|
||||||
|
{
|
||||||
|
SlotId = slotId,
|
||||||
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serializedSlots.Add(slot.Serialize());
|
|
||||||
|
slots.Add(SlotBase.CreateFromEntity(slot, token));
|
||||||
}
|
}
|
||||||
string serialized = serializedSlots.Aggregate(string.Empty, (current, slot) => slot == null ? current : current + slot);
|
|
||||||
|
|
||||||
return this.Ok(LbpSerializer.TaggedStringElement("slots", serialized, "total", serializedSlots.Count));
|
return this.Ok(new GenericSlotResponse(slots, slots.Count, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/developer")]
|
[HttpGet("slots/developer")]
|
||||||
public async Task<IActionResult> StoryPlayers()
|
public async Task<IActionResult> StoryPlayers()
|
||||||
{
|
{
|
||||||
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
List<int> activeSlotIds = RoomHelper.Rooms.Where(r => r.Slot.SlotType == SlotType.Developer).Select(r => r.Slot.SlotId).ToList();
|
List<int> activeSlotIds = RoomHelper.Rooms.Where(r => r.Slot.SlotType == SlotType.Developer).Select(r => r.Slot.SlotId).ToList();
|
||||||
|
|
||||||
List<string> serializedSlots = new();
|
List<SlotBase> slots = new();
|
||||||
|
|
||||||
foreach (int id in activeSlotIds)
|
foreach (int id in activeSlotIds)
|
||||||
{
|
{
|
||||||
int placeholderSlotId = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
int placeholderSlotId = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
||||||
Slot slot = await this.database.Slots.FirstAsync(s => s.SlotId == placeholderSlotId);
|
SlotEntity slot = await this.database.Slots.FirstAsync(s => s.SlotId == placeholderSlotId);
|
||||||
serializedSlots.Add(slot.SerializeDevSlot());
|
|
||||||
|
slots.Add(SlotBase.CreateFromEntity(slot, token));
|
||||||
}
|
}
|
||||||
|
|
||||||
string serialized = serializedSlots.Aggregate(string.Empty, (current, slot) => current + slot);
|
return this.Ok(new GenericSlotResponse(slots));
|
||||||
|
|
||||||
return this.Ok(LbpSerializer.StringElement("slots", serialized));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("s/developer/{id:int}")]
|
[HttpGet("s/developer/{id:int}")]
|
||||||
public async Task<IActionResult> SDev(int id)
|
public async Task<IActionResult> SDev(int id)
|
||||||
{
|
{
|
||||||
int slotId = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
GameTokenEntity token = this.GetToken();
|
||||||
Slot slot = await this.database.Slots.FirstAsync(s => s.SlotId == slotId);
|
|
||||||
|
|
||||||
return this.Ok(slot.SerializeDevSlot());
|
int slotId = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
|
||||||
|
SlotEntity slot = await this.database.Slots.FirstAsync(s => s.SlotId == slotId);
|
||||||
|
|
||||||
|
return this.Ok(SlotBase.CreateFromEntity(slot, token));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("s/user/{id:int}")]
|
[HttpGet("s/user/{id:int}")]
|
||||||
public async Task<IActionResult> SUser(int id)
|
public async Task<IActionResult> SUser(int id)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
GameVersion gameVersion = token.GameVersion;
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.ByGameVersion(gameVersion, true, true).FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? slot = await this.database.Slots.ByGameVersion(gameVersion, true, true).FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
|
|
||||||
if (slot == null) return this.NotFound();
|
if (slot == null) return this.NotFound();
|
||||||
|
|
||||||
RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == id && r.UserId == token.UserId);
|
return this.Ok(SlotBase.CreateFromEntity(slot, token, SerializationMode.Full));
|
||||||
VisitedLevel? visitedLevel = await this.database.VisitedLevels.FirstOrDefaultAsync(r => r.SlotId == id && r.UserId == token.UserId);
|
|
||||||
Review? review = await this.database.Reviews.Include(r => r.Slot).FirstOrDefaultAsync(r => r.SlotId == id && r.ReviewerId == token.UserId);
|
|
||||||
return this.Ok(slot.Serialize(gameVersion, ratedLevel, visitedLevel, review, true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/cool")]
|
[HttpGet("slots/cool")]
|
||||||
|
@ -163,27 +152,28 @@ public class SlotsController : ControllerBase
|
||||||
[HttpGet("slots")]
|
[HttpGet("slots")]
|
||||||
public async Task<IActionResult> NewestSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> NewestSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
GameVersion gameVersion = token.GameVersion;
|
||||||
|
|
||||||
IQueryable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion, false, true)
|
List<SlotBase> slots = await this.database.Slots.ByGameVersion(gameVersion, false, true)
|
||||||
.OrderByDescending(s => s.FirstUploaded)
|
.OrderByDescending(s => s.FirstUploaded)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30));
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = Enumerable.Aggregate(slots, string.Empty, (current, slot) => current + slot.Serialize(gameVersion));
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
||||||
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
return this.Ok(new GenericSlotResponse(slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/like/{slotType}/{slotId:int}")]
|
[HttpGet("slots/like/{slotType}/{slotId:int}")]
|
||||||
public async Task<IActionResult> SimilarSlots([FromRoute] string slotType, [FromRoute] int slotId, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> SimilarSlots([FromRoute] string slotType, [FromRoute] int slotId, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
|
@ -191,10 +181,10 @@ public class SlotsController : ControllerBase
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
GameVersion gameVersion = token.GameVersion;
|
||||||
|
|
||||||
Slot? targetSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
SlotEntity? targetSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
||||||
if (targetSlot == null) return this.BadRequest();
|
if (targetSlot == null) return this.BadRequest();
|
||||||
|
|
||||||
string[] tags = targetSlot.LevelTags;
|
string[] tags = targetSlot.LevelTags(this.database);
|
||||||
|
|
||||||
List<int> slotIdsWithTag = this.database.RatedLevels
|
List<int> slotIdsWithTag = this.database.RatedLevels
|
||||||
.Where(r => r.TagLBP1.Length > 0)
|
.Where(r => r.TagLBP1.Length > 0)
|
||||||
|
@ -202,105 +192,108 @@ public class SlotsController : ControllerBase
|
||||||
.Select(r => r.SlotId)
|
.Select(r => r.SlotId)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
IQueryable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion, false, true)
|
List<SlotBase> slots = await this.database.Slots.ByGameVersion(gameVersion, false, true)
|
||||||
.Where(s => slotIdsWithTag.Contains(s.SlotId))
|
.Where(s => slotIdsWithTag.Contains(s.SlotId))
|
||||||
.OrderByDescending(s => s.PlaysLBP1)
|
.OrderByDescending(s => s.PlaysLBP1)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30));
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = Enumerable.Aggregate(slots, string.Empty, (current, slot) => current + slot.Serialize(gameVersion));
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
||||||
int total = slotIdsWithTag.Count;
|
int total = slotIdsWithTag.Count;
|
||||||
|
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
return this.Ok(new GenericSlotResponse(slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/highestRated")]
|
[HttpGet("slots/highestRated")]
|
||||||
public async Task<IActionResult> HighestRatedSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> HighestRatedSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
GameVersion gameVersion = token.GameVersion;
|
||||||
|
|
||||||
IEnumerable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion, false, true)
|
List<SlotBase> slots = await this.database.Slots.ByGameVersion(gameVersion, false, true)
|
||||||
.AsEnumerable()
|
.ToAsyncEnumerable()
|
||||||
.OrderByDescending(s => s.RatingLBP1)
|
.OrderByDescending(s => s.RatingLBP1)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30));
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(gameVersion));
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
||||||
int total = await StatisticsHelper.SlotCount(this.database);
|
int total = await StatisticsHelper.SlotCount(this.database);
|
||||||
|
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
return this.Ok(new GenericSlotResponse(slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/tag")]
|
[HttpGet("slots/tag")]
|
||||||
public async Task<IActionResult> SimilarSlots([FromQuery] string tag, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> SimilarSlots([FromQuery] string tag, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
|
||||||
|
|
||||||
List<int> slotIdsWithTag = await this.database.RatedLevels.Where(r => r.TagLBP1.Length > 0)
|
List<int> slotIdsWithTag = await this.database.RatedLevels.Where(r => r.TagLBP1.Length > 0)
|
||||||
.Where(r => r.TagLBP1 == tag)
|
.Where(r => r.TagLBP1 == tag)
|
||||||
.Select(s => s.SlotId)
|
.Select(s => s.SlotId)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
IQueryable<Slot> slots = this.database.Slots.Where(s => slotIdsWithTag.Contains(s.SlotId))
|
List<SlotBase> slots = await this.database.Slots.Where(s => slotIdsWithTag.Contains(s.SlotId))
|
||||||
.ByGameVersion(gameVersion, false, true)
|
.ByGameVersion(token.GameVersion, false, true)
|
||||||
.OrderByDescending(s => s.PlaysLBP1)
|
.OrderByDescending(s => s.PlaysLBP1)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30));
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = Enumerable.Aggregate(slots, string.Empty, (current, slot) => current + slot.Serialize(gameVersion));
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
||||||
int total = slotIdsWithTag.Count;
|
int total = slotIdsWithTag.Count;
|
||||||
|
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
return this.Ok(new GenericSlotResponse(slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/mmpicks")]
|
[HttpGet("slots/mmpicks")]
|
||||||
public async Task<IActionResult> TeamPickedSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> TeamPickedSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
List<SlotBase> slots = await this.database.Slots.Where(s => s.TeamPick)
|
||||||
|
.ByGameVersion(token.GameVersion, false, true)
|
||||||
IQueryable<Slot> slots = this.database.Slots.Where(s => s.TeamPick)
|
|
||||||
.ByGameVersion(gameVersion, false, true)
|
|
||||||
.OrderByDescending(s => s.LastUpdated)
|
.OrderByDescending(s => s.LastUpdated)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30));
|
.Take(Math.Min(pageSize, 30))
|
||||||
string response = Enumerable.Aggregate(slots, string.Empty, (current, slot) => current + slot.Serialize(gameVersion));
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
||||||
int total = await StatisticsHelper.TeamPickCountForGame(this.database, token.GameVersion);
|
int total = await StatisticsHelper.TeamPickCountForGame(this.database, token.GameVersion);
|
||||||
|
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
return this.Ok(new GenericSlotResponse(slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/lbp2luckydip")]
|
[HttpGet("slots/lbp2luckydip")]
|
||||||
public async Task<IActionResult> LuckyDipSlots([FromQuery] int pageStart, [FromQuery] int pageSize, [FromQuery] int seed)
|
public async Task<IActionResult> LuckyDipSlots([FromQuery] int pageStart, [FromQuery] int pageSize, [FromQuery] int seed)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
GameVersion gameVersion = token.GameVersion;
|
||||||
|
|
||||||
IEnumerable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion, false, true).OrderBy(_ => EF.Functions.Random()).Take(Math.Min(pageSize, 30));
|
List<SlotBase> slots = await this.database.Slots.ByGameVersion(gameVersion, false, true)
|
||||||
|
.OrderBy(_ => EF.Functions.Random())
|
||||||
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(gameVersion));
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
||||||
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
||||||
|
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
return this.Ok(new GenericSlotResponse(slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/thumbs")]
|
[HttpGet("slots/thumbs")]
|
||||||
|
@ -314,24 +307,25 @@ public class SlotsController : ControllerBase
|
||||||
[FromQuery] string? dateFilterType = null
|
[FromQuery] string? dateFilterType = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
Random rand = new();
|
Random rand = new();
|
||||||
|
|
||||||
IEnumerable<Slot> slots = this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
List<SlotBase> slots = await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
||||||
.AsEnumerable()
|
.AsAsyncEnumerable()
|
||||||
.OrderByDescending(s => s.Thumbsup)
|
.OrderByDescending(s => s.Thumbsup)
|
||||||
.ThenBy(_ => rand.Next())
|
.ThenBy(_ => rand.Next())
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30));
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(token.GameVersion));
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
||||||
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
||||||
|
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
return this.Ok(new GenericSlotResponse(slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/mostUniquePlays")]
|
[HttpGet("slots/mostUniquePlays")]
|
||||||
|
@ -345,20 +339,19 @@ public class SlotsController : ControllerBase
|
||||||
[FromQuery] string? dateFilterType = null
|
[FromQuery] string? dateFilterType = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
Random rand = new();
|
Random rand = new();
|
||||||
|
|
||||||
IEnumerable<Slot> slots = this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
List<SlotBase> slots = await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
||||||
.AsEnumerable()
|
.AsAsyncEnumerable()
|
||||||
.OrderByDescending
|
.OrderByDescending(
|
||||||
(
|
|
||||||
// probably not the best way to do this?
|
// probably not the best way to do this?
|
||||||
s =>
|
s =>
|
||||||
{
|
{
|
||||||
return this.getGameFilter(gameFilterType, token.GameVersion) switch
|
return getGameFilter(gameFilterType, token.GameVersion) switch
|
||||||
{
|
{
|
||||||
GameVersion.LittleBigPlanet1 => s.PlaysLBP1Unique,
|
GameVersion.LittleBigPlanet1 => s.PlaysLBP1Unique,
|
||||||
GameVersion.LittleBigPlanet2 => s.PlaysLBP2Unique,
|
GameVersion.LittleBigPlanet2 => s.PlaysLBP2Unique,
|
||||||
|
@ -366,17 +359,17 @@ public class SlotsController : ControllerBase
|
||||||
GameVersion.LittleBigPlanetVita => s.PlaysLBP2Unique,
|
GameVersion.LittleBigPlanetVita => s.PlaysLBP2Unique,
|
||||||
_ => s.PlaysUnique,
|
_ => s.PlaysUnique,
|
||||||
};
|
};
|
||||||
}
|
})
|
||||||
)
|
|
||||||
.ThenBy(_ => rand.Next())
|
.ThenBy(_ => rand.Next())
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30));
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(token.GameVersion));
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
||||||
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
||||||
|
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
return this.Ok(new GenericSlotResponse(slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/mostHearted")]
|
[HttpGet("slots/mostHearted")]
|
||||||
|
@ -390,24 +383,23 @@ public class SlotsController : ControllerBase
|
||||||
[FromQuery] string? dateFilterType = null
|
[FromQuery] string? dateFilterType = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
Random rand = new();
|
List<SlotBase> slots = await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
||||||
|
.AsAsyncEnumerable()
|
||||||
IEnumerable<Slot> slots = this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
|
||||||
.AsEnumerable()
|
|
||||||
.OrderByDescending(s => s.Hearts)
|
.OrderByDescending(s => s.Hearts)
|
||||||
.ThenBy(_ => rand.Next())
|
.ThenBy(_ => RandomNumberGenerator.GetInt32(int.MaxValue))
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 30));
|
.Take(Math.Min(pageSize, 30))
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(token.GameVersion));
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
||||||
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
||||||
|
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
return this.Ok(new GenericSlotResponse(slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
// /slots/busiest?pageStart=1&pageSize=30&gameFilterType=both&players=1&move=true
|
// /slots/busiest?pageStart=1&pageSize=30&gameFilterType=both&players=1&move=true
|
||||||
|
@ -421,7 +413,7 @@ public class SlotsController : ControllerBase
|
||||||
[FromQuery] bool? move = null
|
[FromQuery] bool? move = null
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
if (pageSize <= 0) return this.BadRequest();
|
||||||
|
|
||||||
|
@ -447,42 +439,45 @@ public class SlotsController : ControllerBase
|
||||||
.OrderByDescending(kvp => kvp.Value)
|
.OrderByDescending(kvp => kvp.Value)
|
||||||
.Select(kvp => kvp.Key);
|
.Select(kvp => kvp.Key);
|
||||||
|
|
||||||
List<Slot> slots = new();
|
List<SlotBase> slots = new();
|
||||||
|
|
||||||
foreach (int slotId in orderedPlayersBySlotId)
|
foreach (int slotId in orderedPlayersBySlotId)
|
||||||
{
|
{
|
||||||
Slot? slot = await this.database.Slots.ByGameVersion(token.GameVersion, false, true)
|
SlotBase? slot = await this.database.Slots.ByGameVersion(token.GameVersion, false, true)
|
||||||
.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
.Where(s => s.SlotId == slotId)
|
||||||
|
.Select(s => SlotBase.CreateFromEntity(s, token))
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
if (slot == null) continue; // shouldn't happen ever unless the room is borked
|
if (slot == null) continue; // shouldn't happen ever unless the room is borked
|
||||||
|
|
||||||
slots.Add(slot);
|
slots.Add(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(token.GameVersion));
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
||||||
int total = playersBySlotId.Count;
|
int total = playersBySlotId.Count;
|
||||||
|
|
||||||
return this.Ok(generateSlotsResponse(response, start, total));
|
return this.Ok(new GenericSlotResponse(slots, total, start));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private GameVersion getGameFilter(string? gameFilterType, GameVersion version)
|
private static GameVersion getGameFilter(string? gameFilterType, GameVersion version)
|
||||||
{
|
{
|
||||||
if (version == GameVersion.LittleBigPlanetVita) return GameVersion.LittleBigPlanetVita;
|
return version switch
|
||||||
if (version == GameVersion.LittleBigPlanetPSP) return GameVersion.LittleBigPlanetPSP;
|
|
||||||
|
|
||||||
return gameFilterType switch
|
|
||||||
{
|
{
|
||||||
"lbp1" => GameVersion.LittleBigPlanet1,
|
GameVersion.LittleBigPlanetVita => GameVersion.LittleBigPlanetVita,
|
||||||
"lbp2" => GameVersion.LittleBigPlanet2,
|
GameVersion.LittleBigPlanetPSP => GameVersion.LittleBigPlanetPSP,
|
||||||
"lbp3" => GameVersion.LittleBigPlanet3,
|
_ => gameFilterType switch
|
||||||
"both" => GameVersion.LittleBigPlanet2, // LBP2 default option
|
{
|
||||||
null => GameVersion.LittleBigPlanet1,
|
"lbp1" => GameVersion.LittleBigPlanet1,
|
||||||
_ => GameVersion.Unknown,
|
"lbp2" => GameVersion.LittleBigPlanet2,
|
||||||
|
"lbp3" => GameVersion.LittleBigPlanet3,
|
||||||
|
"both" => GameVersion.LittleBigPlanet2, // LBP2 default option
|
||||||
|
null => GameVersion.LittleBigPlanet1,
|
||||||
|
_ => GameVersion.Unknown,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private IQueryable<Slot> filterByRequest(string? gameFilterType, string? dateFilterType, GameVersion version)
|
private IQueryable<SlotEntity> filterByRequest(string? gameFilterType, string? dateFilterType, GameVersion version)
|
||||||
{
|
{
|
||||||
if (version == GameVersion.LittleBigPlanetVita || version == GameVersion.LittleBigPlanetPSP || version == GameVersion.Unknown)
|
if (version == GameVersion.LittleBigPlanetVita || version == GameVersion.LittleBigPlanetPSP || version == GameVersion.Unknown)
|
||||||
{
|
{
|
||||||
|
@ -498,9 +493,9 @@ public class SlotsController : ControllerBase
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
GameVersion gameVersion = this.getGameFilter(gameFilterType, version);
|
GameVersion gameVersion = getGameFilter(gameFilterType, version);
|
||||||
|
|
||||||
IQueryable<Slot> whereSlots;
|
IQueryable<SlotEntity> whereSlots;
|
||||||
|
|
||||||
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
||||||
if (gameFilterType == "both")
|
if (gameFilterType == "both")
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
|
|
||||||
|
@ -33,11 +33,7 @@ public class StatisticsController : ControllerBase
|
||||||
int totalSlotCount = await StatisticsHelper.SlotCountForGame(this.database, this.GetToken().GameVersion);
|
int totalSlotCount = await StatisticsHelper.SlotCountForGame(this.database, this.GetToken().GameVersion);
|
||||||
int mmPicksCount = await StatisticsHelper.TeamPickCountForGame(this.database, this.GetToken().GameVersion);
|
int mmPicksCount = await StatisticsHelper.TeamPickCountForGame(this.database, this.GetToken().GameVersion);
|
||||||
|
|
||||||
return this.Ok
|
return this.Ok(new PlanetStatsResponse(totalSlotCount, mmPicksCount));
|
||||||
(
|
|
||||||
LbpSerializer.StringElement
|
|
||||||
("planetStats", LbpSerializer.StringElement("totalSlotCount", totalSlotCount) + LbpSerializer.StringElement("mmPicksCount", mmPicksCount))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("planetStats/totalLevelCount")]
|
[HttpGet("planetStats/totalLevelCount")]
|
||||||
|
|
|
@ -4,12 +4,14 @@ using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Files;
|
using LBPUnion.ProjectLighthouse.Files;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -30,57 +32,41 @@ public class UserController : ControllerBase
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string?> getSerializedUser(string username, GameVersion gameVersion = GameVersion.LittleBigPlanet1)
|
|
||||||
{
|
|
||||||
User? user = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
|
||||||
return user?.Serialize(gameVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string?> getSerializedUserPicture(string username)
|
|
||||||
{
|
|
||||||
// use an anonymous type to only fetch certain columns
|
|
||||||
var partialUser = await this.database.Users.Where(u => u.Username == username)
|
|
||||||
.Select(u => new
|
|
||||||
{
|
|
||||||
u.Username,
|
|
||||||
u.IconHash,
|
|
||||||
})
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
if (partialUser == null) return null;
|
|
||||||
|
|
||||||
string user = LbpSerializer.TaggedStringElement("npHandle", partialUser.Username, "icon", partialUser.IconHash);
|
|
||||||
return LbpSerializer.TaggedStringElement("user", user, "type", "user");
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("user/{username}")]
|
[HttpGet("user/{username}")]
|
||||||
public async Task<IActionResult> GetUser(string username)
|
public async Task<IActionResult> GetUser(string username)
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
UserEntity? user = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
|
|
||||||
string? user = await this.getSerializedUser(username, token.GameVersion);
|
|
||||||
if (user == null) return this.NotFound();
|
if (user == null) return this.NotFound();
|
||||||
|
|
||||||
return this.Ok(user);
|
return this.Ok(GameUser.CreateFromEntity(user, this.GetToken().GameVersion));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("users")]
|
[HttpGet("users")]
|
||||||
public async Task<IActionResult> GetUserAlt([FromQuery] string[] u)
|
public async Task<IActionResult> GetUserAlt([FromQuery(Name = "u")] string[] userList)
|
||||||
{
|
{
|
||||||
List<string?> serializedUsers = new();
|
List<MinimalUserProfile> minimalUserList = new();
|
||||||
foreach (string userId in u) serializedUsers.Add(await this.getSerializedUserPicture(userId));
|
foreach (string username in userList)
|
||||||
|
{
|
||||||
|
MinimalUserProfile? profile = await this.database.Users.Where(u => u.Username == username)
|
||||||
|
.Select(u => new MinimalUserProfile
|
||||||
|
{
|
||||||
|
UserHandle = new NpHandle(u.Username, u.IconHash),
|
||||||
|
})
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
if (profile == null) continue;
|
||||||
|
minimalUserList.Add(profile);
|
||||||
|
}
|
||||||
|
|
||||||
string serialized = serializedUsers.Aggregate(string.Empty, (current, user) => user == null ? current : current + user);
|
return this.Ok(new MinimalUserListResponse(minimalUserList));
|
||||||
|
|
||||||
return this.Ok(LbpSerializer.StringElement("users", serialized));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("updateUser")]
|
[HttpPost("updateUser")]
|
||||||
public async Task<IActionResult> UpdateUser()
|
public async Task<IActionResult> UpdateUser()
|
||||||
{
|
{
|
||||||
GameToken token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
User? user = await this.database.UserFromGameToken(token);
|
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
UserUpdate? update = await this.DeserializeBody<UserUpdate>("updateUser", "user");
|
UserUpdate? update = await this.DeserializeBody<UserUpdate>("updateUser", "user");
|
||||||
|
|
||||||
|
@ -118,17 +104,17 @@ public class UserController : ControllerBase
|
||||||
|
|
||||||
if (update.Slots != null)
|
if (update.Slots != null)
|
||||||
{
|
{
|
||||||
|
update.Slots = update.Slots.Where(s => s.Type == SlotType.User)
|
||||||
|
.Where(s => s.Location != null)
|
||||||
|
.Where(s => s.SlotId != 0).ToList();
|
||||||
foreach (UserUpdateSlot? updateSlot in update.Slots)
|
foreach (UserUpdateSlot? updateSlot in update.Slots)
|
||||||
{
|
{
|
||||||
// ReSharper disable once MergeIntoNegatedPattern
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == updateSlot.SlotId);
|
||||||
if (updateSlot.Type != SlotType.User || updateSlot.Location == null || updateSlot.SlotId == 0) continue;
|
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == updateSlot.SlotId);
|
|
||||||
if (slot == null) continue;
|
if (slot == null) continue;
|
||||||
|
|
||||||
if (slot.CreatorId != token.UserId) continue;
|
if (slot.CreatorId != token.UserId) continue;
|
||||||
|
|
||||||
slot.Location = updateSlot.Location;
|
slot.Location = updateSlot.Location!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +145,11 @@ public class UserController : ControllerBase
|
||||||
case GameVersion.Unknown:
|
case GameVersion.Unknown:
|
||||||
default: // The rest do not support custom earths.
|
default: // The rest do not support custom earths.
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"invalid gameVersion {token.GameVersion} for setting earth");
|
string bodyString = await this.ReadBodyAsync();
|
||||||
|
Logger.Warn($"User with invalid gameVersion '{token.GameVersion}' tried to set earth hash: \n" +
|
||||||
|
$"body: '{bodyString}'",
|
||||||
|
LogArea.Resources);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,10 +160,11 @@ public class UserController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("update_my_pins")]
|
[HttpPost("update_my_pins")]
|
||||||
|
[Produces("text/json")]
|
||||||
public async Task<IActionResult> UpdateMyPins()
|
public async Task<IActionResult> UpdateMyPins()
|
||||||
{
|
{
|
||||||
User? user = await this.database.UserFromGameToken(this.GetToken());
|
UserEntity? user = await this.database.UserFromGameToken(this.GetToken());
|
||||||
if (user == null) return this.StatusCode(403, "");
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
string bodyString = await this.ReadBodyAsync();
|
string bodyString = await this.ReadBodyAsync();
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ public class SetLastContactMiddleware : MiddlewareDBContext
|
||||||
if (context.Request.Path.ToString().StartsWith("/LITTLEBIGPLANETPS3_XML"))
|
if (context.Request.Path.ToString().StartsWith("/LITTLEBIGPLANETPS3_XML"))
|
||||||
{
|
{
|
||||||
// We begin by grabbing a token from the request, if this is a LBPPS3_XML request of course.
|
// We begin by grabbing a token from the request, if this is a LBPPS3_XML request of course.
|
||||||
GameToken? gameToken = await database.GameTokenFromRequest(context.Request);
|
GameTokenEntity? gameToken = await database.GameTokenFromRequest(context.Request);
|
||||||
|
|
||||||
if (gameToken?.GameVersion == GameVersion.LittleBigPlanet1)
|
if (gameToken?.GameVersion == GameVersion.LittleBigPlanet1)
|
||||||
// Ignore UserFromGameToken null because user must exist for a token to exist
|
// Ignore UserFromGameToken null because user must exist for a token to exist
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class GameServerStartup
|
||||||
(
|
(
|
||||||
options =>
|
options =>
|
||||||
{
|
{
|
||||||
options.OutputFormatters.Add(new XmlOutputFormatter());
|
options.OutputFormatters.Add(new LbpOutputFormatter());
|
||||||
options.OutputFormatters.Add(new JsonOutputFormatter());
|
options.OutputFormatters.Add(new JsonOutputFormatter());
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class TokenAuthHandler : AuthenticationHandler<AuthenticationSchemeOption
|
||||||
{
|
{
|
||||||
if (!this.Context.Request.Cookies.ContainsKey(cookie)) return AuthenticateResult.Fail("No auth cookie");
|
if (!this.Context.Request.Cookies.ContainsKey(cookie)) return AuthenticateResult.Fail("No auth cookie");
|
||||||
|
|
||||||
GameToken? gameToken = await this.database.GameTokenFromRequest(this.Request);
|
GameTokenEntity? gameToken = await this.database.GameTokenFromRequest(this.Request);
|
||||||
if (gameToken == null) return AuthenticateResult.Fail("No game token");
|
if (gameToken == null) return AuthenticateResult.Fail("No game token");
|
||||||
|
|
||||||
this.Context.Items["Token"] = gameToken;
|
this.Context.Items["Token"] = gameToken;
|
||||||
|
|
|
@ -20,6 +20,6 @@ public static class CategoryHelper
|
||||||
Categories.Add(new LuckyDipCategory());
|
Categories.Add(new LuckyDipCategory());
|
||||||
|
|
||||||
using DatabaseContext database = new();
|
using DatabaseContext database = new();
|
||||||
foreach (DatabaseCategory category in database.CustomCategories) Categories.Add(new CustomCategory(category));
|
foreach (DatabaseCategoryEntity category in database.CustomCategories) Categories.Add(new CustomCategory(category));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,18 +2,19 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
public abstract class CategoryWithUser : Category
|
public abstract class CategoryWithUser : Category
|
||||||
{
|
{
|
||||||
public abstract Slot? GetPreviewSlot(DatabaseContext database, User user);
|
public abstract SlotEntity? GetPreviewSlot(DatabaseContext database, UserEntity user);
|
||||||
public override Slot? GetPreviewSlot(DatabaseContext database)
|
public override SlotEntity? GetPreviewSlot(DatabaseContext database)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.Error("tried to get preview slot without user on CategoryWithUser", LogArea.Category);
|
Logger.Error("tried to get preview slot without user on CategoryWithUser", LogArea.Category);
|
||||||
|
@ -22,7 +23,7 @@ public abstract class CategoryWithUser : Category
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract int GetTotalSlots(DatabaseContext database, User user);
|
public abstract int GetTotalSlots(DatabaseContext database, UserEntity user);
|
||||||
public override int GetTotalSlots(DatabaseContext database)
|
public override int GetTotalSlots(DatabaseContext database)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -32,14 +33,14 @@ public abstract class CategoryWithUser : Category
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract IQueryable<Slot> GetSlots(DatabaseContext database, User user, int pageStart, int pageSize);
|
public abstract IQueryable<SlotEntity> GetSlots(DatabaseContext database, UserEntity user, int pageStart, int pageSize);
|
||||||
public override IList<Slot> GetSlots(DatabaseContext database, int pageStart, int pageSize)
|
public override IList<SlotEntity> GetSlots(DatabaseContext database, int pageStart, int pageSize)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.Error("tried to get slots without user on CategoryWithUser", LogArea.Category);
|
Logger.Error("tried to get slots without user on CategoryWithUser", LogArea.Category);
|
||||||
if (Debugger.IsAttached) Debugger.Break();
|
if (Debugger.IsAttached) Debugger.Break();
|
||||||
#endif
|
#endif
|
||||||
return new List<Slot>();
|
return new List<SlotEntity>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public new string Serialize(DatabaseContext database)
|
public new string Serialize(DatabaseContext database)
|
||||||
|
@ -48,35 +49,13 @@ public abstract class CategoryWithUser : Category
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Serialize(DatabaseContext database, User user)
|
public GameCategory Serialize(DatabaseContext database, UserEntity user)
|
||||||
{
|
{
|
||||||
Slot? previewSlot = this.GetPreviewSlot(database, user);
|
List<SlotBase> slots = new()
|
||||||
|
{
|
||||||
string previewResults = "";
|
SlotBase.CreateFromEntity(this.GetPreviewSlot(database, user), GameVersion.LittleBigPlanet3, user.UserId),
|
||||||
if (previewSlot != null)
|
};
|
||||||
previewResults = LbpSerializer.TaggedStringElement
|
int totalSlots = this.GetTotalSlots(database, user);
|
||||||
(
|
return GameCategory.CreateFromEntity(this, new GenericSlotResponse(slots, totalSlots, 2));
|
||||||
"results",
|
|
||||||
previewSlot.Serialize(),
|
|
||||||
new Dictionary<string, object>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"total", this.GetTotalSlots(database, user)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"hint_start", "2"
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return LbpSerializer.StringElement
|
|
||||||
(
|
|
||||||
"category",
|
|
||||||
LbpSerializer.StringElement("name", this.Name) +
|
|
||||||
LbpSerializer.StringElement("description", this.Description) +
|
|
||||||
LbpSerializer.StringElement("url", this.IngameEndpoint) +
|
|
||||||
(previewSlot == null ? "" : previewResults) +
|
|
||||||
LbpSerializer.StringElement("icon", this.IconHash)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@ public class CustomCategory : Category
|
||||||
this.SlotIds = slotIds.ToList();
|
this.SlotIds = slotIds.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CustomCategory(DatabaseCategory category)
|
public CustomCategory(DatabaseCategoryEntity category)
|
||||||
{
|
{
|
||||||
this.Name = category.Name;
|
this.Name = category.Name;
|
||||||
this.Description = category.Description;
|
this.Description = category.Description;
|
||||||
|
@ -35,8 +35,8 @@ public class CustomCategory : Category
|
||||||
public sealed override string Description { get; set; }
|
public sealed override string Description { get; set; }
|
||||||
public sealed override string IconHash { get; set; }
|
public sealed override string IconHash { get; set; }
|
||||||
public sealed override string Endpoint { get; set; }
|
public sealed override string Endpoint { get; set; }
|
||||||
public override Slot? GetPreviewSlot(DatabaseContext database) => database.Slots.FirstOrDefault(s => s.SlotId == this.SlotIds[0]);
|
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.FirstOrDefault(s => s.SlotId == this.SlotIds[0]);
|
||||||
public override IQueryable<Slot> GetSlots
|
public override IQueryable<SlotEntity> GetSlots
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
(DatabaseContext database, int pageStart, int pageSize)
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3).Where(s => this.SlotIds.Contains(s.SlotId));
|
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3).Where(s => this.SlotIds.Contains(s.SlotId));
|
||||||
public override int GetTotalSlots(DatabaseContext database) => this.SlotIds.Count;
|
public override int GetTotalSlots(DatabaseContext database) => this.SlotIds.Count;
|
||||||
|
|
|
@ -15,7 +15,7 @@ public class HeartedCategory : CategoryWithUser
|
||||||
public override string Description { get; set; } = "Content you've hearted";
|
public override string Description { get; set; } = "Content you've hearted";
|
||||||
public override string IconHash { get; set; } = "g820611";
|
public override string IconHash { get; set; } = "g820611";
|
||||||
public override string Endpoint { get; set; } = "hearted";
|
public override string Endpoint { get; set; } = "hearted";
|
||||||
public override Slot? GetPreviewSlot(DatabaseContext database, User user) // note: developer slots act up in LBP3 when listed here, so I omitted it
|
public override SlotEntity? GetPreviewSlot(DatabaseContext database, UserEntity user) // note: developer slots act up in LBP3 when listed here, so I omitted it
|
||||||
=> database.HeartedLevels.Where(h => h.UserId == user.UserId)
|
=> database.HeartedLevels.Where(h => h.UserId == user.UserId)
|
||||||
.Where(h => h.Slot.Type == SlotType.User && !h.Slot.Hidden && h.Slot.GameVersion <= GameVersion.LittleBigPlanet3)
|
.Where(h => h.Slot.Type == SlotType.User && !h.Slot.Hidden && h.Slot.GameVersion <= GameVersion.LittleBigPlanet3)
|
||||||
.OrderByDescending(h => h.HeartedLevelId)
|
.OrderByDescending(h => h.HeartedLevelId)
|
||||||
|
@ -24,7 +24,7 @@ public class HeartedCategory : CategoryWithUser
|
||||||
.ByGameVersion(GameVersion.LittleBigPlanet3, false, false, true)
|
.ByGameVersion(GameVersion.LittleBigPlanet3, false, false, true)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
public override IQueryable<Slot> GetSlots(DatabaseContext database, User user, int pageStart, int pageSize)
|
public override IQueryable<SlotEntity> GetSlots(DatabaseContext database, UserEntity user, int pageStart, int pageSize)
|
||||||
=> database.HeartedLevels.Where(h => h.UserId == user.UserId)
|
=> database.HeartedLevels.Where(h => h.UserId == user.UserId)
|
||||||
.Where(h => h.Slot.Type == SlotType.User && !h.Slot.Hidden && h.Slot.GameVersion <= GameVersion.LittleBigPlanet3)
|
.Where(h => h.Slot.Type == SlotType.User && !h.Slot.Hidden && h.Slot.GameVersion <= GameVersion.LittleBigPlanet3)
|
||||||
.OrderByDescending(h => h.HeartedLevelId)
|
.OrderByDescending(h => h.HeartedLevelId)
|
||||||
|
@ -34,5 +34,5 @@ public class HeartedCategory : CategoryWithUser
|
||||||
.Skip(Math.Max(0, pageStart))
|
.Skip(Math.Max(0, pageStart))
|
||||||
.Take(Math.Min(pageSize, 20));
|
.Take(Math.Min(pageSize, 20));
|
||||||
|
|
||||||
public override int GetTotalSlots(DatabaseContext database, User user) => database.HeartedLevels.Count(h => h.UserId == user.UserId);
|
public override int GetTotalSlots(DatabaseContext database, UserEntity user) => database.HeartedLevels.Count(h => h.UserId == user.UserId);
|
||||||
}
|
}
|
|
@ -14,8 +14,8 @@ public class HighestRatedCategory : Category
|
||||||
public override string Description { get; set; } = "Community Highest Rated content";
|
public override string Description { get; set; } = "Community Highest Rated content";
|
||||||
public override string IconHash { get; set; } = "g820603";
|
public override string IconHash { get; set; } = "g820603";
|
||||||
public override string Endpoint { get; set; } = "thumbs";
|
public override string Endpoint { get; set; } = "thumbs";
|
||||||
public override Slot? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User).AsEnumerable().MaxBy(s => s.Thumbsup);
|
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User).AsEnumerable().MaxBy(s => s.Thumbsup);
|
||||||
public override IEnumerable<Slot> GetSlots
|
public override IEnumerable<SlotEntity> GetSlots
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
(DatabaseContext database, int pageStart, int pageSize)
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
|
|
|
@ -14,8 +14,8 @@ public class LuckyDipCategory : Category
|
||||||
public override string Description { get; set; } = "Randomized uploaded content";
|
public override string Description { get; set; } = "Randomized uploaded content";
|
||||||
public override string IconHash { get; set; } = "g820605";
|
public override string IconHash { get; set; } = "g820605";
|
||||||
public override string Endpoint { get; set; } = "lbp2luckydip";
|
public override string Endpoint { get; set; } = "lbp2luckydip";
|
||||||
public override Slot? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User).OrderByDescending(_ => EF.Functions.Random()).FirstOrDefault();
|
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User).OrderByDescending(_ => EF.Functions.Random()).FirstOrDefault();
|
||||||
public override IQueryable<Slot> GetSlots
|
public override IQueryable<SlotEntity> GetSlots
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
(DatabaseContext database, int pageStart, int pageSize)
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
||||||
.OrderByDescending(_ => EF.Functions.Random())
|
.OrderByDescending(_ => EF.Functions.Random())
|
||||||
|
|
|
@ -14,8 +14,8 @@ public class MostHeartedCategory : Category
|
||||||
public override string Description { get; set; } = "The Most Hearted Content";
|
public override string Description { get; set; } = "The Most Hearted Content";
|
||||||
public override string IconHash { get; set; } = "g820607";
|
public override string IconHash { get; set; } = "g820607";
|
||||||
public override string Endpoint { get; set; } = "mostHearted";
|
public override string Endpoint { get; set; } = "mostHearted";
|
||||||
public override Slot? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User).AsEnumerable().MaxBy(s => s.Hearts);
|
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User).AsEnumerable().MaxBy(s => s.Hearts);
|
||||||
public override IEnumerable<Slot> GetSlots
|
public override IEnumerable<SlotEntity> GetSlots
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
(DatabaseContext database, int pageStart, int pageSize)
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
|
|
|
@ -13,12 +13,12 @@ public class MostPlayedCategory : Category
|
||||||
public override string Description { get; set; } = "The most played content";
|
public override string Description { get; set; } = "The most played content";
|
||||||
public override string IconHash { get; set; } = "g820608";
|
public override string IconHash { get; set; } = "g820608";
|
||||||
public override string Endpoint { get; set; } = "mostUniquePlays";
|
public override string Endpoint { get; set; } = "mostUniquePlays";
|
||||||
public override Slot? GetPreviewSlot(DatabaseContext database) => database.Slots
|
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots
|
||||||
.Where(s => s.Type == SlotType.User)
|
.Where(s => s.Type == SlotType.User)
|
||||||
.OrderByDescending(s => s.PlaysLBP1Unique + s.PlaysLBP2Unique + s.PlaysLBP3Unique)
|
.OrderByDescending(s => s.PlaysLBP1Unique + s.PlaysLBP2Unique + s.PlaysLBP3Unique)
|
||||||
.ThenByDescending(s => s.PlaysLBP1 + s.PlaysLBP2 + s.PlaysLBP3)
|
.ThenByDescending(s => s.PlaysLBP1 + s.PlaysLBP2 + s.PlaysLBP3)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
public override IQueryable<Slot> GetSlots
|
public override IQueryable<SlotEntity> GetSlots
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
(DatabaseContext database, int pageStart, int pageSize)
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
||||||
.OrderByDescending(s => s.PlaysLBP1Unique + s.PlaysLBP2Unique + s.PlaysLBP3Unique)
|
.OrderByDescending(s => s.PlaysLBP1Unique + s.PlaysLBP2Unique + s.PlaysLBP3Unique)
|
||||||
|
|
|
@ -13,8 +13,8 @@ public class NewestLevelsCategory : Category
|
||||||
public override string Description { get; set; } = "The most recently published content";
|
public override string Description { get; set; } = "The most recently published content";
|
||||||
public override string IconHash { get; set; } = "g820623";
|
public override string IconHash { get; set; } = "g820623";
|
||||||
public override string Endpoint { get; set; } = "newest";
|
public override string Endpoint { get; set; } = "newest";
|
||||||
public override Slot? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User).OrderByDescending(s => s.FirstUploaded).FirstOrDefault();
|
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User).OrderByDescending(s => s.FirstUploaded).FirstOrDefault();
|
||||||
public override IQueryable<Slot> GetSlots
|
public override IQueryable<SlotEntity> GetSlots
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
(DatabaseContext database, int pageStart, int pageSize)
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
||||||
.OrderByDescending(s => s.FirstUploaded)
|
.OrderByDescending(s => s.FirstUploaded)
|
||||||
|
|
|
@ -15,7 +15,7 @@ public class QueueCategory : CategoryWithUser
|
||||||
public override string Description { get; set; } = "Your queued content";
|
public override string Description { get; set; } = "Your queued content";
|
||||||
public override string IconHash { get; set; } = "g820614";
|
public override string IconHash { get; set; } = "g820614";
|
||||||
public override string Endpoint { get; set; } = "queue";
|
public override string Endpoint { get; set; } = "queue";
|
||||||
public override Slot? GetPreviewSlot(DatabaseContext database, User user)
|
public override SlotEntity? GetPreviewSlot(DatabaseContext database, UserEntity user)
|
||||||
=> database.QueuedLevels.Where(q => q.UserId == user.UserId)
|
=> database.QueuedLevels.Where(q => q.UserId == user.UserId)
|
||||||
.Where(q => q.Slot.Type == SlotType.User && !q.Slot.Hidden && q.Slot.GameVersion <= GameVersion.LittleBigPlanet3)
|
.Where(q => q.Slot.Type == SlotType.User && !q.Slot.Hidden && q.Slot.GameVersion <= GameVersion.LittleBigPlanet3)
|
||||||
.OrderByDescending(q => q.QueuedLevelId)
|
.OrderByDescending(q => q.QueuedLevelId)
|
||||||
|
@ -24,7 +24,7 @@ public class QueueCategory : CategoryWithUser
|
||||||
.ByGameVersion(GameVersion.LittleBigPlanet3, false, false, true)
|
.ByGameVersion(GameVersion.LittleBigPlanet3, false, false, true)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
public override IQueryable<Slot> GetSlots(DatabaseContext database, User user, int pageStart, int pageSize)
|
public override IQueryable<SlotEntity> GetSlots(DatabaseContext database, UserEntity user, int pageStart, int pageSize)
|
||||||
=> database.QueuedLevels.Where(q => q.UserId == user.UserId)
|
=> database.QueuedLevels.Where(q => q.UserId == user.UserId)
|
||||||
.Where(q => q.Slot.Type == SlotType.User && !q.Slot.Hidden && q.Slot.GameVersion <= GameVersion.LittleBigPlanet3)
|
.Where(q => q.Slot.Type == SlotType.User && !q.Slot.Hidden && q.Slot.GameVersion <= GameVersion.LittleBigPlanet3)
|
||||||
.OrderByDescending(q => q.QueuedLevelId)
|
.OrderByDescending(q => q.QueuedLevelId)
|
||||||
|
@ -34,5 +34,5 @@ public class QueueCategory : CategoryWithUser
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Skip(Math.Max(0, pageStart - 1))
|
||||||
.Take(Math.Min(pageSize, 20));
|
.Take(Math.Min(pageSize, 20));
|
||||||
|
|
||||||
public override int GetTotalSlots(DatabaseContext database, User user) => database.QueuedLevels.Count(q => q.UserId == user.UserId);
|
public override int GetTotalSlots(DatabaseContext database, UserEntity user) => database.QueuedLevels.Count(q => q.UserId == user.UserId);
|
||||||
}
|
}
|
|
@ -13,8 +13,8 @@ public class TeamPicksCategory : Category
|
||||||
public override string Description { get; set; } = "Community Team Picks";
|
public override string Description { get; set; } = "Community Team Picks";
|
||||||
public override string IconHash { get; set; } = "g820626";
|
public override string IconHash { get; set; } = "g820626";
|
||||||
public override string Endpoint { get; set; } = "team_picks";
|
public override string Endpoint { get; set; } = "team_picks";
|
||||||
public override Slot? GetPreviewSlot(DatabaseContext database) => database.Slots.OrderByDescending(s => s.FirstUploaded).FirstOrDefault(s => s.TeamPick);
|
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.OrderByDescending(s => s.FirstUploaded).FirstOrDefault(s => s.TeamPick);
|
||||||
public override IQueryable<Slot> GetSlots
|
public override IQueryable<SlotEntity> GetSlots
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
(DatabaseContext database, int pageStart, int pageSize)
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
||||||
.OrderByDescending(s => s.FirstUploaded)
|
.OrderByDescending(s => s.FirstUploaded)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Misc;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Misc;
|
||||||
|
|
||||||
|
@ -9,7 +10,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Misc;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[XmlRoot("resources")]
|
[XmlRoot("resources")]
|
||||||
[XmlType("resources")]
|
[XmlType("resources")]
|
||||||
public class ResourceList
|
public class ResourceList : ILbpSerializable
|
||||||
{
|
{
|
||||||
[XmlElement("resource")]
|
[XmlElement("resource")]
|
||||||
public string[]? Resources;
|
public string[]? Resources;
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users;
|
|
||||||
|
|
||||||
[Keyless]
|
|
||||||
public class ClientsConnected
|
|
||||||
{
|
|
||||||
public bool Lbp1 { get; set; }
|
|
||||||
public bool Lbp2 { get; set; }
|
|
||||||
public bool LbpMe { get; set; }
|
|
||||||
public bool Lbp3Ps3 { get; set; }
|
|
||||||
public bool Lbp3Ps4 { get; set; }
|
|
||||||
|
|
||||||
public string Serialize()
|
|
||||||
=> LbpSerializer.StringElement
|
|
||||||
(
|
|
||||||
"clientsConnected",
|
|
||||||
LbpSerializer.StringElement("lbp1", this.Lbp1) +
|
|
||||||
LbpSerializer.StringElement("lbp2", this.Lbp2) +
|
|
||||||
LbpSerializer.StringElement("lbpme", this.LbpMe) +
|
|
||||||
LbpSerializer.StringElement("lbp3ps3", this.Lbp3Ps3) +
|
|
||||||
LbpSerializer.StringElement("lbp3ps4", this.Lbp3Ps4)
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,24 +1,16 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Users;
|
||||||
|
|
||||||
[XmlRoot("privacySettings")]
|
[XmlRoot("privacySettings")]
|
||||||
[XmlType("privacySettings")]
|
[XmlType("privacySettings")]
|
||||||
public class PrivacySettings
|
public class PrivacySettings : ILbpSerializable
|
||||||
{
|
{
|
||||||
[XmlElement("levelVisiblity")]
|
[XmlElement("levelVisiblity")]
|
||||||
public string? LevelVisibility { get; set; }
|
public string? LevelVisibility { get; set; }
|
||||||
|
|
||||||
[XmlElement("profileVisiblity")]
|
[XmlElement("profileVisiblity")]
|
||||||
public string? ProfileVisibility { get; set; }
|
public string? ProfileVisibility { get; set; }
|
||||||
|
|
||||||
public string Serialize()
|
|
||||||
=> LbpSerializer.StringElement
|
|
||||||
(
|
|
||||||
"privacySettings",
|
|
||||||
LbpSerializer.StringElement("levelVisibility", this.LevelVisibility) +
|
|
||||||
LbpSerializer.StringElement("profileVisibility", this.ProfileVisibility)
|
|
||||||
);
|
|
||||||
}
|
}
|
|
@ -22,10 +22,10 @@ public class AdminReportController : ControllerBase
|
||||||
[HttpGet("remove")]
|
[HttpGet("remove")]
|
||||||
public async Task<IActionResult> DeleteReport([FromRoute] int id)
|
public async Task<IActionResult> DeleteReport([FromRoute] int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsAdmin) return this.StatusCode(403, "");
|
if (user == null || !user.IsAdmin) return this.Forbid();
|
||||||
|
|
||||||
GriefReport? report = await this.database.Reports.FirstOrDefaultAsync(r => r.ReportId == id);
|
GriefReportEntity? report = await this.database.Reports.FirstOrDefaultAsync(r => r.ReportId == id);
|
||||||
if (report == null) return this.NotFound();
|
if (report == null) return this.NotFound();
|
||||||
|
|
||||||
List<string> hashes = new()
|
List<string> hashes = new()
|
||||||
|
@ -49,10 +49,10 @@ public class AdminReportController : ControllerBase
|
||||||
[HttpGet("dismiss")]
|
[HttpGet("dismiss")]
|
||||||
public async Task<IActionResult> DismissReport([FromRoute] int id)
|
public async Task<IActionResult> DismissReport([FromRoute] int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsModerator) return this.StatusCode(403, "");
|
if (user == null || !user.IsModerator) return this.Forbid();
|
||||||
|
|
||||||
GriefReport? report = await this.database.Reports.FirstOrDefaultAsync(r => r.ReportId == id);
|
GriefReportEntity? report = await this.database.Reports.FirstOrDefaultAsync(r => r.ReportId == id);
|
||||||
if (report == null) return this.NotFound();
|
if (report == null) return this.NotFound();
|
||||||
|
|
||||||
FileHelper.DeleteResource(report.JpegHash);
|
FileHelper.DeleteResource(report.JpegHash);
|
||||||
|
|
|
@ -28,10 +28,10 @@ public class AdminUserController : ControllerBase
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpGet("wipePlanets")]
|
[HttpGet("wipePlanets")]
|
||||||
public async Task<IActionResult> WipePlanets([FromRoute] int id) {
|
public async Task<IActionResult> WipePlanets([FromRoute] int id) {
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsModerator) return this.NotFound();
|
if (user == null || !user.IsModerator) return this.NotFound();
|
||||||
|
|
||||||
User? targetedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
UserEntity? targetedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
if (targetedUser == null) return this.NotFound();
|
if (targetedUser == null) return this.NotFound();
|
||||||
|
|
||||||
string[] hashes = {
|
string[] hashes = {
|
||||||
|
@ -47,7 +47,7 @@ public class AdminUserController : ControllerBase
|
||||||
if (string.IsNullOrWhiteSpace(hash)) continue;
|
if (string.IsNullOrWhiteSpace(hash)) continue;
|
||||||
|
|
||||||
// Find users with a matching hash
|
// Find users with a matching hash
|
||||||
List<User> users = await this.database.Users
|
List<UserEntity> users = await this.database.Users
|
||||||
.Where(u => u.PlanetHashLBP2 == hash ||
|
.Where(u => u.PlanetHashLBP2 == hash ||
|
||||||
u.PlanetHashLBP3 == hash ||
|
u.PlanetHashLBP3 == hash ||
|
||||||
u.PlanetHashLBPVita == hash)
|
u.PlanetHashLBPVita == hash)
|
||||||
|
@ -57,7 +57,7 @@ public class AdminUserController : ControllerBase
|
||||||
System.Diagnostics.Debug.Assert(users.Count != 0);
|
System.Diagnostics.Debug.Assert(users.Count != 0);
|
||||||
|
|
||||||
// Reset each users' hash.
|
// Reset each users' hash.
|
||||||
foreach (User userWithPlanet in users)
|
foreach (UserEntity userWithPlanet in users)
|
||||||
{
|
{
|
||||||
userWithPlanet.PlanetHashLBP2 = "";
|
userWithPlanet.PlanetHashLBP2 = "";
|
||||||
userWithPlanet.PlanetHashLBP3 = "";
|
userWithPlanet.PlanetHashLBP3 = "";
|
||||||
|
@ -92,10 +92,10 @@ public class AdminUserController : ControllerBase
|
||||||
[HttpPost("/admin/user/{id:int}/setPermissionLevel")]
|
[HttpPost("/admin/user/{id:int}/setPermissionLevel")]
|
||||||
public async Task<IActionResult> SetUserPermissionLevel([FromRoute] int id, [FromForm] PermissionLevel role)
|
public async Task<IActionResult> SetUserPermissionLevel([FromRoute] int id, [FromForm] PermissionLevel role)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsAdmin) return this.NotFound();
|
if (user == null || !user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
User? targetedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
UserEntity? targetedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
if (targetedUser == null) return this.NotFound();
|
if (targetedUser == null) return this.NotFound();
|
||||||
|
|
||||||
if (role != PermissionLevel.Banned)
|
if (role != PermissionLevel.Banned)
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class AuthenticationController : ControllerBase
|
||||||
[HttpGet("unlink/{platform}")]
|
[HttpGet("unlink/{platform}")]
|
||||||
public async Task<IActionResult> UnlinkPlatform(string platform)
|
public async Task<IActionResult> UnlinkPlatform(string platform)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
Platform[] invalidTokens;
|
Platform[] invalidTokens;
|
||||||
|
@ -48,10 +48,10 @@ public class AuthenticationController : ControllerBase
|
||||||
[HttpGet("approve/{id:int}")]
|
[HttpGet("approve/{id:int}")]
|
||||||
public async Task<IActionResult> Approve(int id)
|
public async Task<IActionResult> Approve(int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("/login");
|
if (user == null) return this.Redirect("/login");
|
||||||
|
|
||||||
PlatformLinkAttempt? linkAttempt = await this.database.PlatformLinkAttempts
|
PlatformLinkAttemptEntity? linkAttempt = await this.database.PlatformLinkAttempts
|
||||||
.FirstOrDefaultAsync(l => l.PlatformLinkAttemptId == id);
|
.FirstOrDefaultAsync(l => l.PlatformLinkAttemptId == id);
|
||||||
if (linkAttempt == null) return this.NotFound();
|
if (linkAttempt == null) return this.NotFound();
|
||||||
|
|
||||||
|
@ -76,10 +76,10 @@ public class AuthenticationController : ControllerBase
|
||||||
[HttpGet("deny/{id:int}")]
|
[HttpGet("deny/{id:int}")]
|
||||||
public async Task<IActionResult> Deny(int id)
|
public async Task<IActionResult> Deny(int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("/login");
|
if (user == null) return this.Redirect("/login");
|
||||||
|
|
||||||
PlatformLinkAttempt? linkAttempt = await this.database.PlatformLinkAttempts
|
PlatformLinkAttemptEntity? linkAttempt = await this.database.PlatformLinkAttempts
|
||||||
.FirstOrDefaultAsync(l => l.PlatformLinkAttemptId == id);
|
.FirstOrDefaultAsync(l => l.PlatformLinkAttemptId == id);
|
||||||
if (linkAttempt == null) return this.NotFound();
|
if (linkAttempt == null) return this.NotFound();
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@ public class ModerationCaseController : ControllerBase
|
||||||
[HttpGet("dismiss")]
|
[HttpGet("dismiss")]
|
||||||
public async Task<IActionResult> DismissCase([FromRoute] int id)
|
public async Task<IActionResult> DismissCase([FromRoute] int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsModerator) return this.StatusCode(403, "");
|
if (user == null || !user.IsModerator) return this.Forbid();
|
||||||
|
|
||||||
ModerationCase? @case = await this.database.Cases.FirstOrDefaultAsync(c => c.CaseId == id);
|
ModerationCaseEntity? @case = await this.database.Cases.FirstOrDefaultAsync(c => c.CaseId == id);
|
||||||
if (@case == null) return this.NotFound();
|
if (@case == null) return this.NotFound();
|
||||||
|
|
||||||
@case.DismissedAt = DateTime.Now;
|
@case.DismissedAt = DateTime.Now;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
@ -17,9 +18,9 @@ public class ModerationRemovalController : ControllerBase
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IActionResult> Delete<T>(DbSet<T> dbSet, int id, string? callbackUrl, Func<User, int, Task<T?>> getHandler) where T: class
|
private async Task<IActionResult> Delete<T>(DbSet<T> dbSet, int id, string? callbackUrl, Func<UserEntity, int, Task<T?>> getHandler) where T: class
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
T? item = await getHandler(user, id);
|
T? item = await getHandler(user, id);
|
||||||
|
@ -34,9 +35,9 @@ public class ModerationRemovalController : ControllerBase
|
||||||
[HttpGet("deleteScore/{scoreId:int}")]
|
[HttpGet("deleteScore/{scoreId:int}")]
|
||||||
public async Task<IActionResult> DeleteScore(int scoreId, [FromQuery] string? callbackUrl)
|
public async Task<IActionResult> DeleteScore(int scoreId, [FromQuery] string? callbackUrl)
|
||||||
{
|
{
|
||||||
return await this.Delete<Score>(this.database.Scores, scoreId, callbackUrl, async (user, id) =>
|
return await this.Delete<ScoreEntity>(this.database.Scores, scoreId, callbackUrl, async (user, id) =>
|
||||||
{
|
{
|
||||||
Score? score = await this.database.Scores.Include(s => s.Slot).FirstOrDefaultAsync(s => s.ScoreId == id);
|
ScoreEntity? score = await this.database.Scores.Include(s => s.Slot).FirstOrDefaultAsync(s => s.ScoreId == id);
|
||||||
if (score == null) return null;
|
if (score == null) return null;
|
||||||
|
|
||||||
return user.IsModerator ? score : null;
|
return user.IsModerator ? score : null;
|
||||||
|
@ -46,10 +47,10 @@ public class ModerationRemovalController : ControllerBase
|
||||||
[HttpGet("deleteComment/{commentId:int}")]
|
[HttpGet("deleteComment/{commentId:int}")]
|
||||||
public async Task<IActionResult> DeleteComment(int commentId, [FromQuery] string? callbackUrl)
|
public async Task<IActionResult> DeleteComment(int commentId, [FromQuery] string? callbackUrl)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
Comment? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
|
CommentEntity? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
|
||||||
if (comment == null) return this.Redirect("~/404");
|
if (comment == null) return this.Redirect("~/404");
|
||||||
|
|
||||||
if (comment.Deleted) return this.Redirect(callbackUrl ?? "~/");
|
if (comment.Deleted) return this.Redirect(callbackUrl ?? "~/");
|
||||||
|
@ -82,10 +83,10 @@ public class ModerationRemovalController : ControllerBase
|
||||||
[HttpGet("deleteReview/{reviewId:int}")]
|
[HttpGet("deleteReview/{reviewId:int}")]
|
||||||
public async Task<IActionResult> DeleteReview(int reviewId, [FromQuery] string? callbackUrl)
|
public async Task<IActionResult> DeleteReview(int reviewId, [FromQuery] string? callbackUrl)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
Review? review = await this.database.Reviews.Include(r => r.Slot).FirstOrDefaultAsync(c => c.ReviewId == reviewId);
|
ReviewEntity? review = await this.database.Reviews.Include(r => r.Slot).FirstOrDefaultAsync(c => c.ReviewId == reviewId);
|
||||||
if (review == null) return this.Redirect("~/404");
|
if (review == null) return this.Redirect("~/404");
|
||||||
|
|
||||||
if (review.Deleted) return this.Redirect(callbackUrl ?? "~/");
|
if (review.Deleted) return this.Redirect(callbackUrl ?? "~/");
|
||||||
|
@ -103,9 +104,9 @@ public class ModerationRemovalController : ControllerBase
|
||||||
[HttpGet("deletePhoto/{photoId:int}")]
|
[HttpGet("deletePhoto/{photoId:int}")]
|
||||||
public async Task<IActionResult> DeletePhoto(int photoId, [FromQuery] string? callbackUrl)
|
public async Task<IActionResult> DeletePhoto(int photoId, [FromQuery] string? callbackUrl)
|
||||||
{
|
{
|
||||||
return await this.Delete<Photo>(this.database.Photos, photoId, callbackUrl, async (user, id) =>
|
return await this.Delete<PhotoEntity>(this.database.Photos, photoId, callbackUrl, async (user, id) =>
|
||||||
{
|
{
|
||||||
Photo? photo = await this.database.Photos.Include(p => p.Slot).FirstOrDefaultAsync(p => p.PhotoId == id);
|
PhotoEntity? photo = await this.database.Photos.Include(p => p.Slot).FirstOrDefaultAsync(p => p.PhotoId == id);
|
||||||
if (photo == null) return null;
|
if (photo == null) return null;
|
||||||
|
|
||||||
if (!user.IsModerator && photo.CreatorId != user.UserId) return null;
|
if (!user.IsModerator && photo.CreatorId != user.UserId) return null;
|
||||||
|
|
|
@ -23,10 +23,10 @@ public class ModerationSlotController : ControllerBase
|
||||||
[HttpGet("teamPick")]
|
[HttpGet("teamPick")]
|
||||||
public async Task<IActionResult> TeamPick([FromRoute] int id)
|
public async Task<IActionResult> TeamPick([FromRoute] int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsModerator) return this.StatusCode(403, "");
|
if (user == null || !user.IsModerator) return this.Forbid();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.Include(s => s.Creator).FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? slot = await this.database.Slots.Include(s => s.Creator).FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (slot == null) return this.NotFound();
|
if (slot == null) return this.NotFound();
|
||||||
|
|
||||||
slot.TeamPick = true;
|
slot.TeamPick = true;
|
||||||
|
@ -42,10 +42,10 @@ public class ModerationSlotController : ControllerBase
|
||||||
[HttpGet("removeTeamPick")]
|
[HttpGet("removeTeamPick")]
|
||||||
public async Task<IActionResult> RemoveTeamPick([FromRoute] int id)
|
public async Task<IActionResult> RemoveTeamPick([FromRoute] int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsModerator) return this.StatusCode(403, "");
|
if (user == null || !user.IsModerator) return this.Forbid();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (slot == null) return this.NotFound();
|
if (slot == null) return this.NotFound();
|
||||||
|
|
||||||
slot.TeamPick = false;
|
slot.TeamPick = false;
|
||||||
|
@ -58,10 +58,10 @@ public class ModerationSlotController : ControllerBase
|
||||||
[HttpGet("delete")]
|
[HttpGet("delete")]
|
||||||
public async Task<IActionResult> DeleteLevel([FromRoute] int id)
|
public async Task<IActionResult> DeleteLevel([FromRoute] int id)
|
||||||
{
|
{
|
||||||
User? user = this.database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsModerator) return this.StatusCode(403, "");
|
if (user == null || !user.IsModerator) return this.Forbid();
|
||||||
|
|
||||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (slot == null) return this.Ok();
|
if (slot == null) return this.Ok();
|
||||||
|
|
||||||
await this.database.RemoveSlot(slot);
|
await this.database.RemoveSlot(slot);
|
||||||
|
|
|
@ -30,10 +30,10 @@ public class SlotPageController : ControllerBase
|
||||||
[HttpGet("unpublish")]
|
[HttpGet("unpublish")]
|
||||||
public async Task<IActionResult> UnpublishSlot([FromRoute] int id)
|
public async Task<IActionResult> UnpublishSlot([FromRoute] int id)
|
||||||
{
|
{
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
Slot? targetSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? targetSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (targetSlot == null) return this.Redirect("~/slots/0");
|
if (targetSlot == null) return this.Redirect("~/slots/0");
|
||||||
|
|
||||||
if (targetSlot.CreatorId != token.UserId) return this.Redirect("~/slot/" + id);
|
if (targetSlot.CreatorId != token.UserId) return this.Redirect("~/slot/" + id);
|
||||||
|
@ -48,7 +48,7 @@ public class SlotPageController : ControllerBase
|
||||||
[HttpGet("rateComment")]
|
[HttpGet("rateComment")]
|
||||||
public async Task<IActionResult> RateComment([FromRoute] int id, [FromQuery] int commentId, [FromQuery] int rating)
|
public async Task<IActionResult> RateComment([FromRoute] int id, [FromQuery] int commentId, [FromQuery] int rating)
|
||||||
{
|
{
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
await this.database.RateComment(token.UserId, commentId, rating);
|
await this.database.RateComment(token.UserId, commentId, rating);
|
||||||
|
@ -59,7 +59,7 @@ public class SlotPageController : ControllerBase
|
||||||
[HttpPost("postComment")]
|
[HttpPost("postComment")]
|
||||||
public async Task<IActionResult> PostComment([FromRoute] int id, [FromForm] string? msg)
|
public async Task<IActionResult> PostComment([FromRoute] int id, [FromForm] string? msg)
|
||||||
{
|
{
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
if (msg == null)
|
if (msg == null)
|
||||||
|
@ -90,10 +90,10 @@ public class SlotPageController : ControllerBase
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
|
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
|
||||||
|
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
Slot? heartedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? heartedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (heartedSlot == null) return this.NotFound();
|
if (heartedSlot == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.HeartLevel(token.UserId, heartedSlot);
|
await this.database.HeartLevel(token.UserId, heartedSlot);
|
||||||
|
@ -106,10 +106,10 @@ public class SlotPageController : ControllerBase
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
|
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
|
||||||
|
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
Slot? heartedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? heartedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (heartedSlot == null) return this.NotFound();
|
if (heartedSlot == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.UnheartLevel(token.UserId, heartedSlot);
|
await this.database.UnheartLevel(token.UserId, heartedSlot);
|
||||||
|
@ -122,10 +122,10 @@ public class SlotPageController : ControllerBase
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
|
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
|
||||||
|
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
Slot? queuedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? queuedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (queuedSlot == null) return this.NotFound();
|
if (queuedSlot == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.QueueLevel(token.UserId, queuedSlot);
|
await this.database.QueueLevel(token.UserId, queuedSlot);
|
||||||
|
@ -138,10 +138,10 @@ public class SlotPageController : ControllerBase
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
|
if (string.IsNullOrEmpty(callbackUrl)) callbackUrl = "~/slot/" + id;
|
||||||
|
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
Slot? queuedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
SlotEntity? queuedSlot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
|
||||||
if (queuedSlot == null) return this.NotFound();
|
if (queuedSlot == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.UnqueueLevel(token.UserId, queuedSlot);
|
await this.database.UnqueueLevel(token.UserId, queuedSlot);
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class UserPageController : ControllerBase
|
||||||
[HttpGet("rateComment")]
|
[HttpGet("rateComment")]
|
||||||
public async Task<IActionResult> RateComment([FromRoute] int id, [FromQuery] int? commentId, [FromQuery] int? rating)
|
public async Task<IActionResult> RateComment([FromRoute] int id, [FromQuery] int? commentId, [FromQuery] int? rating)
|
||||||
{
|
{
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
await this.database.RateComment(token.UserId, commentId.GetValueOrDefault(), rating.GetValueOrDefault());
|
await this.database.RateComment(token.UserId, commentId.GetValueOrDefault(), rating.GetValueOrDefault());
|
||||||
|
@ -35,7 +35,7 @@ public class UserPageController : ControllerBase
|
||||||
[HttpPost("postComment")]
|
[HttpPost("postComment")]
|
||||||
public async Task<IActionResult> PostComment([FromRoute] int id, [FromForm] string? msg)
|
public async Task<IActionResult> PostComment([FromRoute] int id, [FromForm] string? msg)
|
||||||
{
|
{
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
if (msg == null)
|
if (msg == null)
|
||||||
|
@ -64,10 +64,10 @@ public class UserPageController : ControllerBase
|
||||||
[HttpGet("heart")]
|
[HttpGet("heart")]
|
||||||
public async Task<IActionResult> HeartUser([FromRoute] int id)
|
public async Task<IActionResult> HeartUser([FromRoute] int id)
|
||||||
{
|
{
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
UserEntity? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
if (heartedUser == null) return this.NotFound();
|
if (heartedUser == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.HeartUser(token.UserId, heartedUser);
|
await this.database.HeartUser(token.UserId, heartedUser);
|
||||||
|
@ -78,10 +78,10 @@ public class UserPageController : ControllerBase
|
||||||
[HttpGet("unheart")]
|
[HttpGet("unheart")]
|
||||||
public async Task<IActionResult> UnheartUser([FromRoute] int id)
|
public async Task<IActionResult> UnheartUser([FromRoute] int id)
|
||||||
{
|
{
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
UserEntity? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
if (heartedUser == null) return this.NotFound();
|
if (heartedUser == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.UnheartUser(token.UserId, heartedUser);
|
await this.database.UnheartUser(token.UserId, heartedUser);
|
||||||
|
@ -92,10 +92,10 @@ public class UserPageController : ControllerBase
|
||||||
[HttpGet("block")]
|
[HttpGet("block")]
|
||||||
public async Task<IActionResult> BlockUser([FromRoute] int id)
|
public async Task<IActionResult> BlockUser([FromRoute] int id)
|
||||||
{
|
{
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
User? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
UserEntity? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
if (blockedUser == null) return this.NotFound();
|
if (blockedUser == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.BlockUser(token.UserId, blockedUser);
|
await this.database.BlockUser(token.UserId, blockedUser);
|
||||||
|
@ -106,10 +106,10 @@ public class UserPageController : ControllerBase
|
||||||
[HttpGet("unblock")]
|
[HttpGet("unblock")]
|
||||||
public async Task<IActionResult> UnblockUser([FromRoute] int id)
|
public async Task<IActionResult> UnblockUser([FromRoute] int id)
|
||||||
{
|
{
|
||||||
WebToken? token = this.database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
User? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
UserEntity? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
if (blockedUser == null) return this.NotFound();
|
if (blockedUser == null) return this.NotFound();
|
||||||
|
|
||||||
await this.database.UnblockUser(token.UserId, blockedUser);
|
await this.database.UnblockUser(token.UserId, blockedUser);
|
||||||
|
|
|
@ -32,15 +32,15 @@ public static class PartialExtensions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<IHtmlContent> ToLink<T>(this User user, IHtmlHelper<T> helper, ViewDataDictionary<T> viewData, string language, string timeZone = "", bool includeStatus = false)
|
public static Task<IHtmlContent> ToLink<T>(this UserEntity user, IHtmlHelper<T> helper, ViewDataDictionary<T> viewData, string language, string timeZone = "", bool includeStatus = false)
|
||||||
=> helper.PartialAsync("Partials/Links/UserLinkPartial", user, viewData.WithLang(language).WithTime(timeZone).WithKeyValue("IncludeStatus", includeStatus));
|
=> helper.PartialAsync("Partials/Links/UserLinkPartial", user, viewData.WithLang(language).WithTime(timeZone).WithKeyValue("IncludeStatus", includeStatus));
|
||||||
|
|
||||||
public static Task<IHtmlContent> ToHtml<T>
|
public static Task<IHtmlContent> ToHtml<T>
|
||||||
(
|
(
|
||||||
this Slot slot,
|
this SlotEntity slot,
|
||||||
IHtmlHelper<T> helper,
|
IHtmlHelper<T> helper,
|
||||||
ViewDataDictionary<T> viewData,
|
ViewDataDictionary<T> viewData,
|
||||||
User? user,
|
UserEntity? user,
|
||||||
string callbackUrl,
|
string callbackUrl,
|
||||||
string language = "",
|
string language = "",
|
||||||
string timeZone = "",
|
string timeZone = "",
|
||||||
|
@ -55,6 +55,6 @@ public static class PartialExtensions
|
||||||
.WithKeyValue("IsMini", isMini)
|
.WithKeyValue("IsMini", isMini)
|
||||||
.WithKeyValue("IsMobile", isMobile));
|
.WithKeyValue("IsMobile", isMobile));
|
||||||
|
|
||||||
public static Task<IHtmlContent> ToHtml<T>(this Photo photo, IHtmlHelper<T> helper, ViewDataDictionary<T> viewData, string language, string timeZone, bool canDelete = false)
|
public static Task<IHtmlContent> ToHtml<T>(this PhotoEntity photo, IHtmlHelper<T> helper, ViewDataDictionary<T> viewData, string language, string timeZone, bool canDelete = false)
|
||||||
=> helper.PartialAsync("Partials/PhotoPartial", photo, viewData.WithLang(language).WithTime(timeZone).CanDelete(canDelete));
|
=> helper.PartialAsync("Partials/PhotoPartial", photo, viewData.WithLang(language).WithTime(timeZone).CanDelete(canDelete));
|
||||||
}
|
}
|
|
@ -14,14 +14,14 @@ public class UserRequiredRedirectMiddleware : MiddlewareDBContext
|
||||||
|
|
||||||
public override async Task InvokeAsync(HttpContext ctx, DatabaseContext database)
|
public override async Task InvokeAsync(HttpContext ctx, DatabaseContext database)
|
||||||
{
|
{
|
||||||
WebToken? token = database.WebTokenFromRequest(ctx.Request);
|
WebTokenEntity? token = database.WebTokenFromRequest(ctx.Request);
|
||||||
if (token == null || pathContains(ctx, "/logout"))
|
if (token == null || pathContains(ctx, "/logout"))
|
||||||
{
|
{
|
||||||
await this.next(ctx);
|
await this.next(ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
User? user = await database.Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
await this.next(ctx);
|
await this.next(ctx);
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="ui four column grid">
|
<div class="ui four column grid">
|
||||||
@foreach (ApiKey key in Model.ApiKeys)
|
@foreach (ApiKeyEntity key in Model.ApiKeys)
|
||||||
{
|
{
|
||||||
<div id="keyitem-@key.Id" class="five wide column">
|
<div id="keyitem-@key.Id" class="five wide column">
|
||||||
<div class="ui blue segment">
|
<div class="ui blue segment">
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.Admin;
|
||||||
|
|
||||||
public class AdminApiKeyPageModel : BaseLayout
|
public class AdminApiKeyPageModel : BaseLayout
|
||||||
{
|
{
|
||||||
public List<ApiKey> ApiKeys = new();
|
public List<ApiKeyEntity> ApiKeys = new();
|
||||||
public int KeyCount;
|
public int KeyCount;
|
||||||
|
|
||||||
public AdminApiKeyPageModel(DatabaseContext database) : base(database)
|
public AdminApiKeyPageModel(DatabaseContext database) : base(database)
|
||||||
|
@ -17,7 +17,7 @@ public class AdminApiKeyPageModel : BaseLayout
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet()
|
public async Task<IActionResult> OnGet()
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
if (!user.IsAdmin) return this.NotFound();
|
if (!user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
|
@ -29,10 +29,10 @@ public class AdminApiKeyPageModel : BaseLayout
|
||||||
|
|
||||||
public async Task<IActionResult> OnPost(string keyId)
|
public async Task<IActionResult> OnPost(string keyId)
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsAdmin) return this.NotFound();
|
if (user == null || !user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
ApiKey? apiKey = await this.Database.APIKeys.FirstOrDefaultAsync(k => k.Id == int.Parse(keyId));
|
ApiKeyEntity? apiKey = await this.Database.APIKeys.FirstOrDefaultAsync(k => k.Id == int.Parse(keyId));
|
||||||
if (apiKey == null) return this.NotFound();
|
if (apiKey == null) return this.NotFound();
|
||||||
this.Database.APIKeys.Remove(apiKey);
|
this.Database.APIKeys.Remove(apiKey);
|
||||||
await this.Database.SaveChangesAsync();
|
await this.Database.SaveChangesAsync();
|
||||||
|
|
|
@ -24,7 +24,7 @@ public class AdminPanelPage : BaseLayout
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet([FromQuery] string? args, [FromQuery] string? command, [FromQuery] string? maintenanceJob, [FromQuery] string? log)
|
public async Task<IActionResult> OnGet([FromQuery] string? args, [FromQuery] string? command, [FromQuery] string? maintenanceJob, [FromQuery] string? log)
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
if (!user.IsAdmin) return this.NotFound();
|
if (!user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<p><b>Note:</b> Users are ordered by their permissions, then by most-recent-first.</p>
|
<p><b>Note:</b> Users are ordered by their permissions, then by most-recent-first.</p>
|
||||||
|
|
||||||
<div class="ui grid">
|
<div class="ui grid">
|
||||||
@foreach (User user in Model.Users)
|
@foreach (UserEntity user in Model.Users)
|
||||||
{
|
{
|
||||||
string color;
|
string color;
|
||||||
string subtitle;
|
string subtitle;
|
||||||
|
|
|
@ -11,13 +11,13 @@ public class AdminPanelUsersPage : BaseLayout
|
||||||
{
|
{
|
||||||
public int UserCount;
|
public int UserCount;
|
||||||
|
|
||||||
public List<User> Users = new();
|
public List<UserEntity> Users = new();
|
||||||
public AdminPanelUsersPage(DatabaseContext database) : base(database)
|
public AdminPanelUsersPage(DatabaseContext database) : base(database)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet()
|
public async Task<IActionResult> OnGet()
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
if (!user.IsAdmin) return this.NotFound();
|
if (!user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,11 @@ public class AdminSetGrantedSlotsPage : BaseLayout
|
||||||
public AdminSetGrantedSlotsPage(DatabaseContext database) : base(database)
|
public AdminSetGrantedSlotsPage(DatabaseContext database) : base(database)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public User? TargetedUser;
|
public UserEntity? TargetedUser;
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet([FromRoute] int id)
|
public async Task<IActionResult> OnGet([FromRoute] int id)
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsAdmin) return this.NotFound();
|
if (user == null || !user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
this.TargetedUser = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
this.TargetedUser = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
|
@ -27,7 +27,7 @@ public class AdminSetGrantedSlotsPage : BaseLayout
|
||||||
|
|
||||||
public async Task<IActionResult> OnPost([FromRoute] int id, int grantedSlotCount)
|
public async Task<IActionResult> OnPost([FromRoute] int id, int grantedSlotCount)
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsAdmin) return this.NotFound();
|
if (user == null || !user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
this.TargetedUser = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
this.TargetedUser = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
}
|
}
|
||||||
<p>@room.PlayerIds.Count players, state is @room.State, version is @room.RoomVersion.ToPrettyString() on platform @room.RoomPlatform</p>
|
<p>@room.PlayerIds.Count players, state is @room.State, version is @room.RoomVersion.ToPrettyString() on platform @room.RoomPlatform</p>
|
||||||
<p>Slot type: @room.Slot.SlotType, slot id: @room.Slot.SlotId</p>
|
<p>Slot type: @room.Slot.SlotType, slot id: @room.Slot.SlotId</p>
|
||||||
@foreach (User player in room.GetPlayers(Model.Database))
|
@foreach (UserEntity player in room.GetPlayers(Model.Database))
|
||||||
{
|
{
|
||||||
<div class="ui segment">@player.Username</div>
|
<div class="ui segment">@player.Username</div>
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class RoomVisualizerPage : BaseLayout
|
||||||
public IActionResult OnGet()
|
public IActionResult OnGet()
|
||||||
{
|
{
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsAdmin) return this.NotFound();
|
if (user == null || !user.IsAdmin) return this.NotFound();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,14 @@ public class CompleteEmailVerificationPage : BaseLayout
|
||||||
{
|
{
|
||||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
||||||
|
|
||||||
EmailVerificationToken? emailVerifyToken = await this.Database.EmailVerificationTokens.FirstOrDefaultAsync(e => e.EmailToken == token);
|
EmailVerificationTokenEntity? emailVerifyToken = await this.Database.EmailVerificationTokens.FirstOrDefaultAsync(e => e.EmailToken == token);
|
||||||
if (emailVerifyToken == null)
|
if (emailVerifyToken == null)
|
||||||
{
|
{
|
||||||
this.Error = "Invalid verification token";
|
this.Error = "Invalid verification token";
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
User user = await this.Database.Users.FirstAsync(u => u.UserId == emailVerifyToken.UserId);
|
UserEntity user = await this.Database.Users.FirstAsync(u => u.UserId == emailVerifyToken.UserId);
|
||||||
|
|
||||||
if (DateTime.Now > emailVerifyToken.ExpiresAt)
|
if (DateTime.Now > emailVerifyToken.ExpiresAt)
|
||||||
{
|
{
|
||||||
|
@ -50,7 +50,7 @@ public class CompleteEmailVerificationPage : BaseLayout
|
||||||
if (user.Password != null) return this.Page();
|
if (user.Password != null) return this.Page();
|
||||||
|
|
||||||
// if user's account was created automatically
|
// if user's account was created automatically
|
||||||
WebToken webToken = new()
|
WebTokenEntity webToken = new()
|
||||||
{
|
{
|
||||||
ExpiresAt = DateTime.Now.AddDays(7),
|
ExpiresAt = DateTime.Now.AddDays(7),
|
||||||
Verified = true,
|
Verified = true,
|
||||||
|
|
|
@ -19,7 +19,7 @@ public class SendVerificationEmailPage : BaseLayout
|
||||||
{
|
{
|
||||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
||||||
|
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("/login");
|
if (user == null) return this.Redirect("/login");
|
||||||
|
|
||||||
if (user.EmailAddressVerified) return this.Redirect("/");
|
if (user.EmailAddressVerified) return this.Redirect("/");
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class SetEmailForm : BaseLayout
|
||||||
public IActionResult OnGet()
|
public IActionResult OnGet()
|
||||||
{
|
{
|
||||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
||||||
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("/login");
|
if (token == null) return this.Redirect("/login");
|
||||||
|
|
||||||
return this.Page();
|
return this.Page();
|
||||||
|
@ -33,10 +33,10 @@ public class SetEmailForm : BaseLayout
|
||||||
{
|
{
|
||||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
if (!ServerConfiguration.Instance.Mail.MailEnabled) return this.NotFound();
|
||||||
|
|
||||||
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/login");
|
if (token == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
UserEntity? user = await this.Database.Users.FirstOrDefaultAsync(u => u.UserId == token.UserId);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
if (!SanitizationHelper.IsValidEmail(emailAddress))
|
if (!SanitizationHelper.IsValidEmail(emailAddress))
|
||||||
|
|
|
@ -22,7 +22,7 @@ else
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@foreach (PlatformLinkAttempt authAttempt in Model.LinkAttempts)
|
@foreach (PlatformLinkAttemptEntity authAttempt in Model.LinkAttempts)
|
||||||
{
|
{
|
||||||
DateTimeOffset timestamp = TimeZoneInfo.ConvertTime(DateTimeOffset.FromUnixTimeMilliseconds(authAttempt.Timestamp), timeZoneInfo);
|
DateTimeOffset timestamp = TimeZoneInfo.ConvertTime(DateTimeOffset.FromUnixTimeMilliseconds(authAttempt.Timestamp), timeZoneInfo);
|
||||||
<div class="ui red segment">
|
<div class="ui red segment">
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.Website.Pages.ExternalAuth;
|
||||||
public class AuthenticationPage : BaseLayout
|
public class AuthenticationPage : BaseLayout
|
||||||
{
|
{
|
||||||
|
|
||||||
public List<PlatformLinkAttempt> LinkAttempts = new();
|
public List<PlatformLinkAttemptEntity> LinkAttempts = new();
|
||||||
|
|
||||||
public IPAddress? IpAddress;
|
public IPAddress? IpAddress;
|
||||||
public AuthenticationPage(DatabaseContext database) : base(database)
|
public AuthenticationPage(DatabaseContext database) : base(database)
|
||||||
|
@ -18,7 +18,7 @@ public class AuthenticationPage : BaseLayout
|
||||||
|
|
||||||
public IActionResult OnGet()
|
public IActionResult OnGet()
|
||||||
{
|
{
|
||||||
if (this.User == null) return this.StatusCode(403, "");
|
if (this.User == null) return this.Forbid();
|
||||||
|
|
||||||
this.IpAddress = this.HttpContext.Connection.RemoteIpAddress;
|
this.IpAddress = this.HttpContext.Connection.RemoteIpAddress;
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
|
|
||||||
@{
|
@{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (User user in Model.PlayersOnline)
|
foreach (UserEntity user in Model.PlayersOnline)
|
||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
@await user.ToLink(Html, ViewData, language, timeZone, true)
|
@await user.ToLink(Html, ViewData, language, timeZone, true)
|
||||||
|
@ -66,7 +66,7 @@
|
||||||
<h1><i class="star icon"></i>@Model.Translate(LandingPageStrings.LatestTeamPicks)</h1>
|
<h1><i class="star icon"></i>@Model.Translate(LandingPageStrings.LatestTeamPicks)</h1>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<div class="ui left aligned segment">
|
<div class="ui left aligned segment">
|
||||||
@foreach (Slot slot in Model.LatestTeamPicks!) @* Can't reach a point where this is null *@
|
@foreach (SlotEntity slot in Model.LatestTeamPicks!) @* Can't reach a point where this is null *@
|
||||||
{
|
{
|
||||||
@await slot.ToHtml(Html, ViewData, Model.User, $"~/slot/{slot.SlotId}", language, timeZone, isMobile, true, true)
|
@await slot.ToHtml(Html, ViewData, Model.User, $"~/slot/{slot.SlotId}", language, timeZone, isMobile, true, true)
|
||||||
<br>
|
<br>
|
||||||
|
@ -83,7 +83,7 @@
|
||||||
<h1><i class="globe americas icon"></i>@Model.Translate(LandingPageStrings.NewestLevels)</h1>
|
<h1><i class="globe americas icon"></i>@Model.Translate(LandingPageStrings.NewestLevels)</h1>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<div class="ui left aligned segment">
|
<div class="ui left aligned segment">
|
||||||
@foreach (Slot slot in Model.NewestLevels!) @* Can't reach a point where this is null *@
|
@foreach (SlotEntity slot in Model.NewestLevels!) @* Can't reach a point where this is null *@
|
||||||
{
|
{
|
||||||
@await slot.ToHtml(Html, ViewData, Model.User, $"~/slot/{slot.SlotId}", language, timeZone, isMobile, true, true)
|
@await slot.ToHtml(Html, ViewData, Model.User, $"~/slot/{slot.SlotId}", language, timeZone, isMobile, true, true)
|
||||||
<br>
|
<br>
|
||||||
|
|
|
@ -17,15 +17,15 @@ public class LandingPage : BaseLayout
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public int PendingAuthAttempts;
|
public int PendingAuthAttempts;
|
||||||
public List<User> PlayersOnline = new();
|
public List<UserEntity> PlayersOnline = new();
|
||||||
|
|
||||||
public List<Slot>? LatestTeamPicks;
|
public List<SlotEntity>? LatestTeamPicks;
|
||||||
public List<Slot>? NewestLevels;
|
public List<SlotEntity>? NewestLevels;
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public async Task<IActionResult> OnGet()
|
public async Task<IActionResult> OnGet()
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user != null && user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
|
if (user != null && user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
|
||||||
|
|
||||||
if (user != null)
|
if (user != null)
|
||||||
|
|
|
@ -25,7 +25,7 @@ public class BaseLayout : PageModel
|
||||||
|
|
||||||
public string Title = string.Empty;
|
public string Title = string.Empty;
|
||||||
|
|
||||||
private User? user;
|
private UserEntity? user;
|
||||||
public BaseLayout(DatabaseContext database)
|
public BaseLayout(DatabaseContext database)
|
||||||
{
|
{
|
||||||
this.Database = database;
|
this.Database = database;
|
||||||
|
@ -35,7 +35,7 @@ public class BaseLayout : PageModel
|
||||||
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderSlots, "/slots/0", "globe americas"));
|
this.NavigationItems.Add(new PageNavigationItem(BaseLayoutStrings.HeaderSlots, "/slots/0", "globe americas"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public new User? User {
|
public new UserEntity? User {
|
||||||
get {
|
get {
|
||||||
if (this.user != null) return this.user;
|
if (this.user != null) return this.user;
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class LoginForm : BaseLayout
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
User? user;
|
UserEntity? user;
|
||||||
|
|
||||||
if (!ServerConfiguration.Instance.Mail.MailEnabled)
|
if (!ServerConfiguration.Instance.Mail.MailEnabled)
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,7 @@ public class LoginForm : BaseLayout
|
||||||
user = await this.Database.Users.FirstOrDefaultAsync(u => u.EmailAddress == username);
|
user = await this.Database.Users.FirstOrDefaultAsync(u => u.EmailAddress == username);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
User? noEmailUser = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
UserEntity? noEmailUser = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
if (noEmailUser != null && noEmailUser.EmailAddress == null) user = noEmailUser;
|
if (noEmailUser != null && noEmailUser.EmailAddress == null) user = noEmailUser;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ public class LoginForm : BaseLayout
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
WebToken webToken = new()
|
WebTokenEntity webToken = new()
|
||||||
{
|
{
|
||||||
UserId = user.UserId,
|
UserId = user.UserId,
|
||||||
UserToken = CryptoHelper.GenerateAuthToken(),
|
UserToken = CryptoHelper.GenerateAuthToken(),
|
||||||
|
|
|
@ -12,7 +12,7 @@ public class LogoutPage : BaseLayout
|
||||||
{}
|
{}
|
||||||
public async Task<IActionResult> OnGet()
|
public async Task<IActionResult> OnGet()
|
||||||
{
|
{
|
||||||
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("~/");
|
if (token == null) return this.Redirect("~/");
|
||||||
|
|
||||||
this.Database.WebTokens.Remove(token);
|
this.Database.WebTokens.Remove(token);
|
||||||
|
|
|
@ -19,7 +19,7 @@ public class PasswordResetPage : BaseLayout
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public async Task<IActionResult> OnPost(string password, string confirmPassword)
|
public async Task<IActionResult> OnPost(string password, string confirmPassword)
|
||||||
{
|
{
|
||||||
User? user;
|
UserEntity? user;
|
||||||
if (this.Request.Query.ContainsKey("token"))
|
if (this.Request.Query.ContainsKey("token"))
|
||||||
{
|
{
|
||||||
user = await this.Database.UserFromPasswordResetToken(this.Request.Query["token"][0]);
|
user = await this.Database.UserFromPasswordResetToken(this.Request.Query["token"][0]);
|
||||||
|
@ -63,7 +63,7 @@ public class PasswordResetPage : BaseLayout
|
||||||
{
|
{
|
||||||
if (this.Request.Query.ContainsKey("token")) return this.Page();
|
if (this.Request.Query.ContainsKey("token")) return this.Page();
|
||||||
|
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
|
|
||||||
return this.Page();
|
return this.Page();
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class PasswordResetRequestForm : BaseLayout
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.EmailAddress == email && u.EmailAddressVerified);
|
UserEntity? user = await this.Database.Users.FirstOrDefaultAsync(u => u.EmailAddress == email && u.EmailAddressVerified);
|
||||||
|
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
|
@ -51,7 +51,7 @@ public class PasswordResetRequestForm : BaseLayout
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
PasswordResetToken token = new()
|
PasswordResetTokenEntity token = new()
|
||||||
{
|
{
|
||||||
Created = DateTime.Now,
|
Created = DateTime.Now,
|
||||||
UserId = user.UserId,
|
UserId = user.UserId,
|
||||||
|
|
|
@ -15,7 +15,7 @@ public class PasswordResetRequiredPage : BaseLayout
|
||||||
|
|
||||||
public IActionResult OnGet()
|
public IActionResult OnGet()
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
if (!user.PasswordResetRequired) return this.Redirect("~/passwordReset");
|
if (!user.PasswordResetRequired) return this.Redirect("~/passwordReset");
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ public class PirateSignupPage : BaseLayout
|
||||||
|
|
||||||
public IActionResult OnGet()
|
public IActionResult OnGet()
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("/login");
|
if (user == null) return this.Redirect("/login");
|
||||||
|
|
||||||
return this.Page();
|
return this.Page();
|
||||||
|
@ -20,7 +20,7 @@ public class PirateSignupPage : BaseLayout
|
||||||
|
|
||||||
public async Task<IActionResult> OnPost()
|
public async Task<IActionResult> OnPost()
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("/login");
|
if (user == null) return this.Redirect("/login");
|
||||||
|
|
||||||
user.Language = user.Language == "en-PT" ? "en" : "en-PT";
|
user.Language = user.Language == "en-PT" ? "en" : "en-PT";
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class RegisterForm : BaseLayout
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
User? existingUser = await this.Database.Users.FirstOrDefaultAsync(u => u.Username.ToLower() == username.ToLower());
|
UserEntity? existingUser = await this.Database.Users.FirstOrDefaultAsync(u => u.Username.ToLower() == username.ToLower());
|
||||||
if (existingUser != null)
|
if (existingUser != null)
|
||||||
{
|
{
|
||||||
this.Error = this.Translate(ErrorStrings.UsernameTaken);
|
this.Error = this.Translate(ErrorStrings.UsernameTaken);
|
||||||
|
@ -74,9 +74,9 @@ public class RegisterForm : BaseLayout
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
User user = await this.Database.CreateUser(username, CryptoHelper.BCryptHash(password), emailAddress);
|
UserEntity user = await this.Database.CreateUser(username, CryptoHelper.BCryptHash(password), emailAddress);
|
||||||
|
|
||||||
WebToken webToken = new()
|
WebTokenEntity webToken = new()
|
||||||
{
|
{
|
||||||
UserId = user.UserId,
|
UserId = user.UserId,
|
||||||
UserToken = CryptoHelper.GenerateAuthToken(),
|
UserToken = CryptoHelper.GenerateAuthToken(),
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
<p>There are @Model.UserCount banned users.</p>
|
<p>There are @Model.UserCount banned users.</p>
|
||||||
|
|
||||||
@foreach (User user in Model.Users)
|
@foreach (UserEntity user in Model.Users)
|
||||||
{
|
{
|
||||||
<div class="ui segment">
|
<div class="ui segment">
|
||||||
@await Html.PartialAsync("Partials/UserCardPartial", user, new ViewDataDictionary(ViewData)
|
@await Html.PartialAsync("Partials/UserCardPartial", user, new ViewDataDictionary(ViewData)
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class BannedUsersPage : BaseLayout
|
||||||
public BannedUsersPage(DatabaseContext database) : base(database)
|
public BannedUsersPage(DatabaseContext database) : base(database)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public List<User> Users = new();
|
public List<UserEntity> Users = new();
|
||||||
|
|
||||||
public int PageAmount;
|
public int PageAmount;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ public class BannedUsersPage : BaseLayout
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
|
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
|
||||||
{
|
{
|
||||||
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("/login");
|
if (token == null) return this.Redirect("/login");
|
||||||
|
|
||||||
this.Users = await this.Database.Users
|
this.Users = await this.Database.Users
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
@foreach (ModerationCase @case in Model.Cases)
|
@foreach (ModerationCaseEntity @case in Model.Cases)
|
||||||
{
|
{
|
||||||
@(await Html.PartialAsync("Partials/ModerationCasePartial", @case, ViewData.WithTime(timeZone)))
|
@(await Html.PartialAsync("Partials/ModerationCasePartial", @case, ViewData.WithTime(timeZone)))
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@ public class CasePage : BaseLayout
|
||||||
public CasePage(DatabaseContext database) : base(database)
|
public CasePage(DatabaseContext database) : base(database)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public List<ModerationCase> Cases = new();
|
public List<ModerationCaseEntity> Cases = new();
|
||||||
public int CaseCount;
|
public int CaseCount;
|
||||||
public int DismissedCaseCount;
|
public int DismissedCaseCount;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ public class CasePage : BaseLayout
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
|
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.NotFound();
|
if (user == null) return this.NotFound();
|
||||||
if (!user.IsModerator) return this.NotFound();
|
if (!user.IsModerator) return this.NotFound();
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
<p>There are @Model.SlotCount hidden levels.</p>
|
<p>There are @Model.SlotCount hidden levels.</p>
|
||||||
|
|
||||||
@foreach (Slot slot in Model.Slots)
|
@foreach (SlotEntity slot in Model.Slots)
|
||||||
{
|
{
|
||||||
<div class="ui segment">
|
<div class="ui segment">
|
||||||
@await slot.ToHtml(Html, ViewData, Model.User, $"~/moderation/hiddenLevels/{Model.PageNumber}", language, timeZone, isMobile, true)
|
@await slot.ToHtml(Html, ViewData, Model.User, $"~/moderation/hiddenLevels/{Model.PageNumber}", language, timeZone, isMobile, true)
|
||||||
|
|
|
@ -19,11 +19,11 @@ public class HiddenLevelsPage : BaseLayout
|
||||||
|
|
||||||
public int SlotCount;
|
public int SlotCount;
|
||||||
|
|
||||||
public List<Slot> Slots = new();
|
public List<SlotEntity> Slots = new();
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
|
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
|
||||||
{
|
{
|
||||||
WebToken? token = this.Database.WebTokenFromRequest(this.Request);
|
WebTokenEntity? token = this.Database.WebTokenFromRequest(this.Request);
|
||||||
if (token == null) return this.Redirect("/login");
|
if (token == null) return this.Redirect("/login");
|
||||||
|
|
||||||
this.Slots = await this.Database.Slots
|
this.Slots = await this.Database.Slots
|
||||||
|
|
|
@ -16,7 +16,7 @@ public class ModPanelPage : BaseLayout
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet()
|
public async Task<IActionResult> OnGet()
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
if (!user.IsModerator) return this.NotFound();
|
if (!user.IsModerator) return this.NotFound();
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class NewCasePage : BaseLayout
|
||||||
|
|
||||||
public IActionResult OnGet([FromQuery] CaseType? type, [FromQuery] int? affectedId)
|
public IActionResult OnGet([FromQuery] CaseType? type, [FromQuery] int? affectedId)
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsModerator) return this.Redirect("/login");
|
if (user == null || !user.IsModerator) return this.Redirect("/login");
|
||||||
|
|
||||||
if (type == null) return this.BadRequest();
|
if (type == null) return this.BadRequest();
|
||||||
|
@ -31,7 +31,7 @@ public class NewCasePage : BaseLayout
|
||||||
|
|
||||||
public async Task<IActionResult> OnPost(CaseType? type, string? reason, string? modNotes, DateTime expires, int? affectedId)
|
public async Task<IActionResult> OnPost(CaseType? type, string? reason, string? modNotes, DateTime expires, int? affectedId)
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null || !user.IsModerator) return this.Redirect("/login");
|
if (user == null || !user.IsModerator) return this.Redirect("/login");
|
||||||
|
|
||||||
if (type == null) return this.BadRequest();
|
if (type == null) return this.BadRequest();
|
||||||
|
@ -43,7 +43,7 @@ public class NewCasePage : BaseLayout
|
||||||
// if id is invalid then return bad request
|
// if id is invalid then return bad request
|
||||||
if (!await type.Value.IsIdValid((int)affectedId, this.Database)) return this.BadRequest();
|
if (!await type.Value.IsIdValid((int)affectedId, this.Database)) return this.BadRequest();
|
||||||
|
|
||||||
ModerationCase @case = new()
|
ModerationCaseEntity @case = new()
|
||||||
{
|
{
|
||||||
Type = type.Value,
|
Type = type.Value,
|
||||||
Reason = reason,
|
Reason = reason,
|
||||||
|
|
|
@ -14,15 +14,15 @@ public class ReportPage : BaseLayout
|
||||||
public ReportPage(DatabaseContext database) : base(database)
|
public ReportPage(DatabaseContext database) : base(database)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public GriefReport Report = null!; // Report is not used if it's null in OnGet
|
public GriefReportEntity Report = null!; // Report is not used if it's null in OnGet
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet([FromRoute] int reportId)
|
public async Task<IActionResult> OnGet([FromRoute] int reportId)
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
if (!user.IsAdmin) return this.NotFound();
|
if (!user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
GriefReport? report = await this.Database.Reports
|
GriefReportEntity? report = await this.Database.Reports
|
||||||
.Include(r => r.ReportingPlayer)
|
.Include(r => r.ReportingPlayer)
|
||||||
.FirstOrDefaultAsync(r => r.ReportId == reportId);
|
.FirstOrDefaultAsync(r => r.ReportId == reportId);
|
||||||
if (report == null) return this.NotFound();
|
if (report == null) return this.NotFound();
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
let images = [];
|
let images = [];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@foreach (GriefReport report in Model.Reports)
|
@foreach (GriefReportEntity report in Model.Reports)
|
||||||
{
|
{
|
||||||
@await Html.PartialAsync("Partials/ReportPartial", report, ViewData.WithTime(timeZone))
|
@await Html.PartialAsync("Partials/ReportPartial", report, ViewData.WithTime(timeZone))
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ public class ReportsPage : BaseLayout
|
||||||
|
|
||||||
public int ReportCount;
|
public int ReportCount;
|
||||||
|
|
||||||
public List<GriefReport> Reports = new();
|
public List<GriefReportEntity> Reports = new();
|
||||||
|
|
||||||
public string SearchValue = "";
|
public string SearchValue = "";
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ public class ReportsPage : BaseLayout
|
||||||
|
|
||||||
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
|
public async Task<IActionResult> OnGet([FromRoute] int pageNumber, [FromQuery] string? name)
|
||||||
{
|
{
|
||||||
User? user = this.Database.UserFromWebRequest(this.Request);
|
UserEntity? user = this.Database.UserFromWebRequest(this.Request);
|
||||||
if (user == null) return this.Redirect("~/login");
|
if (user == null) return this.Redirect("~/login");
|
||||||
if (!user.IsModerator) return this.NotFound();
|
if (!user.IsModerator) return this.NotFound();
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public class ReportsPage : BaseLayout
|
||||||
.Take(ServerStatics.PageSize)
|
.Take(ServerStatics.PageSize)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
foreach (GriefReport r in this.Reports)
|
foreach (GriefReportEntity r in this.Reports)
|
||||||
{
|
{
|
||||||
r.XmlPlayers = (ReportPlayer[]?)JsonSerializer.Deserialize(r.Players, typeof(ReportPlayer[])) ?? Array.Empty<ReportPlayer>();
|
r.XmlPlayers = (ReportPlayer[]?)JsonSerializer.Deserialize(r.Players, typeof(ReportPlayer[])) ?? Array.Empty<ReportPlayer>();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.User
|
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.UserEntity
|
||||||
|
|
||||||
<form method="post" action="/admin/user/@Model.UserId/setGrantedSlots">
|
<form method="post" action="/admin/user/@Model.UserId/setGrantedSlots">
|
||||||
@Html.AntiForgeryToken()
|
@Html.AntiForgeryToken()
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
@using System.IO
|
@using System.IO
|
||||||
@using LBPUnion.ProjectLighthouse.Localization
|
@using LBPUnion.ProjectLighthouse.Localization
|
||||||
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
|
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
|
||||||
|
@using LBPUnion.ProjectLighthouse.Types.Entities.Interaction
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
||||||
|
|
||||||
@{
|
@{
|
||||||
|
@ -42,65 +43,70 @@
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@{
|
||||||
|
int i = 0;
|
||||||
|
foreach (KeyValuePair<CommentEntity, RatedCommentEntity?> commentAndReaction in Model.Comments)
|
||||||
|
{
|
||||||
|
CommentEntity comment = commentAndReaction.Key;
|
||||||
|
int yourThumb = commentAndReaction.Value?.Rating ?? 0;
|
||||||
|
DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(comment.Timestamp / 1000).ToLocalTime();
|
||||||
|
StringWriter messageWriter = new();
|
||||||
|
HttpUtility.HtmlDecode(comment.getComment(), messageWriter);
|
||||||
|
|
||||||
@for(int i = 0; i < Model.Comments.Count; i++)
|
string decodedMessage = messageWriter.ToString();
|
||||||
{
|
string? url = Url.RouteUrl(ViewContext.RouteData.Values);
|
||||||
Comment comment = Model.Comments[i];
|
if (url == null) continue;
|
||||||
DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(comment.Timestamp / 1000).ToLocalTime();
|
|
||||||
StringWriter messageWriter = new();
|
|
||||||
HttpUtility.HtmlDecode(comment.getComment(), messageWriter);
|
|
||||||
|
|
||||||
string decodedMessage = messageWriter.ToString();
|
int rating = comment.ThumbsUp - comment.ThumbsDown;
|
||||||
string? url = Url.RouteUrl(ViewContext.RouteData.Values);
|
|
||||||
if (url == null) continue;
|
|
||||||
|
|
||||||
int rating = comment.ThumbsUp - comment.ThumbsDown;
|
<div style="display: flex" id="@comment.CommentId">
|
||||||
|
@{
|
||||||
<div style="display: flex" id="@comment.CommentId">
|
string style = "";
|
||||||
@{
|
if (Model.User?.UserId == comment.PosterUserId)
|
||||||
string style = "";
|
{
|
||||||
if (Model.User?.UserId == comment.PosterUserId)
|
style = "pointer-events: none";
|
||||||
{
|
}
|
||||||
style = "pointer-events: none";
|
|
||||||
}
|
}
|
||||||
}
|
<div class="voting" style="@(style)">
|
||||||
<div class="voting" style="@(style)">
|
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(yourThumb == 1 ? 0 : 1)">
|
||||||
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(comment.YourThumb == 1 ? 0 : 1)">
|
<i class="fitted @(yourThumb == 1 ? "green" : "grey") arrow up link icon" style="display: block"></i>
|
||||||
<i class="fitted @(comment.YourThumb == 1 ? "green" : "grey") arrow up link icon" style="display: block"></i>
|
</a>
|
||||||
</a>
|
<span style="text-align: center; margin: auto; @(rating < 0 ? "margin-left: -5px" : "")">@(rating)</span>
|
||||||
<span style="text-align: center; margin: auto; @(rating < 0 ? "margin-left: -5px" : "")">@(rating)</span>
|
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(yourThumb == -1 ? 0 : -1)">
|
||||||
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(comment.YourThumb == -1 ? 0 : -1)">
|
<i class="fitted @(yourThumb == -1 ? "red" : "grey") arrow down link icon" style="display: block"></i>
|
||||||
<i class="fitted @(comment.YourThumb == -1 ? "red" : "grey") arrow down link icon" style="display: block"></i>
|
</a>
|
||||||
</a>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="comment">
|
<div class="comment">
|
||||||
<b>@await comment.Poster.ToLink(Html, ViewData, language): </b>
|
<b>@await comment.Poster.ToLink(Html, ViewData, language): </b>
|
||||||
@if (comment.Deleted)
|
@if (comment.Deleted)
|
||||||
{
|
{
|
||||||
<i>
|
<i>
|
||||||
|
<span>@decodedMessage</span>
|
||||||
|
</i>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
<span>@decodedMessage</span>
|
<span>@decodedMessage</span>
|
||||||
</i>
|
}
|
||||||
}
|
@if (((Model.User?.IsModerator ?? false) || Model.User?.UserId == comment.PosterUserId || Model.User?.UserId == pageOwnerId) && !comment.Deleted)
|
||||||
else
|
{
|
||||||
{
|
<button class="ui red icon button" style="display:inline-flex; float: right" onclick="deleteComment(@comment.CommentId)">
|
||||||
<span>@decodedMessage</span>
|
<i class="trash icon"></i>
|
||||||
}
|
</button>
|
||||||
@if (((Model.User?.IsModerator ?? false) || Model.User?.UserId == comment.PosterUserId || Model.User?.UserId == pageOwnerId) && !comment.Deleted)
|
}
|
||||||
{
|
<p>
|
||||||
<button class="ui red icon button" style="display:inline-flex; float: right" onclick="deleteComment(@comment.CommentId)">
|
<i>@TimeZoneInfo.ConvertTime(timestamp, timeZoneInfo).ToString("M/d/yyyy @ h:mm:ss tt")</i>
|
||||||
<i class="trash icon"></i>
|
</p>
|
||||||
</button>
|
@if (i != Model.Comments.Count - 1)
|
||||||
}
|
{
|
||||||
<p>
|
<div class="ui divider"></div>
|
||||||
<i>@TimeZoneInfo.ConvertTime(timestamp, timeZoneInfo).ToString("M/d/yyyy @ h:mm:ss tt")</i>
|
}
|
||||||
</p>
|
</div>
|
||||||
@if (i != Model.Comments.Count - 1)
|
|
||||||
{
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
<script>
|
<script>
|
||||||
function deleteComment(commentId){
|
function deleteComment(commentId){
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<div class="ui list">
|
<div class="ui list">
|
||||||
@for(int i = 0; i < Model.Scores.Count; i++)
|
@for(int i = 0; i < Model.Scores.Count; i++)
|
||||||
{
|
{
|
||||||
Score score = Model.Scores[i];
|
ScoreEntity score = Model.Scores[i];
|
||||||
string[] playerIds = score.PlayerIds;
|
string[] playerIds = score.PlayerIds;
|
||||||
DatabaseContext database = Model.Database;
|
DatabaseContext database = Model.Database;
|
||||||
<div class="item">
|
<div class="item">
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
<div class="list" style="padding-top: 0">
|
<div class="list" style="padding-top: 0">
|
||||||
@for (int j = 0; j < playerIds.Length; j++)
|
@for (int j = 0; j < playerIds.Length; j++)
|
||||||
{
|
{
|
||||||
User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == playerIds[j]);
|
UserEntity? user = await database.Users.FirstOrDefaultAsync(u => u.Username == playerIds[j]);
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<i class="minus icon" style="padding-top: 9px"></i>
|
<i class="minus icon" style="padding-top: 9px"></i>
|
||||||
<div class="content" style="padding-left: 0">
|
<div class="content" style="padding-left: 0">
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
@using LBPUnion.ProjectLighthouse.Database
|
||||||
@using LBPUnion.ProjectLighthouse.Localization
|
@using LBPUnion.ProjectLighthouse.Localization
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Users
|
@using LBPUnion.ProjectLighthouse.Types.Users
|
||||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.User
|
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.UserEntity
|
||||||
|
|
||||||
@{
|
@{
|
||||||
string language = (string?)ViewData["Language"] ?? LocalizationManager.DefaultLang;
|
string language = (string?)ViewData["Language"] ?? LocalizationManager.DefaultLang;
|
||||||
string timeZone = (string?)ViewData["TimeZone"] ?? TimeZoneInfo.Local.Id;
|
string timeZone = (string?)ViewData["TimeZone"] ?? TimeZoneInfo.Local.Id;
|
||||||
bool includeStatus = (bool?)ViewData["IncludeStatus"] ?? false;
|
bool includeStatus = (bool?)ViewData["IncludeStatus"] ?? false;
|
||||||
string userStatus = includeStatus ? Model.Status.ToTranslatedString(language, timeZone) : "";
|
await using DatabaseContext database = new();
|
||||||
|
string userStatus = includeStatus ? Model.GetStatus(database).ToTranslatedString(language, timeZone) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
<a href="/user/@Model.UserId" title="@userStatus" class="user-link">
|
<a href="/user/@Model.UserId" title="@userStatus" class="user-link">
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Level
|
@using LBPUnion.ProjectLighthouse.Types.Entities.Level
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Moderation.Cases
|
@using LBPUnion.ProjectLighthouse.Types.Moderation.Cases
|
||||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Moderation.ModerationCase
|
@model LBPUnion.ProjectLighthouse.Types.Entities.Moderation.ModerationCaseEntity
|
||||||
|
|
||||||
@{
|
@{
|
||||||
DatabaseContext database = new();
|
DatabaseContext database = new();
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
|
|
||||||
@if (Model.Type.AffectsLevel())
|
@if (Model.Type.AffectsLevel())
|
||||||
{
|
{
|
||||||
Slot? slot = await Model.GetSlotAsync(database);
|
SlotEntity? slot = await Model.GetSlotAsync(database);
|
||||||
if (slot != null)
|
if (slot != null)
|
||||||
{
|
{
|
||||||
<p><strong>Affected level:</strong> <a href="/slot/@slot.SlotId">@slot.Name</a></p>
|
<p><strong>Affected level:</strong> <a href="/slot/@slot.SlotId">@slot.Name</a></p>
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
}
|
}
|
||||||
else if (Model.Type.AffectsUser())
|
else if (Model.Type.AffectsUser())
|
||||||
{
|
{
|
||||||
User? user = await Model.GetUserAsync(database);
|
UserEntity? user = await Model.GetUserAsync(database);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
<p><strong>Affected user:</strong> <a href="/user/@user.UserId">@user.Username</a></p>
|
<p><strong>Affected user:</strong> <a href="/user/@user.UserId">@user.Username</a></p>
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
|
@using LBPUnion.ProjectLighthouse.Servers.Website.Extensions
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Levels
|
@using LBPUnion.ProjectLighthouse.Types.Levels
|
||||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.Photo
|
@using LBPUnion.ProjectLighthouse.Types.Serialization
|
||||||
|
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.PhotoEntity
|
||||||
|
|
||||||
@{
|
@{
|
||||||
string language = (string?)ViewData["Language"] ?? LocalizationManager.DefaultLang;
|
string language = (string?)ViewData["Language"] ?? LocalizationManager.DefaultLang;
|
||||||
|
@ -83,15 +84,17 @@
|
||||||
</p>
|
</p>
|
||||||
}
|
}
|
||||||
<div id="hover-subjects-@Model.PhotoId">
|
<div id="hover-subjects-@Model.PhotoId">
|
||||||
@foreach (PhotoSubject subject in Model.PhotoSubjects)
|
@foreach (PhotoSubjectEntity subject in Model.PhotoSubjects)
|
||||||
{
|
{
|
||||||
@await subject.User.ToLink(Html, ViewData, language, timeZone)
|
@await subject.User.ToLink(Html, ViewData, language, timeZone)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@{
|
@{
|
||||||
PhotoSubject[] subjects = Model.PhotoSubjects.ToArray();
|
GamePhotoSubject[] subjects = Model.PhotoSubjects.Select(GamePhotoSubject.CreateFromEntity).ToArray();
|
||||||
foreach (PhotoSubject subject in subjects) subject.Username = subject.User.Username;
|
foreach (GamePhotoSubject subject in subjects)
|
||||||
|
{
|
||||||
|
subject.Username = Model.PhotoSubjects.Where(ps => ps.UserId == subject.UserId).Select(ps => ps.User.Username).First();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Moderation.Reports
|
@using LBPUnion.ProjectLighthouse.Types.Moderation.Reports
|
||||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Moderation.GriefReport
|
@model LBPUnion.ProjectLighthouse.Types.Entities.Moderation.GriefReportEntity
|
||||||
|
|
||||||
@{
|
@{
|
||||||
string timeZone = (string?)ViewData["TimeZone"] ?? TimeZoneInfo.Local.Id;
|
string timeZone = (string?)ViewData["TimeZone"] ?? TimeZoneInfo.Local.Id;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
@using LBPUnion.ProjectLighthouse.Files
|
@using LBPUnion.ProjectLighthouse.Files
|
||||||
@using LBPUnion.ProjectLighthouse.Helpers
|
@using LBPUnion.ProjectLighthouse.Helpers
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Level
|
@using LBPUnion.ProjectLighthouse.Types.Entities.Level
|
||||||
|
@using LBPUnion.ProjectLighthouse.Types.Serialization
|
||||||
|
|
||||||
@{
|
@{
|
||||||
bool isMobile = (bool?)ViewData["IsMobile"] ?? false;
|
bool isMobile = (bool?)ViewData["IsMobile"] ?? false;
|
||||||
|
@ -30,7 +31,7 @@
|
||||||
|
|
||||||
@for(int i = 0; i < Model.Reviews.Count; i++)
|
@for(int i = 0; i < Model.Reviews.Count; i++)
|
||||||
{
|
{
|
||||||
Review review = Model.Reviews[i];
|
ReviewEntity review = Model.Reviews[i];
|
||||||
string faceHash = (review.Thumb switch {
|
string faceHash = (review.Thumb switch {
|
||||||
-1 => review.Reviewer?.BooHash,
|
-1 => review.Reviewer?.BooHash,
|
||||||
0 => review.Reviewer?.MehHash,
|
0 => review.Reviewer?.MehHash,
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
@using LBPUnion.ProjectLighthouse.Types.Entities.Profile
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Users
|
@using LBPUnion.ProjectLighthouse.Types.Users
|
||||||
@using Microsoft.EntityFrameworkCore
|
@using Microsoft.EntityFrameworkCore
|
||||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Level.Slot
|
@model LBPUnion.ProjectLighthouse.Types.Entities.Level.SlotEntity
|
||||||
|
|
||||||
@{
|
@{
|
||||||
User? user = (User?)ViewData["User"];
|
UserEntity? user = (UserEntity?)ViewData["User"];
|
||||||
|
|
||||||
await using DatabaseContext database = new();
|
await using DatabaseContext database = new();
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
@using LBPUnion.ProjectLighthouse.Database
|
||||||
@using LBPUnion.ProjectLighthouse.Localization
|
@using LBPUnion.ProjectLighthouse.Localization
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Users
|
@using LBPUnion.ProjectLighthouse.Types.Users
|
||||||
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.User
|
@model LBPUnion.ProjectLighthouse.Types.Entities.Profile.UserEntity
|
||||||
|
|
||||||
@{
|
@{
|
||||||
bool showLink = (bool?)ViewData["ShowLink"] ?? false;
|
bool showLink = (bool?)ViewData["ShowLink"] ?? false;
|
||||||
|
@ -40,14 +41,22 @@
|
||||||
}
|
}
|
||||||
</h1>
|
</h1>
|
||||||
}
|
}
|
||||||
|
@{
|
||||||
|
await using DatabaseContext context = new();
|
||||||
|
|
||||||
|
int hearts = Model.GetHeartCount(context);
|
||||||
|
int comments = Model.GetCommentCount(context);
|
||||||
|
int levels = Model.GetUsedSlotCount(context);
|
||||||
|
int photos = Model.GetUploadedPhotoCount(context);
|
||||||
|
}
|
||||||
<span>
|
<span>
|
||||||
<i>@Model.Status.ToTranslatedString(language, timeZone)</i>
|
<i>@Model.GetStatus(context).ToTranslatedString(language, timeZone)</i>
|
||||||
</span>
|
</span>
|
||||||
<div class="cardStatsUnderTitle">
|
<div class="cardStatsUnderTitle">
|
||||||
<i class="pink heart icon" title="Hearts"></i> <span>@Model.Hearts</span>
|
<i class="pink heart icon" title="Hearts"></i> <span>@hearts</span>
|
||||||
<i class="blue comment icon" title="Comments"></i> <span>@Model.Comments</span>
|
<i class="blue comment icon" title="Comments"></i> <span>@comments</span>
|
||||||
<i class="green upload icon" title="Uploaded Levels"></i><span>@Model.UsedSlots</span>
|
<i class="green upload icon" title="Uploaded Levels"></i><span>@levels</span>
|
||||||
<i class="purple camera icon" title="Uploaded Photos"></i><span>@Model.PhotosByMe</span>
|
<i class="purple camera icon" title="Uploaded Photos"></i><span>@photos</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue