mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-06-19 14:01:27 +00:00
Rewrite gameserver slot filter system (#763)
* Initial implementation of new slot sorting and filtering system * Initial implementation of filtering for lbp3 community tab * Add support for organization on lbp3 * Add playlist and user categories * Implement unit tests for all filters Refactor more systems to use PaginationData * Fix PlayerCountFilter test * Add more unit tests and integration tests for the filter system * Fix LBP2 move filter and gameFilterType * Fix sort by likes in LBP3 category * Add sort for total plays * Remove extra whitespace and make styling more consistent * Order hearted and queued levels by primary key ID * Fix query without order warnings
This commit is contained in:
parent
de228cb242
commit
0c1e350fa3
106 changed files with 4040 additions and 1183 deletions
|
@ -1,4 +1,6 @@
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.API.Responses;
|
using LBPUnion.ProjectLighthouse.Servers.API.Responses;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
@ -31,10 +33,10 @@ public class StatisticsEndpoints : ApiEndpointController
|
||||||
new StatisticsResponse
|
new StatisticsResponse
|
||||||
{
|
{
|
||||||
Photos = await StatisticsHelper.PhotoCount(this.database),
|
Photos = await StatisticsHelper.PhotoCount(this.database),
|
||||||
Slots = await StatisticsHelper.SlotCount(this.database),
|
Slots = await StatisticsHelper.SlotCount(this.database, new SlotQueryBuilder()),
|
||||||
Users = await StatisticsHelper.UserCount(this.database),
|
Users = await StatisticsHelper.UserCount(this.database),
|
||||||
RecentMatches = await StatisticsHelper.RecentMatches(this.database),
|
RecentMatches = await StatisticsHelper.RecentMatches(this.database),
|
||||||
TeamPicks = await StatisticsHelper.TeamPickCount(this.database),
|
TeamPicks = await StatisticsHelper.SlotCount(this.database, new SlotQueryBuilder().AddFilter(new TeamPickFilter())),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
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.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
@ -42,12 +43,10 @@ public class CommentController : ControllerBase
|
||||||
|
|
||||||
[HttpGet("comments/{slotType}/{slotId:int}")]
|
[HttpGet("comments/{slotType}/{slotId:int}")]
|
||||||
[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(string? username, string? slotType, int slotId)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0 || pageStart < 0) 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);
|
if (slotType == "developer") slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
|
||||||
|
@ -55,6 +54,8 @@ public class CommentController : ControllerBase
|
||||||
int targetId;
|
int targetId;
|
||||||
CommentType type = username == null ? CommentType.Level : CommentType.Profile;
|
CommentType type = username == null ? CommentType.Level : CommentType.Profile;
|
||||||
|
|
||||||
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
if (type == CommentType.Level)
|
if (type == CommentType.Level)
|
||||||
{
|
{
|
||||||
targetId = await this.database.Slots.Where(s => s.SlotId == slotId)
|
targetId = await this.database.Slots.Where(s => s.SlotId == slotId)
|
||||||
|
@ -82,8 +83,7 @@ public class CommentController : ControllerBase
|
||||||
.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))
|
.ApplyPagination(pageData)
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(c => GameComment.CreateFromEntity(c, token.UserId));
|
.ToListAsync()).ToSerializableList(c => GameComment.CreateFromEntity(c, token.UserId));
|
||||||
|
|
||||||
return this.Ok(new CommentListResponse(comments));
|
return this.Ok(new CommentListResponse(comments));
|
||||||
|
|
|
@ -10,7 +10,7 @@ using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Login;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
|
@ -13,7 +13,7 @@ using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Login;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("LITTLEBIGPLANETPS3_XML/login")]
|
[Route("LITTLEBIGPLANETPS3_XML/login")]
|
|
@ -6,7 +6,7 @@ using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Login;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Authorize]
|
[Authorize]
|
|
@ -64,5 +64,4 @@ public class ReportController : ControllerBase
|
||||||
|
|
||||||
return this.Ok();
|
return this.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,6 +8,7 @@ using LBPUnion.ProjectLighthouse.Logging;
|
||||||
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.Filter;
|
||||||
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.Serialization;
|
||||||
|
@ -159,54 +160,53 @@ public class PhotosController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("photos/{slotType}/{id:int}")]
|
[HttpGet("photos/{slotType}/{id:int}")]
|
||||||
public async Task<IActionResult> SlotPhotos([FromQuery] int pageStart, [FromQuery] int pageSize, string slotType, int id)
|
public async Task<IActionResult> SlotPhotos(string slotType, int id)
|
||||||
{
|
{
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
List<GamePhoto> photos = (await this.database.Photos.Include(p => p.PhotoSubjects)
|
List<GamePhoto> photos = (await this.database.Photos.Include(p => p.PhotoSubjects)
|
||||||
.Where(p => p.SlotId == id)
|
.Where(p => p.SlotId == id)
|
||||||
.OrderByDescending(s => s.Timestamp)
|
.OrderByDescending(s => s.Timestamp)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.ApplyPagination(pageData)
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(GamePhoto.CreateFromEntity);
|
.ToListAsync()).ToSerializableList(GamePhoto.CreateFromEntity);
|
||||||
|
|
||||||
return this.Ok(new PhotoListResponse(photos));
|
return this.Ok(new PhotoListResponse(photos));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("photos/by")]
|
[HttpGet("photos/by")]
|
||||||
public async Task<IActionResult> UserPhotosBy([FromQuery] string user, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> UserPhotosBy(string user)
|
||||||
{
|
{
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
List<GamePhoto> photos = (await this.database.Photos.Include(p => p.PhotoSubjects)
|
List<GamePhoto> photos = (await this.database.Photos.Include(p => p.PhotoSubjects)
|
||||||
.Where(p => p.CreatorId == targetUserId)
|
.Where(p => p.CreatorId == targetUserId)
|
||||||
.OrderByDescending(s => s.Timestamp)
|
.OrderByDescending(s => s.Timestamp)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.ApplyPagination(pageData)
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(GamePhoto.CreateFromEntity);
|
.ToListAsync()).ToSerializableList(GamePhoto.CreateFromEntity);
|
||||||
return this.Ok(new PhotoListResponse(photos));
|
return this.Ok(new PhotoListResponse(photos));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("photos/with")]
|
[HttpGet("photos/with")]
|
||||||
public async Task<IActionResult> UserPhotosWith([FromQuery] string user, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> UserPhotosWith(string user)
|
||||||
{
|
{
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
List<GamePhoto> photos = (await this.database.Photos.Include(p => p.PhotoSubjects)
|
List<GamePhoto> photos = (await this.database.Photos.Include(p => p.PhotoSubjects)
|
||||||
.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))
|
.ApplyPagination(pageData)
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(GamePhoto.CreateFromEntity);
|
.ToListAsync()).ToSerializableList(GamePhoto.CreateFromEntity);
|
||||||
|
|
||||||
return this.Ok(new PhotoListResponse(photos));
|
return this.Ok(new PhotoListResponse(photos));
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||||
|
[Produces("text/xml")]
|
||||||
|
public class CategoryController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly DatabaseContext database;
|
||||||
|
|
||||||
|
public CategoryController(DatabaseContext database)
|
||||||
|
{
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("searches")]
|
||||||
|
[HttpGet("genres")]
|
||||||
|
public async Task<IActionResult> GenresAndSearches()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
|
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||||
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
|
pageData.TotalElements = CategoryHelper.Categories.Count;
|
||||||
|
|
||||||
|
if (!int.TryParse(this.Request.Query["num_categories_with_results"], out int results)) results = 5;
|
||||||
|
|
||||||
|
List<GameCategory> categories = new();
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
||||||
|
|
||||||
|
foreach (Category category in CategoryHelper.Categories.Skip(Math.Max(0, pageData.PageStart - 1))
|
||||||
|
.Take(Math.Min(pageData.PageSize, pageData.MaxElements))
|
||||||
|
.ToList())
|
||||||
|
{
|
||||||
|
int numResults = results > 0 ? 1 : 0;
|
||||||
|
categories.Add(await category.Serialize(this.database, token, queryBuilder, numResults));
|
||||||
|
results--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.Ok(new CategoryListResponse(categories, pageData.TotalElements, "", pageData.HintStart));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("searches/{endpointName}")]
|
||||||
|
public async Task<IActionResult> GetCategorySlots(string endpointName)
|
||||||
|
{
|
||||||
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
|
UserEntity? user = await this.database.UserFromGameToken(token);
|
||||||
|
if (user == null) return this.Forbid();
|
||||||
|
|
||||||
|
Category? category = CategoryHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName);
|
||||||
|
if (category == null) return this.NotFound();
|
||||||
|
|
||||||
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
|
Logger.Debug("Found category " + category, LogArea.Category);
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
||||||
|
|
||||||
|
GenericSerializableList returnList = category switch
|
||||||
|
{
|
||||||
|
SlotCategory gc => await this.GetSlotCategory(gc, token, queryBuilder, pageData),
|
||||||
|
PlaylistCategory pc => await this.GetPlaylistCategory(pc, token, pageData),
|
||||||
|
UserCategory uc => await this.GetUserCategory(uc, token, pageData),
|
||||||
|
_ => new GenericSerializableList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.Ok(returnList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<GenericSerializableList> GetUserCategory(UserCategory userCategory, GameTokenEntity token, PaginationData pageData)
|
||||||
|
{
|
||||||
|
int totalUsers = await userCategory.GetItems(this.database, token).CountAsync();
|
||||||
|
pageData.TotalElements = totalUsers;
|
||||||
|
IQueryable<UserEntity> userQuery = userCategory.GetItems(this.database, token).ApplyPagination(pageData);
|
||||||
|
|
||||||
|
List<ILbpSerializable> users =
|
||||||
|
(await userQuery.ToListAsync()).ToSerializableList<UserEntity, ILbpSerializable>(GameUser
|
||||||
|
.CreateFromEntity);
|
||||||
|
return new GenericSerializableList(users, pageData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<GenericSerializableList> GetPlaylistCategory(PlaylistCategory playlistCategory, GameTokenEntity token, PaginationData pageData)
|
||||||
|
{
|
||||||
|
int totalPlaylists = await playlistCategory.GetItems(this.database, token).CountAsync();
|
||||||
|
pageData.TotalElements = totalPlaylists;
|
||||||
|
IQueryable<PlaylistEntity> playlistQuery = playlistCategory.GetItems(this.database, token).ApplyPagination(pageData);
|
||||||
|
|
||||||
|
List<ILbpSerializable> playlists =
|
||||||
|
(await playlistQuery.ToListAsync()).ToSerializableList<PlaylistEntity, ILbpSerializable>(GamePlaylist
|
||||||
|
.CreateFromEntity);
|
||||||
|
return new GenericSerializableList(playlists, pageData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<GenericSerializableList> GetSlotCategory(SlotCategory slotCategory, GameTokenEntity token, SlotQueryBuilder queryBuilder, PaginationData pageData)
|
||||||
|
{
|
||||||
|
int totalSlots = await slotCategory.GetItems(this.database, token, queryBuilder).CountAsync();
|
||||||
|
pageData.TotalElements = totalSlots;
|
||||||
|
IQueryable<SlotEntity> slotQuery = slotCategory.GetItems(this.database, token, queryBuilder).ApplyPagination(pageData);
|
||||||
|
|
||||||
|
if (bool.TryParse(this.Request.Query["includePlayed"], out bool includePlayed) && !includePlayed)
|
||||||
|
{
|
||||||
|
slotQuery = slotQuery.Select(s => new SlotMetadata
|
||||||
|
{
|
||||||
|
Slot = s,
|
||||||
|
Played = this.database.VisitedLevels.Any(v => v.SlotId == s.SlotId && v.UserId == token.UserId),
|
||||||
|
})
|
||||||
|
.Where(s => !s.Played)
|
||||||
|
.Select(s => s.Slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.Request.Query.ContainsKey("sort"))
|
||||||
|
{
|
||||||
|
string sort = (string?)this.Request.Query["sort"] ?? "";
|
||||||
|
slotQuery = sort switch
|
||||||
|
{
|
||||||
|
"relevance" => slotQuery.ApplyOrdering(new SlotSortBuilder<SlotEntity>()
|
||||||
|
.AddSort(new UniquePlaysTotalSort())
|
||||||
|
.AddSort(new LastUpdatedSort())),
|
||||||
|
"likes" => slotQuery.Select(s => new SlotMetadata
|
||||||
|
{
|
||||||
|
Slot = s,
|
||||||
|
ThumbsUp = this.database.RatedLevels.Count(r => r.SlotId == s.SlotId && r.Rating == 1),
|
||||||
|
})
|
||||||
|
.OrderByDescending(s => s.ThumbsUp)
|
||||||
|
.Select(s => s.Slot),
|
||||||
|
"hearts" => slotQuery.Select(s => new SlotMetadata
|
||||||
|
{
|
||||||
|
Slot = s,
|
||||||
|
Hearts = this.database.HeartedLevels.Count(h => h.SlotId == s.SlotId),
|
||||||
|
})
|
||||||
|
.OrderByDescending(s => s.Hearts)
|
||||||
|
.Select(s => s.Slot),
|
||||||
|
"date" => slotQuery.ApplyOrdering(new SlotSortBuilder<SlotEntity>().AddSort(new FirstUploadedSort())),
|
||||||
|
"plays" => slotQuery.ApplyOrdering(
|
||||||
|
new SlotSortBuilder<SlotEntity>().AddSort(new UniquePlaysTotalSort()).AddSort(new TotalPlaysSort())),
|
||||||
|
_ => slotQuery,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ILbpSerializable> slots =
|
||||||
|
(await slotQuery.ToListAsync()).ToSerializableList<SlotEntity, ILbpSerializable>(s =>
|
||||||
|
SlotBase.CreateFromEntity(s, token));
|
||||||
|
return new GenericSerializableList(slots, pageData);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,13 +2,8 @@
|
||||||
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.Logging;
|
|
||||||
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.Token;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
@ -148,95 +143,4 @@ public class CollectionController : ControllerBase
|
||||||
|
|
||||||
return this.Ok(await this.GetUserPlaylists(targetUserId));
|
return this.Ok(await this.GetUserPlaylists(targetUserId));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("searches")]
|
|
||||||
[HttpGet("genres")]
|
|
||||||
public async Task<IActionResult> GenresAndSearches()
|
|
||||||
{
|
|
||||||
GameTokenEntity token = this.GetToken();
|
|
||||||
|
|
||||||
UserEntity? user = await this.database.UserFromGameToken(token);
|
|
||||||
if (user == null) return this.Forbid();
|
|
||||||
|
|
||||||
List<GameCategory> categories = new();
|
|
||||||
|
|
||||||
foreach (Category category in CategoryHelper.Categories.ToList())
|
|
||||||
{
|
|
||||||
if(category is CategoryWithUser categoryWithUser) categories.Add(categoryWithUser.Serialize(this.database, user));
|
|
||||||
else categories.Add(category.Serialize(this.database));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.Ok(new CategoryListResponse(categories, CategoryHelper.Categories.Count, 0, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("searches/{endpointName}")]
|
|
||||||
public async Task<IActionResult> GetCategorySlots(string endpointName, [FromQuery] int pageStart, [FromQuery] int pageSize,
|
|
||||||
[FromQuery] int players = 0,
|
|
||||||
[FromQuery] string? labelFilter0 = null,
|
|
||||||
[FromQuery] string? labelFilter1 = null,
|
|
||||||
[FromQuery] string? labelFilter2 = null,
|
|
||||||
[FromQuery] string? labelFilter3 = null,
|
|
||||||
[FromQuery] string? labelFilter4 = null,
|
|
||||||
[FromQuery] string? move = null,
|
|
||||||
[FromQuery] string? adventure = null
|
|
||||||
)
|
|
||||||
{
|
|
||||||
GameTokenEntity token = this.GetToken();
|
|
||||||
|
|
||||||
UserEntity? user = await this.database.UserFromGameToken(token);
|
|
||||||
if (user == null) return this.Forbid();
|
|
||||||
|
|
||||||
Category? category = CategoryHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName);
|
|
||||||
if (category == null) return this.NotFound();
|
|
||||||
|
|
||||||
Logger.Debug("Found category " + category, LogArea.Category);
|
|
||||||
|
|
||||||
List<SlotEntity> slots;
|
|
||||||
int totalSlots;
|
|
||||||
|
|
||||||
if (category is CategoryWithUser categoryWithUser)
|
|
||||||
{
|
|
||||||
slots = (await categoryWithUser.GetSlots(this.database, user, pageStart, pageSize)
|
|
||||||
.ToListAsync());
|
|
||||||
totalSlots = categoryWithUser.GetTotalSlots(this.database, user);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
slots = category.GetSlots(this.database, pageStart, pageSize)
|
|
||||||
.ToList();
|
|
||||||
totalSlots = category.GetTotalSlots(this.database);
|
|
||||||
}
|
|
||||||
|
|
||||||
slots = this.filterSlots(slots, players + 1, labelFilter0, labelFilter1, labelFilter2, labelFilter3, labelFilter4, move, adventure);
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse("results", slots.ToSerializableList(s => SlotBase.CreateFromEntity(s, token)), totalSlots, pageStart + pageSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<SlotEntity> filterSlots(List<SlotEntity> slots, int players, string? labelFilter0 = null, string? labelFilter1 = null, string? labelFilter2 = null, string? labelFilter3 = null, string? labelFilter4 = null, string? move = null, string? adventure = null)
|
|
||||||
{
|
|
||||||
slots.RemoveAll(s => s.MinimumPlayers != players);
|
|
||||||
|
|
||||||
if (labelFilter0 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter0));
|
|
||||||
if (labelFilter1 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter1));
|
|
||||||
if (labelFilter2 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter2));
|
|
||||||
if (labelFilter3 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter3));
|
|
||||||
if (labelFilter4 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter4));
|
|
||||||
|
|
||||||
if (move == "noneCan")
|
|
||||||
slots.RemoveAll(s => s.MoveRequired);
|
|
||||||
if (move == "allMust")
|
|
||||||
slots.RemoveAll(s => !s.MoveRequired);
|
|
||||||
|
|
||||||
if (adventure == "noneCan")
|
|
||||||
slots.RemoveAll(s => s.IsAdventurePlanet);
|
|
||||||
if (adventure == "allMust")
|
|
||||||
slots.RemoveAll(s => !s.IsAdventurePlanet);
|
|
||||||
|
|
||||||
return slots;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,11 +1,13 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Interaction;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
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.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
@ -22,6 +24,7 @@ namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
||||||
public class ListController : ControllerBase
|
public class ListController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext database;
|
private readonly DatabaseContext database;
|
||||||
|
|
||||||
public ListController(DatabaseContext database)
|
public ListController(DatabaseContext database)
|
||||||
{
|
{
|
||||||
this.database = database;
|
this.database = database;
|
||||||
|
@ -32,31 +35,30 @@ public class ListController : ControllerBase
|
||||||
#region Level Queue (lolcatftw)
|
#region Level Queue (lolcatftw)
|
||||||
|
|
||||||
[HttpGet("slots/lolcatftw/{username}")]
|
[HttpGet("slots/lolcatftw/{username}")]
|
||||||
public async Task<IActionResult> GetQueuedLevels
|
public async Task<IActionResult> GetQueuedLevels(string username)
|
||||||
(
|
|
||||||
string username,
|
|
||||||
[FromQuery] int pageStart,
|
|
||||||
[FromQuery] int pageSize,
|
|
||||||
[FromQuery] string? gameFilterType = null,
|
|
||||||
[FromQuery] int? players = null,
|
|
||||||
[FromQuery] bool? move = null,
|
|
||||||
[FromQuery] string? dateFilterType = null
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
List<SlotBase> queuedLevels = (await this.filterListByRequest(gameFilterType, dateFilterType, token.GameVersion, username, ListFilterType.Queue)
|
int targetUserId = await this.database.Users.Where(u => u.Username == username)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Select(u => u.UserId)
|
||||||
.Take(Math.Min(pageSize, 30))
|
.FirstOrDefaultAsync();
|
||||||
.ToListAsync())
|
if (targetUserId == 0) return this.BadRequest();
|
||||||
.ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
int total = await this.database.QueuedLevels.CountAsync(q => q.UserId == token.UserId);
|
pageData.TotalElements = await this.database.QueuedLevels.CountAsync(q => q.UserId == targetUserId);
|
||||||
int start = pageStart + Math.Min(pageSize, 30);
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(queuedLevels, total, start));
|
IQueryable<SlotEntity> baseQuery = this.database.QueuedLevels.Where(h => h.UserId == targetUserId)
|
||||||
|
.OrderByDescending(q => q.QueuedLevelId)
|
||||||
|
.Include(q => q.Slot)
|
||||||
|
.Select(q => q.Slot);
|
||||||
|
|
||||||
|
List<SlotBase> queuedLevels = await baseQuery.GetSlots(token,
|
||||||
|
this.FilterFromRequest(token),
|
||||||
|
pageData,
|
||||||
|
new SlotSortBuilder<SlotEntity>());
|
||||||
|
|
||||||
|
return this.Ok(new GenericSlotResponse(queuedLevels, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("lolcatftw/add/user/{id:int}")]
|
[HttpPost("lolcatftw/add/user/{id:int}")]
|
||||||
|
@ -102,37 +104,33 @@ public class ListController : ControllerBase
|
||||||
#region Hearted Levels
|
#region Hearted Levels
|
||||||
|
|
||||||
[HttpGet("favouriteSlots/{username}")]
|
[HttpGet("favouriteSlots/{username}")]
|
||||||
public async Task<IActionResult> GetFavouriteSlots
|
public async Task<IActionResult> GetFavouriteSlots(string username)
|
||||||
(
|
|
||||||
string username,
|
|
||||||
[FromQuery] int pageStart,
|
|
||||||
[FromQuery] int pageSize,
|
|
||||||
[FromQuery] string? gameFilterType = null,
|
|
||||||
[FromQuery] int? players = null,
|
|
||||||
[FromQuery] bool? move = null,
|
|
||||||
[FromQuery] string? dateFilterType = null
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
UserEntity? targetUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
int targetUserId = await this.database.Users.Where(u => u.Username == username)
|
||||||
if (targetUser == null) return this.Forbid();
|
.Select(u => u.UserId)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
if (targetUserId == 0) return this.BadRequest();
|
||||||
|
|
||||||
List<SlotBase> heartedLevels = (await this.filterListByRequest(gameFilterType, dateFilterType, token.GameVersion, username, ListFilterType.FavouriteSlots)
|
pageData.TotalElements = await this.database.HeartedLevels.CountAsync(h => h.UserId == targetUserId);
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
|
IQueryable<SlotEntity> baseQuery = this.database.HeartedLevels.Where(h => h.UserId == targetUserId)
|
||||||
|
.OrderByDescending(h => h.HeartedLevelId)
|
||||||
|
.Include(h => h.Slot)
|
||||||
|
.Select(h => h.Slot);
|
||||||
|
|
||||||
int total = await this.database.HeartedLevels.CountAsync(q => q.UserId == targetUser.UserId);
|
List<SlotBase> heartedLevels = await baseQuery.GetSlots(token,
|
||||||
int start = pageStart + Math.Min(pageSize, 30);
|
this.FilterFromRequest(token),
|
||||||
|
pageData,
|
||||||
|
new SlotSortBuilder<SlotEntity>());
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse("favouriteSlots", heartedLevels, total, start));
|
return this.Ok(new GenericSlotResponse("favouriteSlots", heartedLevels, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
[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)
|
||||||
|
@ -148,7 +146,7 @@ public class ListController : ControllerBase
|
||||||
|
|
||||||
if (slotType == "developer")
|
if (slotType == "developer")
|
||||||
{
|
{
|
||||||
GameVersion slotGameVersion = (slot.InternalSlotId < FirstLbp2DeveloperSlotId) ? GameVersion.LittleBigPlanet1 : token.GameVersion;
|
GameVersion slotGameVersion = (slot.InternalSlotId < firstLbp2DeveloperSlotId) ? GameVersion.LittleBigPlanet1 : token.GameVersion;
|
||||||
slot.GameVersion = slotGameVersion;
|
slot.GameVersion = slotGameVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +169,7 @@ public class ListController : ControllerBase
|
||||||
|
|
||||||
if (slotType == "developer")
|
if (slotType == "developer")
|
||||||
{
|
{
|
||||||
GameVersion slotGameVersion = (slot.InternalSlotId < FirstLbp2DeveloperSlotId) ? GameVersion.LittleBigPlanet1 : token.GameVersion;
|
GameVersion slotGameVersion = (slot.InternalSlotId < firstLbp2DeveloperSlotId) ? GameVersion.LittleBigPlanet1 : token.GameVersion;
|
||||||
slot.GameVersion = slotGameVersion;
|
slot.GameVersion = slotGameVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,26 +183,27 @@ public class ListController : ControllerBase
|
||||||
#region Hearted Playlists
|
#region Hearted Playlists
|
||||||
|
|
||||||
[HttpGet("favouritePlaylists/{username}")]
|
[HttpGet("favouritePlaylists/{username}")]
|
||||||
public async Task<IActionResult> GetFavouritePlaylists(string username, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> GetFavouritePlaylists(string username)
|
||||||
{
|
{
|
||||||
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.Forbid();
|
if (targetUserId == 0) return this.Forbid();
|
||||||
|
|
||||||
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
List<GamePlaylist> heartedPlaylists = (await 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)
|
||||||
.Include(p => p.Playlist.Creator)
|
|
||||||
.OrderByDescending(p => p.HeartedPlaylistId)
|
.OrderByDescending(p => p.HeartedPlaylistId)
|
||||||
.Select(p => p.Playlist)
|
.Select(p => p.Playlist)
|
||||||
|
.ApplyPagination(pageData)
|
||||||
.ToListAsync()).ToSerializableList(GamePlaylist.CreateFromEntity);
|
.ToListAsync()).ToSerializableList(GamePlaylist.CreateFromEntity);
|
||||||
|
|
||||||
int total = await this.database.HeartedPlaylists.CountAsync(p => p.UserId == targetUserId);
|
pageData.TotalElements = await this.database.HeartedPlaylists.CountAsync(p => p.UserId == targetUserId);
|
||||||
|
|
||||||
return this.Ok(new GenericPlaylistResponse<GamePlaylist>("favouritePlaylists", heartedPlaylists)
|
return this.Ok(new GenericPlaylistResponse<GamePlaylist>("favouritePlaylists", heartedPlaylists)
|
||||||
{
|
{
|
||||||
Total = total,
|
Total = pageData.TotalElements,
|
||||||
HintStart = pageStart + Math.Min(pageSize, 30),
|
HintStart = pageData.HintStart,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,26 +240,27 @@ public class ListController : ControllerBase
|
||||||
#region Users
|
#region Users
|
||||||
|
|
||||||
[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)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
UserEntity? targetUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
if (targetUser == null) return this.Forbid();
|
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
int targetUserId = await this.database.Users.Where(u => u.Username == username)
|
||||||
|
.Select(u => u.UserId)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
if (targetUserId == 0) return this.BadRequest();
|
||||||
|
|
||||||
|
pageData.TotalElements = await this.database.HeartedProfiles.CountAsync(h => h.UserId == targetUserId);
|
||||||
|
|
||||||
List<GameUser> heartedProfiles = (await this.database.HeartedProfiles.Include(h => h.HeartedUser)
|
List<GameUser> heartedProfiles = (await this.database.HeartedProfiles.Include(h => h.HeartedUser)
|
||||||
.OrderBy(h => h.HeartedProfileId)
|
.OrderBy(h => h.HeartedProfileId)
|
||||||
.Where(h => h.UserId == targetUser.UserId)
|
.Where(h => h.UserId == targetUserId)
|
||||||
.Select(h => h.HeartedUser)
|
.Select(h => h.HeartedUser)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.ApplyPagination(pageData)
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(u => GameUser.CreateFromEntity(u, token.GameVersion));
|
.ToListAsync()).ToSerializableList(u => GameUser.CreateFromEntity(u, token.GameVersion));
|
||||||
|
|
||||||
int total = await this.database.HeartedProfiles.CountAsync(h => h.UserId == targetUser.UserId);
|
return this.Ok(new GenericUserResponse<GameUser>("favouriteUsers", heartedProfiles, pageData));
|
||||||
|
|
||||||
return this.Ok(new GenericUserResponse<GameUser>("favouriteUsers", heartedProfiles, total, pageStart + Math.Min(pageSize, 30)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("favourite/user/{username}")]
|
[HttpPost("favourite/user/{username}")]
|
||||||
|
@ -288,85 +288,5 @@ public class ListController : ControllerBase
|
||||||
|
|
||||||
return this.Ok();
|
return this.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Filtering
|
|
||||||
internal enum ListFilterType // used to collapse code that would otherwise be two separate functions
|
|
||||||
{
|
|
||||||
Queue,
|
|
||||||
FavouriteSlots,
|
|
||||||
}
|
|
||||||
|
|
||||||
private static GameVersion getGameFilter(string? gameFilterType, GameVersion version)
|
|
||||||
{
|
|
||||||
return version switch
|
|
||||||
{
|
|
||||||
GameVersion.LittleBigPlanetVita => GameVersion.LittleBigPlanetVita,
|
|
||||||
GameVersion.LittleBigPlanetPSP => GameVersion.LittleBigPlanetPSP,
|
|
||||||
_ => gameFilterType switch
|
|
||||||
{
|
|
||||||
"lbp1" => GameVersion.LittleBigPlanet1,
|
|
||||||
"lbp2" => GameVersion.LittleBigPlanet2,
|
|
||||||
"lbp3" => GameVersion.LittleBigPlanet3,
|
|
||||||
"both" => GameVersion.LittleBigPlanet2, // LBP2 default option
|
|
||||||
null => GameVersion.LittleBigPlanet1,
|
|
||||||
_ => GameVersion.Unknown,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private IQueryable<SlotEntity> filterListByRequest(string? gameFilterType, string? dateFilterType, GameVersion version, string username, ListFilterType filterType)
|
|
||||||
{
|
|
||||||
if (version is GameVersion.LittleBigPlanetPSP or GameVersion.Unknown)
|
|
||||||
{
|
|
||||||
return this.database.Slots.ByGameVersion(version, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
long oldestTime = dateFilterType switch
|
|
||||||
{
|
|
||||||
"thisWeek" => DateTimeOffset.Now.AddDays(-7).ToUnixTimeMilliseconds(),
|
|
||||||
"thisMonth" => DateTimeOffset.Now.AddDays(-31).ToUnixTimeMilliseconds(),
|
|
||||||
_ => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
GameVersion gameVersion = getGameFilter(gameFilterType, version);
|
|
||||||
|
|
||||||
// The filtering only cares if this isn't equal to 'both'
|
|
||||||
if (version == GameVersion.LittleBigPlanetVita) gameFilterType = "lbp2";
|
|
||||||
|
|
||||||
if (filterType == ListFilterType.Queue)
|
|
||||||
{
|
|
||||||
IQueryable<QueuedLevelEntity> whereQueuedLevels;
|
|
||||||
|
|
||||||
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
|
||||||
if (gameFilterType == "both")
|
|
||||||
// Get game versions less than the current version
|
|
||||||
// Needs support for LBP3 ("both" = LBP1+2)
|
|
||||||
whereQueuedLevels = this.database.QueuedLevels.Where(q => q.User.Username == username)
|
|
||||||
.Where(q => q.Slot.Type == SlotType.User && !q.Slot.Hidden && q.Slot.GameVersion <= gameVersion && q.Slot.FirstUploaded >= oldestTime);
|
|
||||||
else
|
|
||||||
// Get game versions exactly equal to gamefiltertype
|
|
||||||
whereQueuedLevels = this.database.QueuedLevels.Where(q => q.User.Username == username)
|
|
||||||
.Where(q => q.Slot.Type == SlotType.User && !q.Slot.Hidden && q.Slot.GameVersion == gameVersion && q.Slot.FirstUploaded >= oldestTime);
|
|
||||||
|
|
||||||
return whereQueuedLevels.OrderByDescending(q => q.QueuedLevelId).Include(q => q.Slot.Creator).Select(q => q.Slot).ByGameVersion(gameVersion, false, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
IQueryable<HeartedLevelEntity> whereHeartedLevels;
|
|
||||||
|
|
||||||
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
|
||||||
if (gameFilterType == "both")
|
|
||||||
// Get game versions less than the current version
|
|
||||||
// Needs support for LBP3 ("both" = LBP1+2)
|
|
||||||
whereHeartedLevels = this.database.HeartedLevels.Where(h => h.User.Username == username)
|
|
||||||
.Where(h => (h.Slot.Type == SlotType.User || h.Slot.Type == SlotType.Developer) && !h.Slot.Hidden && h.Slot.GameVersion <= gameVersion && h.Slot.FirstUploaded >= oldestTime);
|
|
||||||
else
|
|
||||||
// Get game versions exactly equal to gamefiltertype
|
|
||||||
whereHeartedLevels = this.database.HeartedLevels.Where(h => h.User.Username == username)
|
|
||||||
.Where(h => (h.Slot.Type == SlotType.User || h.Slot.Type == SlotType.Developer) && !h.Slot.Hidden && h.Slot.GameVersion == gameVersion && h.Slot.FirstUploaded >= oldestTime);
|
|
||||||
|
|
||||||
return whereHeartedLevels.OrderByDescending(h => h.HeartedLevelId).Include(h => h.Slot.Creator).Select(h => h.Slot).ByGameVersion(gameVersion, false, false, true);
|
|
||||||
}
|
|
||||||
#endregion Filtering
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
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.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -28,7 +28,7 @@ public class ReviewController : ControllerBase
|
||||||
|
|
||||||
// LBP1 rating
|
// LBP1 rating
|
||||||
[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, int rating)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ public class ReviewController : ControllerBase
|
||||||
|
|
||||||
// LBP2 and beyond rating
|
// LBP2 and beyond rating
|
||||||
[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, int rating)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
|
@ -142,54 +142,47 @@ 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)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
|
||||||
|
|
||||||
SlotEntity? 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();
|
||||||
|
|
||||||
List<GameReview> reviews = (await this.database.Reviews.ByGameVersion(gameVersion, true)
|
List<GameReview> reviews = (await this.database.Reviews
|
||||||
.Where(r => r.SlotId == slotId)
|
.Where(r => r.SlotId == slotId)
|
||||||
.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))
|
.ApplyPagination(pageData)
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(r => GameReview.CreateFromEntity(r, token));
|
.ToListAsync()).ToSerializableList(r => GameReview.CreateFromEntity(r, token));
|
||||||
|
|
||||||
|
return this.Ok(new ReviewResponse(reviews, reviews.LastOrDefault()?.Timestamp ?? TimeHelper.TimestampMillis, pageData.HintStart));
|
||||||
return this.Ok(new ReviewResponse(reviews, reviews.LastOrDefault()?.Timestamp ?? TimeHelper.TimestampMillis, pageStart + Math.Min(pageSize, 30)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[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)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
List<GameReview> reviews = (await this.database.Reviews.ByGameVersion(gameVersion, true)
|
List<GameReview> reviews = (await this.database.Reviews
|
||||||
.Where(r => r.ReviewerId == targetUserId)
|
.Where(r => r.ReviewerId == targetUserId)
|
||||||
.OrderByDescending(r => r.Timestamp)
|
.OrderByDescending(r => r.Timestamp)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.ApplyPagination(pageData)
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(r => GameReview.CreateFromEntity(r, token));
|
.ToListAsync()).ToSerializableList(r => GameReview.CreateFromEntity(r, token));
|
||||||
|
|
||||||
return this.Ok(new ReviewResponse(reviews, reviews.LastOrDefault()?.Timestamp ?? TimeHelper.TimestampMillis, pageStart));
|
return this.Ok(new ReviewResponse(reviews, reviews.LastOrDefault()?.Timestamp ?? TimeHelper.TimestampMillis, pageData.HintStart));
|
||||||
}
|
}
|
||||||
|
|
||||||
[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, int rating = 0)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
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.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
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;
|
||||||
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
||||||
|
|
||||||
|
@ -25,102 +27,29 @@ public class SearchController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("searchLBP3")]
|
[HttpGet("searchLBP3")]
|
||||||
public Task<IActionResult> SearchSlotsLBP3([FromQuery] int pageSize, [FromQuery] int pageStart, [FromQuery] string textFilter,
|
public Task<IActionResult> SearchSlotsLBP3([FromQuery] string textFilter)
|
||||||
[FromQuery] int? players = 0,
|
=> this.SearchSlots(textFilter, "results");
|
||||||
[FromQuery] string? labelFilter0 = null,
|
|
||||||
[FromQuery] string? labelFilter1 = null,
|
|
||||||
[FromQuery] string? labelFilter2 = null,
|
|
||||||
[FromQuery] string? labelFilter3 = null,
|
|
||||||
[FromQuery] string? labelFilter4 = null,
|
|
||||||
[FromQuery] string? move = null,
|
|
||||||
[FromQuery] string? adventure = null)
|
|
||||||
=> this.SearchSlots(textFilter, pageSize, pageStart, "results", false, players+1, labelFilter0, labelFilter1, labelFilter2, labelFilter3, labelFilter4, move, adventure);
|
|
||||||
|
|
||||||
[HttpGet("search")]
|
[HttpGet("search")]
|
||||||
public async Task<IActionResult> SearchSlots(
|
public async Task<IActionResult> SearchSlots([FromQuery] string query, string? keyName = "slots")
|
||||||
[FromQuery] string query,
|
|
||||||
[FromQuery] int pageSize,
|
|
||||||
[FromQuery] int pageStart,
|
|
||||||
string? keyName = "slots",
|
|
||||||
bool crosscontrol = false,
|
|
||||||
[FromQuery] int? players = null,
|
|
||||||
[FromQuery] string? labelFilter0 = null,
|
|
||||||
[FromQuery] string? labelFilter1 = null,
|
|
||||||
[FromQuery] string? labelFilter2 = null,
|
|
||||||
[FromQuery] string? labelFilter3 = null,
|
|
||||||
[FromQuery] string? labelFilter4 = null,
|
|
||||||
[FromQuery] string? move = null,
|
|
||||||
[FromQuery] string? adventure = null
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(query)) return this.BadRequest();
|
if (string.IsNullOrWhiteSpace(query)) return this.BadRequest();
|
||||||
|
|
||||||
query = query.ToLower();
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
||||||
|
|
||||||
string[] keywords = query.Split(" ");
|
queryBuilder.AddFilter(new TextFilter(query));
|
||||||
|
|
||||||
IQueryable<SlotEntity> dbQuery = this.database.Slots.ByGameVersion(token.GameVersion, false, true)
|
pageData.TotalElements = await this.database.Slots.Where(queryBuilder.Build()).CountAsync();
|
||||||
.Where(s => s.Type == SlotType.User && s.CrossControllerRequired == crosscontrol)
|
|
||||||
.OrderBy(s => !s.TeamPick)
|
|
||||||
.ThenByDescending(s => s.FirstUploaded)
|
|
||||||
.Where(s => s.SlotId >= 0); // dumb query to conv into IQueryable
|
|
||||||
|
|
||||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
List<SlotBase> slots = await this.database.Slots.Include(s => s.Creator)
|
||||||
foreach (string keyword in keywords)
|
.GetSlots(token, queryBuilder, pageData, new SlotSortBuilder<SlotEntity>());
|
||||||
dbQuery = dbQuery.Where
|
|
||||||
(
|
|
||||||
s => s.Name.ToLower().Contains(keyword) ||
|
|
||||||
s.Description.ToLower().Contains(keyword) ||
|
|
||||||
s.Creator!.Username.ToLower().Contains(keyword) ||
|
|
||||||
s.SlotId.ToString().Equals(keyword)
|
|
||||||
);
|
|
||||||
|
|
||||||
List<SlotEntity> slots = (await dbQuery.Skip(Math.Max(0, pageStart - 1))
|
return this.Ok(new GenericSlotResponse(keyName, slots, pageData));
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync());
|
|
||||||
|
|
||||||
slots = filterSlots(slots, players, labelFilter0, labelFilter1, labelFilter2, labelFilter3, labelFilter4, move, adventure);
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(keyName, slots.ToSerializableList(s => SlotBase.CreateFromEntity(s, token)), await dbQuery.CountAsync(), 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /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
|
||||||
|
|
||||||
private List<SlotEntity> filterSlots(List<SlotEntity> slots, int? players = null, string? labelFilter0 = null, string? labelFilter1 = null, string? labelFilter2 = null, string? labelFilter3 = null, string? labelFilter4 = null, string? move = null, string? adventure = null)
|
|
||||||
{
|
|
||||||
if (players != null)
|
|
||||||
slots.RemoveAll(s => s.MinimumPlayers != players);
|
|
||||||
|
|
||||||
if (labelFilter0 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter0));
|
|
||||||
if (labelFilter1 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter1));
|
|
||||||
if (labelFilter2 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter2));
|
|
||||||
if (labelFilter3 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter3));
|
|
||||||
if (labelFilter4 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter4));
|
|
||||||
|
|
||||||
if (move == "false")
|
|
||||||
slots.RemoveAll(s => s.MoveRequired);
|
|
||||||
if (move == "only")
|
|
||||||
slots.RemoveAll(s => !s.MoveRequired);
|
|
||||||
|
|
||||||
if (move == "noneCan")
|
|
||||||
slots.RemoveAll(s => s.MoveRequired);
|
|
||||||
if (move == "allMust")
|
|
||||||
slots.RemoveAll(s => !s.MoveRequired);
|
|
||||||
|
|
||||||
if (adventure == "noneCan")
|
|
||||||
slots.RemoveAll(s => s.IsAdventurePlanet);
|
|
||||||
if (adventure == "allMust")
|
|
||||||
slots.RemoveAll(s => !s.IsAdventurePlanet);
|
|
||||||
|
|
||||||
return slots;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,16 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Configuration;
|
using System.Linq.Expressions;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Sorts.Metadata;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
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.Filter;
|
||||||
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.Misc;
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
|
@ -23,34 +29,31 @@ namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
||||||
public class SlotsController : ControllerBase
|
public class SlotsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly DatabaseContext database;
|
private readonly DatabaseContext database;
|
||||||
|
|
||||||
public SlotsController(DatabaseContext database)
|
public SlotsController(DatabaseContext database)
|
||||||
{
|
{
|
||||||
this.database = database;
|
this.database = database;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/by")]
|
[HttpGet("slots/by")]
|
||||||
public async Task<IActionResult> SlotsBy([FromQuery(Name = "u")] string username, [FromQuery] int pageStart, [FromQuery] int pageSize, [FromQuery] bool crosscontrol = false)
|
public async Task<IActionResult> SlotsBy([FromQuery(Name = "u")] string username)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
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.NotFound();
|
if (targetUserId == 0) return this.NotFound();
|
||||||
|
|
||||||
int usedSlots = this.database.Slots.Count(s => s.CreatorId == targetUserId);
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
List<SlotBase> slots = (await this.database.Slots.Where(s => s.CreatorId == targetUserId)
|
pageData.TotalElements = await this.database.Slots.CountAsync(s => s.CreatorId == targetUserId);
|
||||||
.ByGameVersion(token.GameVersion, token.UserId == targetUserId)
|
|
||||||
.Where(match => match.CrossControllerRequired == crosscontrol)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, usedSlots))
|
|
||||||
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
int start = pageStart + Math.Min(pageSize, usedSlots);
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token).AddFilter(new CreatorFilter(targetUserId));
|
||||||
int total = await this.database.Slots.CountAsync(s => s.CreatorId == targetUserId && s.CrossControllerRequired == crosscontrol);
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse("slots", slots, total, start));
|
SlotSortBuilder<SlotEntity> sortBuilder = new SlotSortBuilder<SlotEntity>().AddSort(new FirstUploadedSort());
|
||||||
|
|
||||||
|
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, sortBuilder);
|
||||||
|
|
||||||
|
return this.Ok(new GenericSlotResponse("slots", slots, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slotList")]
|
[HttpGet("slotList")]
|
||||||
|
@ -61,7 +64,7 @@ public class SlotsController : ControllerBase
|
||||||
List<SlotBase> slots = new();
|
List<SlotBase> slots = new();
|
||||||
foreach (int slotId in slotIds)
|
foreach (int slotId in slotIds)
|
||||||
{
|
{
|
||||||
SlotEntity? 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.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();
|
||||||
|
@ -102,7 +105,7 @@ public class SlotsController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("s/developer/{id:int}")]
|
[HttpGet("s/developer/{id:int}")]
|
||||||
public async Task<IActionResult> SDev(int id)
|
public async Task<IActionResult> DeveloperSlot(int id)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
|
@ -113,13 +116,12 @@ public class SlotsController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("s/user/{id:int}")]
|
[HttpGet("s/user/{id:int}")]
|
||||||
public async Task<IActionResult> SUser(int id)
|
public async Task<IActionResult> UserSlot(int id)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
SlotEntity? slot = await this.database.Slots.Where(this.GetDefaultFilters(token).Build())
|
||||||
|
.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();
|
||||||
|
|
||||||
|
@ -127,66 +129,40 @@ public class SlotsController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/cool")]
|
[HttpGet("slots/cool")]
|
||||||
public async Task<IActionResult> Lbp1CoolSlots([FromQuery] int page)
|
public async Task<IActionResult> Lbp1CoolSlots() => await this.CoolSlots();
|
||||||
{
|
|
||||||
const int pageSize = 30;
|
|
||||||
return await this.CoolSlots((page - 1) * pageSize, pageSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("slots/lbp2cool")]
|
[HttpGet("slots/lbp2cool")]
|
||||||
public async Task<IActionResult> CoolSlots
|
public async Task<IActionResult> CoolSlots() => await this.ThumbsSlots();
|
||||||
(
|
|
||||||
[FromQuery] int pageStart,
|
|
||||||
[FromQuery] int pageSize,
|
|
||||||
[FromQuery] int players = 1,
|
|
||||||
[FromQuery] string? gameFilterType = null,
|
|
||||||
[FromQuery] string? labelFilter0 = null,
|
|
||||||
[FromQuery] string? labelFilter1 = null,
|
|
||||||
[FromQuery] string? labelFilter2 = null,
|
|
||||||
[FromQuery] string? move = null,
|
|
||||||
[FromQuery] int? page = null,
|
|
||||||
[FromQuery] bool crosscontrol = false
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if (page != null) pageStart = (int)page * 30;
|
|
||||||
// bit of a better placeholder until we can track average user interaction with /stream endpoint
|
|
||||||
return await this.ThumbsSlots(pageStart, Math.Min(pageSize, 30), players, gameFilterType, "thisMonth",
|
|
||||||
labelFilter0, labelFilter1, labelFilter2, move, crosscontrol);
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("slots")]
|
[HttpGet("slots")]
|
||||||
public async Task<IActionResult> NewestSlots([FromQuery] int pageStart, [FromQuery] int pageSize, [FromQuery] bool crosscontrol = false)
|
public async Task<IActionResult> NewestSlots()
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
||||||
|
|
||||||
List<SlotBase> slots = (await this.database.Slots.ByGameVersion(gameVersion, false, true)
|
pageData.TotalElements = await StatisticsHelper.SlotCount(this.database, queryBuilder);
|
||||||
.Where(s => s.CrossControllerRequired == crosscontrol)
|
|
||||||
.OrderByDescending(s => s.FirstUploaded)
|
|
||||||
.ThenByDescending(s => s.SlotId)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
SlotSortBuilder<SlotEntity> sortBuilder = new();
|
||||||
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
sortBuilder.AddSort(new FirstUploadedSort());
|
||||||
return this.Ok(new GenericSlotResponse(slots, total, start));
|
sortBuilder.AddSort(new SlotIdSort());
|
||||||
|
|
||||||
|
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, sortBuilder);
|
||||||
|
|
||||||
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
[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)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
if (slotType != "user") return this.BadRequest();
|
if (slotType != "user") return this.BadRequest();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
|
||||||
|
|
||||||
SlotEntity? 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();
|
||||||
|
|
||||||
|
@ -198,275 +174,180 @@ public class SlotsController : ControllerBase
|
||||||
.Select(r => r.SlotId)
|
.Select(r => r.SlotId)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
List<SlotBase> slots = (await this.database.Slots.ByGameVersion(gameVersion, false, true)
|
pageData.TotalElements = slotIdsWithTag.Count;
|
||||||
.Where(s => slotIdsWithTag.Contains(s.SlotId))
|
|
||||||
.OrderByDescending(s => s.PlaysLBP1)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token).AddFilter(0, new SlotIdFilter(slotIdsWithTag));
|
||||||
int total = slotIdsWithTag.Count;
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(slots, total, start));
|
SlotSortBuilder<SlotEntity> sortBuilder = new();
|
||||||
|
sortBuilder.AddSort(new PlaysForGameSort(GameVersion.LittleBigPlanet1));
|
||||||
|
|
||||||
|
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, sortBuilder);
|
||||||
|
|
||||||
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/highestRated")]
|
[HttpGet("slots/highestRated")]
|
||||||
public async Task<IActionResult> HighestRatedSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
|
public async Task<IActionResult> HighestRatedSlots()
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
||||||
|
|
||||||
List<SlotBase> slots = (await this.database.Slots.ByGameVersion(gameVersion, false, true)
|
pageData.TotalElements = await StatisticsHelper.SlotCount(this.database, queryBuilder);
|
||||||
.Select(s => new SlotMetadata
|
|
||||||
{
|
|
||||||
Slot = s,
|
|
||||||
RatingLbp1 = this.database.RatedLevels.Where(r => r.SlotId == s.SlotId).Average(r => (double?)r.RatingLBP1) ?? 3.0,
|
|
||||||
})
|
|
||||||
.OrderByDescending(s => s.RatingLbp1)
|
|
||||||
.Select(s => s.Slot)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
SlotSortBuilder<SlotMetadata> sortBuilder = new();
|
||||||
int total = await StatisticsHelper.SlotCount(this.database);
|
sortBuilder.AddSort(new RatingLBP1Sort());
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(slots, total, start));
|
Expression<Func<SlotEntity, SlotMetadata>> selectorFunc = s => new SlotMetadata
|
||||||
|
{
|
||||||
|
Slot = s,
|
||||||
|
RatingLbp1 = this.database.RatedLevels.Where(r => r.SlotId == s.SlotId)
|
||||||
|
.Average(r => (double?)r.RatingLBP1) ?? 3.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, sortBuilder, selectorFunc);
|
||||||
|
|
||||||
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
[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)
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
List<SlotBase> slots = (await this.database.Slots.Where(s => slotIdsWithTag.Contains(s.SlotId))
|
pageData.TotalElements = slotIdsWithTag.Count;
|
||||||
.ByGameVersion(token.GameVersion, false, true)
|
|
||||||
.OrderByDescending(s => s.PlaysLBP1)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
SlotSortBuilder<SlotEntity> sortBuilder = new();
|
||||||
int total = slotIdsWithTag.Count;
|
sortBuilder.AddSort(new PlaysForGameSort(GameVersion.LittleBigPlanet1));
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(slots, total, start));
|
List<SlotBase> slots = await this.database.GetSlots(token, this.FilterFromRequest(token), pageData, sortBuilder);
|
||||||
|
|
||||||
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/mmpicks")]
|
[HttpGet("slots/mmpicks")]
|
||||||
public async Task<IActionResult> TeamPickedSlots
|
public async Task<IActionResult> TeamPickedSlots()
|
||||||
(
|
|
||||||
[FromQuery] int pageStart,
|
|
||||||
[FromQuery] int pageSize,
|
|
||||||
[FromQuery] int players,
|
|
||||||
[FromQuery] string? gameFilterType = null,
|
|
||||||
[FromQuery] string? dateFilterType = null,
|
|
||||||
[FromQuery] string? labelFilter0 = null,
|
|
||||||
[FromQuery] string? labelFilter1 = null,
|
|
||||||
[FromQuery] string? labelFilter2 = null,
|
|
||||||
[FromQuery] string? move = null,
|
|
||||||
[FromQuery] bool crosscontrol = false
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
List<SlotBase> slots = this.filterSlots((await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token).AddFilter(new TeamPickFilter());
|
||||||
.Where(s => s.TeamPick && s.CrossControllerRequired == crosscontrol)
|
|
||||||
.OrderByDescending(s => s.LastUpdated)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()), players, labelFilter0, labelFilter1, labelFilter2, move).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
|
||||||
int total = await StatisticsHelper.TeamPickCountForGame(this.database, token.GameVersion, crosscontrol);
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(slots, total, start));
|
pageData.TotalElements = await StatisticsHelper.SlotCount(this.database, queryBuilder);
|
||||||
|
|
||||||
|
SlotSortBuilder<SlotEntity> sortBuilder = new();
|
||||||
|
sortBuilder.AddSort(new LastUpdatedSort());
|
||||||
|
|
||||||
|
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, sortBuilder);
|
||||||
|
|
||||||
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/lbp2luckydip")]
|
[HttpGet("slots/lbp2luckydip")]
|
||||||
public async Task<IActionResult> LuckyDipSlots
|
public async Task<IActionResult> LuckyDipSlots([FromQuery] int seed)
|
||||||
(
|
|
||||||
[FromQuery] int pageStart,
|
|
||||||
[FromQuery] int pageSize,
|
|
||||||
[FromQuery] int seed,
|
|
||||||
[FromQuery] int players = 1,
|
|
||||||
[FromQuery] string? gameFilterType = null,
|
|
||||||
[FromQuery] string? dateFilterType = null,
|
|
||||||
[FromQuery] string? labelFilter0 = null,
|
|
||||||
[FromQuery] string? labelFilter1 = null,
|
|
||||||
[FromQuery] string? labelFilter2 = null,
|
|
||||||
[FromQuery] string? move = null,
|
|
||||||
[FromQuery] bool crosscontrol = false
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
GameVersion gameVersion = token.GameVersion;
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
||||||
|
|
||||||
const double biasFactor = .8f;
|
pageData.TotalElements = await StatisticsHelper.SlotCount(this.database, queryBuilder);
|
||||||
List<SlotBase> slots = this.filterSlots((await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
|
||||||
.Where(s => s.CrossControllerRequired == crosscontrol)
|
|
||||||
.OrderByDescending(s => EF.Functions.Random() * (s.FirstUploaded * biasFactor))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()), players, labelFilter0, labelFilter1, labelFilter2, move).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
SlotSortBuilder<SlotEntity> sortBuilder = new();
|
||||||
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
sortBuilder.AddSort(new RandomFirstUploadedSort());
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(slots, total, start));
|
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, sortBuilder);
|
||||||
|
|
||||||
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/thumbs")]
|
[HttpGet("slots/thumbs")]
|
||||||
public async Task<IActionResult> ThumbsSlots
|
public async Task<IActionResult> ThumbsSlots()
|
||||||
(
|
|
||||||
[FromQuery] int pageStart,
|
|
||||||
[FromQuery] int pageSize,
|
|
||||||
[FromQuery] int players,
|
|
||||||
[FromQuery] string? gameFilterType = null,
|
|
||||||
[FromQuery] string? dateFilterType = null,
|
|
||||||
[FromQuery] string? labelFilter0 = null,
|
|
||||||
[FromQuery] string? labelFilter1 = null,
|
|
||||||
[FromQuery] string? labelFilter2 = null,
|
|
||||||
[FromQuery] string? move = null,
|
|
||||||
[FromQuery] bool crosscontrol = false
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
List<SlotBase> slots = this.filterSlots((await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
||||||
.Where(s => s.CrossControllerRequired == crosscontrol)
|
|
||||||
.Select(s => new SlotMetadata
|
|
||||||
{
|
|
||||||
Slot = s,
|
|
||||||
ThumbsUp = this.database.RatedLevels.Count(r => r.SlotId == s.SlotId && r.Rating == 1),
|
|
||||||
})
|
|
||||||
.OrderByDescending(s => s.ThumbsUp)
|
|
||||||
.ThenBy(_ => EF.Functions.Random())
|
|
||||||
.Select(s => s.Slot)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()), players, labelFilter0, labelFilter1, labelFilter2, move).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
pageData.TotalElements = await StatisticsHelper.SlotCount(this.database, queryBuilder);
|
||||||
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(slots, total, start));
|
SlotSortBuilder<SlotMetadata> sortBuilder = new();
|
||||||
|
sortBuilder.AddSort(new ThumbsUpSort());
|
||||||
|
|
||||||
|
Expression<Func<SlotEntity, SlotMetadata>> selectorFunc = s => new SlotMetadata
|
||||||
|
{
|
||||||
|
Slot = s,
|
||||||
|
ThumbsUp = this.database.RatedLevels.Count(r => r.SlotId == s.SlotId && r.Rating == 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, sortBuilder, selectorFunc);
|
||||||
|
|
||||||
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/mostUniquePlays")]
|
[HttpGet("slots/mostUniquePlays")]
|
||||||
public async Task<IActionResult> MostUniquePlaysSlots
|
public async Task<IActionResult> MostUniquePlaysSlots()
|
||||||
(
|
|
||||||
[FromQuery] int pageStart,
|
|
||||||
[FromQuery] int pageSize,
|
|
||||||
[FromQuery] int players,
|
|
||||||
[FromQuery] string? gameFilterType = null,
|
|
||||||
[FromQuery] string? labelFilter0 = null,
|
|
||||||
[FromQuery] string? labelFilter1 = null,
|
|
||||||
[FromQuery] string? labelFilter2 = null,
|
|
||||||
[FromQuery] string? move = null,
|
|
||||||
[FromQuery] string? dateFilterType = null,
|
|
||||||
[FromQuery] bool crosscontrol = false
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
string game = getGameFilter(gameFilterType, token.GameVersion) switch
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
||||||
{
|
|
||||||
GameVersion.LittleBigPlanet1 => "LBP1",
|
|
||||||
GameVersion.LittleBigPlanet2 => "LBP2",
|
|
||||||
GameVersion.LittleBigPlanet3 => "LBP3",
|
|
||||||
GameVersion.LittleBigPlanetVita => "LBP2",
|
|
||||||
_ => "",
|
|
||||||
};
|
|
||||||
|
|
||||||
string colName = $"Plays{game}Unique";
|
pageData.TotalElements = await StatisticsHelper.SlotCount(this.database, queryBuilder);
|
||||||
|
|
||||||
List<SlotBase> slots = this.filterSlots((await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
SlotSortBuilder<SlotEntity> sortBuilder = new();
|
||||||
.Where(s => s.CrossControllerRequired == crosscontrol)
|
sortBuilder.AddSort(new UniquePlaysForGameSort(token.GameVersion));
|
||||||
.OrderByDescending(s => EF.Property<int>(s, colName))
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()), players, labelFilter0, labelFilter1, labelFilter2, move).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, sortBuilder);
|
||||||
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(slots, total, start));
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("slots/mostHearted")]
|
[HttpGet("slots/mostHearted")]
|
||||||
public async Task<IActionResult> MostHeartedSlots
|
public async Task<IActionResult> MostHeartedSlots()
|
||||||
(
|
|
||||||
[FromQuery] int pageStart,
|
|
||||||
[FromQuery] int pageSize,
|
|
||||||
[FromQuery] int players,
|
|
||||||
[FromQuery] string? gameFilterType = null,
|
|
||||||
[FromQuery] string? labelFilter0 = null,
|
|
||||||
[FromQuery] string? labelFilter1 = null,
|
|
||||||
[FromQuery] string? labelFilter2 = null,
|
|
||||||
[FromQuery] string? move = null,
|
|
||||||
[FromQuery] string? dateFilterType = null,
|
|
||||||
[FromQuery] bool crosscontrol = false
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
List<SlotBase> slots = this.filterSlots((await this.filterByRequest(gameFilterType, dateFilterType, token.GameVersion)
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
||||||
.Where(s => s.CrossControllerRequired == crosscontrol)
|
|
||||||
.Select(s => new SlotMetadata
|
|
||||||
{
|
|
||||||
Slot = s,
|
|
||||||
Hearts = this.database.HeartedLevels.Count(r => r.SlotId == s.SlotId),
|
|
||||||
})
|
|
||||||
.OrderByDescending(s => s.Hearts)
|
|
||||||
.Select(s => s.Slot)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.ToListAsync()), players, labelFilter0, labelFilter1, labelFilter2, move).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
|
||||||
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
pageData.TotalElements = await StatisticsHelper.SlotCount(this.database, queryBuilder);
|
||||||
int total = await StatisticsHelper.SlotCountForGame(this.database, token.GameVersion);
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(slots, total, start));
|
SlotSortBuilder<SlotMetadata> sortBuilder = new();
|
||||||
|
sortBuilder.AddSort(new HeartsSort());
|
||||||
|
|
||||||
|
Expression<Func<SlotEntity, SlotMetadata>> selectorFunc = s => new SlotMetadata
|
||||||
|
{
|
||||||
|
Slot = s,
|
||||||
|
Hearts = this.database.HeartedLevels.Count(r => r.SlotId == s.SlotId),
|
||||||
|
};
|
||||||
|
|
||||||
|
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, sortBuilder, selectorFunc);
|
||||||
|
|
||||||
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
}
|
}
|
||||||
|
|
||||||
// /slots/busiest?pageStart=1&pageSize=30&gameFilterType=both&players=1&move=true
|
// /slots/busiest?pageStart=1&pageSize=30&gameFilterType=both&players=1&move=true
|
||||||
[HttpGet("slots/busiest")]
|
[HttpGet("slots/busiest")]
|
||||||
public async Task<IActionResult> BusiestLevels
|
public async Task<IActionResult> BusiestLevels()
|
||||||
(
|
|
||||||
[FromQuery] int pageStart,
|
|
||||||
[FromQuery] int pageSize,
|
|
||||||
[FromQuery] string? gameFilterType = null,
|
|
||||||
[FromQuery] int players = 1,
|
|
||||||
[FromQuery] string? labelFilter0 = null,
|
|
||||||
[FromQuery] string? labelFilter1 = null,
|
|
||||||
[FromQuery] string? labelFilter2 = null,
|
|
||||||
[FromQuery] string? move = null,
|
|
||||||
[FromQuery] bool crosscontrol = false
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
GameTokenEntity token = this.GetToken();
|
GameTokenEntity token = this.GetToken();
|
||||||
|
|
||||||
if (pageSize <= 0) return this.BadRequest();
|
PaginationData pageData = this.Request.GetPaginationData();
|
||||||
|
|
||||||
Dictionary<int, int> playersBySlotId = new();
|
Dictionary<int, int> playersBySlotId = new();
|
||||||
|
|
||||||
|
@ -484,98 +365,15 @@ public class SlotsController : ControllerBase
|
||||||
playersBySlotId.Add(room.Slot.SlotId, playerCount);
|
playersBySlotId.Add(room.Slot.SlotId, playerCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<int> orderedPlayersBySlotId = playersBySlotId
|
pageData.TotalElements = playersBySlotId.Count;
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 30))
|
|
||||||
.OrderByDescending(kvp => kvp.Value)
|
|
||||||
.Select(kvp => kvp.Key);
|
|
||||||
|
|
||||||
List<SlotEntity> slots = new();
|
List<int> orderedPlayersBySlotId = playersBySlotId.OrderByDescending(kvp => kvp.Value).Select(kvp => kvp.Key).ToList();
|
||||||
|
|
||||||
foreach (int slotId in orderedPlayersBySlotId)
|
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token);
|
||||||
{
|
queryBuilder.AddFilter(0, new SlotIdFilter(orderedPlayersBySlotId));
|
||||||
SlotEntity? slot = await this.database.Slots.ByGameVersion(token.GameVersion, false, true)
|
|
||||||
.Where(s => s.SlotId == slotId && s.CrossControllerRequired == crosscontrol)
|
|
||||||
.FirstOrDefaultAsync();
|
|
||||||
if (slot == null) continue; // shouldn't happen ever unless the room is borked
|
|
||||||
|
|
||||||
slots.Add(slot);
|
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, new SlotSortBuilder<SlotEntity>());
|
||||||
}
|
|
||||||
|
|
||||||
slots = this.filterSlots(slots, players, labelFilter0, labelFilter1, labelFilter2, move);
|
return this.Ok(new GenericSlotResponse(slots, pageData));
|
||||||
|
|
||||||
int start = pageStart + Math.Min(pageSize, ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots);
|
|
||||||
int total = playersBySlotId.Count;
|
|
||||||
|
|
||||||
return this.Ok(new GenericSlotResponse(slots.ToSerializableList(s => SlotBase.CreateFromEntity(s, token)), total, start));
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<SlotEntity> filterSlots(List<SlotEntity> slots, int players, string? labelFilter0 = null, string? labelFilter1 = null, string? labelFilter2 = null, string? move = null)
|
|
||||||
{
|
|
||||||
slots.RemoveAll(s => s.MinimumPlayers != players);
|
|
||||||
|
|
||||||
if (labelFilter0 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter0));
|
|
||||||
if (labelFilter1 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter1));
|
|
||||||
if (labelFilter2 != null)
|
|
||||||
slots.RemoveAll(s => !s.AuthorLabels.Split(',').ToList().Contains(labelFilter2));
|
|
||||||
|
|
||||||
if (move == "false")
|
|
||||||
slots.RemoveAll(s => s.MoveRequired);
|
|
||||||
if (move == "only")
|
|
||||||
slots.RemoveAll(s => !s.MoveRequired);
|
|
||||||
|
|
||||||
return slots;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static GameVersion getGameFilter(string? gameFilterType, GameVersion version)
|
|
||||||
{
|
|
||||||
return version switch
|
|
||||||
{
|
|
||||||
GameVersion.LittleBigPlanetVita => GameVersion.LittleBigPlanetVita,
|
|
||||||
GameVersion.LittleBigPlanetPSP => GameVersion.LittleBigPlanetPSP,
|
|
||||||
_ => gameFilterType switch
|
|
||||||
{
|
|
||||||
"lbp1" => GameVersion.LittleBigPlanet1,
|
|
||||||
"lbp2" => GameVersion.LittleBigPlanet2,
|
|
||||||
"lbp3" => GameVersion.LittleBigPlanet3,
|
|
||||||
"both" => GameVersion.LittleBigPlanet2, // LBP2 default option
|
|
||||||
null => GameVersion.LittleBigPlanet1,
|
|
||||||
_ => GameVersion.Unknown,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private IQueryable<SlotEntity> filterByRequest(string? gameFilterType, string? dateFilterType, GameVersion version)
|
|
||||||
{
|
|
||||||
if (version == GameVersion.LittleBigPlanetVita || version == GameVersion.LittleBigPlanetPSP || version == GameVersion.Unknown)
|
|
||||||
{
|
|
||||||
return this.database.Slots.ByGameVersion(version, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
string _dateFilterType = dateFilterType ?? "";
|
|
||||||
|
|
||||||
long oldestTime = _dateFilterType switch
|
|
||||||
{
|
|
||||||
"thisWeek" => DateTimeOffset.Now.AddDays(-7).ToUnixTimeMilliseconds(),
|
|
||||||
"thisMonth" => DateTimeOffset.Now.AddDays(-31).ToUnixTimeMilliseconds(),
|
|
||||||
_ => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
GameVersion gameVersion = getGameFilter(gameFilterType, version);
|
|
||||||
|
|
||||||
IQueryable<SlotEntity> whereSlots;
|
|
||||||
|
|
||||||
// ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
|
|
||||||
if (gameFilterType == "both")
|
|
||||||
// Get game versions less than the current version
|
|
||||||
// Needs support for LBP3 ("both" = LBP1+2)
|
|
||||||
whereSlots = this.database.Slots.Where(s => s.Type == SlotType.User && !s.Hidden && s.GameVersion <= gameVersion && s.FirstUploaded >= oldestTime);
|
|
||||||
else
|
|
||||||
// Get game versions exactly equal to gamefiltertype
|
|
||||||
whereSlots = this.database.Slots.Where(s => s.Type == SlotType.User && !s.Hidden && s.GameVersion == gameVersion && s.FirstUploaded >= oldestTime);
|
|
||||||
|
|
||||||
return whereSlots.Include(s => s.Creator);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,8 +3,10 @@ using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
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.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
|
|
||||||
|
@ -14,7 +16,6 @@ namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
[Produces("text/plain")]
|
[Produces("text/plain")]
|
||||||
public class StatisticsController : ControllerBase
|
public class StatisticsController : ControllerBase
|
||||||
{
|
{
|
||||||
|
|
||||||
private readonly DatabaseContext database;
|
private readonly DatabaseContext database;
|
||||||
|
|
||||||
public StatisticsController(DatabaseContext database)
|
public StatisticsController(DatabaseContext database)
|
||||||
|
@ -23,7 +24,7 @@ public class StatisticsController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("playersInPodCount")]
|
[HttpGet("playersInPodCount")]
|
||||||
public IActionResult PlayersInPodCount() => this.Ok(StatisticsHelper.RoomCountForPlatform(this.GetToken().Platform).ToString());
|
public IActionResult PlayersInPodCount() => this.Ok(StatisticsHelper.RoomCountForPlatform(this.GetToken().Platform).ToString());
|
||||||
|
|
||||||
[HttpGet("totalPlayerCount")]
|
[HttpGet("totalPlayerCount")]
|
||||||
public async Task<IActionResult> TotalPlayerCount() => this.Ok((await StatisticsHelper.RecentMatchesForGame(this.database, this.GetToken().GameVersion)).ToString());
|
public async Task<IActionResult> TotalPlayerCount() => this.Ok((await StatisticsHelper.RecentMatchesForGame(this.database, this.GetToken().GameVersion)).ToString());
|
||||||
|
@ -32,12 +33,19 @@ public IActionResult PlayersInPodCount() => this.Ok(StatisticsHelper.RoomCountFo
|
||||||
[Produces("text/xml")]
|
[Produces("text/xml")]
|
||||||
public async Task<IActionResult> PlanetStats()
|
public async Task<IActionResult> PlanetStats()
|
||||||
{
|
{
|
||||||
int totalSlotCount = await StatisticsHelper.SlotCountForGame(this.database, this.GetToken().GameVersion);
|
SlotQueryBuilder defaultFilter = this.GetDefaultFilters(this.GetToken());
|
||||||
int mmPicksCount = await StatisticsHelper.TeamPickCountForGame(this.database, this.GetToken().GameVersion);
|
int totalSlotCount = await StatisticsHelper.SlotCount(this.database, defaultFilter);
|
||||||
|
defaultFilter.AddFilter(new TeamPickFilter());
|
||||||
|
int mmPicksCount = await StatisticsHelper.SlotCount(this.database, defaultFilter);
|
||||||
|
|
||||||
return this.Ok(new PlanetStatsResponse(totalSlotCount, mmPicksCount));
|
return this.Ok(new PlanetStatsResponse(totalSlotCount, mmPicksCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("planetStats/totalLevelCount")]
|
[HttpGet("planetStats/totalLevelCount")]
|
||||||
public async Task<IActionResult> TotalLevelCount() => this.Ok((await StatisticsHelper.SlotCountForGame(this.database, this.GetToken().GameVersion)).ToString());
|
public async Task<IActionResult> TotalLevelCount()
|
||||||
|
{
|
||||||
|
SlotQueryBuilder defaultFilter = this.GetDefaultFilters(this.GetToken());
|
||||||
|
int totalSlotCount = await StatisticsHelper.SlotCount(this.database, defaultFilter);
|
||||||
|
return this.Ok(totalSlotCount.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
|
|
||||||
|
public static class ControllerExtensions
|
||||||
|
{
|
||||||
|
private static GameVersion GetGameFilter(string? gameFilterType, GameVersion version)
|
||||||
|
{
|
||||||
|
return version switch
|
||||||
|
{
|
||||||
|
GameVersion.LittleBigPlanetVita => GameVersion.LittleBigPlanetVita,
|
||||||
|
GameVersion.LittleBigPlanetPSP => GameVersion.LittleBigPlanetPSP,
|
||||||
|
_ => gameFilterType switch
|
||||||
|
{
|
||||||
|
"lbp1" => GameVersion.LittleBigPlanet1,
|
||||||
|
"lbp2" => GameVersion.LittleBigPlanet2,
|
||||||
|
"lbp3" => GameVersion.LittleBigPlanet3,
|
||||||
|
"both" => GameVersion.LittleBigPlanet2, // LBP2 default option
|
||||||
|
null => GameVersion.LittleBigPlanet1,
|
||||||
|
_ => GameVersion.Unknown,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SlotQueryBuilder GetDefaultFilters(this ControllerBase controller, GameTokenEntity token) =>
|
||||||
|
new SlotQueryBuilder().AddFilter(new GameVersionFilter(token.GameVersion))
|
||||||
|
.AddFilter(new SubLevelFilter(token.UserId))
|
||||||
|
.AddFilter(new HiddenSlotFilter())
|
||||||
|
.AddFilter(new SlotTypeFilter(SlotType.User));
|
||||||
|
|
||||||
|
public static SlotQueryBuilder FilterFromRequest(this ControllerBase controller, GameTokenEntity token)
|
||||||
|
{
|
||||||
|
SlotQueryBuilder queryBuilder = new();
|
||||||
|
|
||||||
|
List<string> authorLabels = new();
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
string? label = controller.Request.Query[$"labelFilter{i}"];
|
||||||
|
if (label == null) continue;
|
||||||
|
authorLabels.Add(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authorLabels.Count > 0) queryBuilder.AddFilter(new AuthorLabelFilter(authorLabels.ToArray()));
|
||||||
|
|
||||||
|
if (int.TryParse(controller.Request.Query["players"], out int minPlayers) && minPlayers >= 1)
|
||||||
|
{
|
||||||
|
// LBP3 starts counting at 0
|
||||||
|
if (token.GameVersion == GameVersion.LittleBigPlanet3) minPlayers++;
|
||||||
|
|
||||||
|
queryBuilder.AddFilter(new PlayerCountFilter(minPlayers));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller.Request.Query.ContainsKey("textFilter"))
|
||||||
|
{
|
||||||
|
string textFilter = (string?)controller.Request.Query["textFilter"] ?? "";
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(textFilter)) queryBuilder.AddFilter(new TextFilter(textFilter));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller.Request.Query.ContainsKey("dateFilterType"))
|
||||||
|
{
|
||||||
|
string dateFilter = (string?)controller.Request.Query["dateFilterType"] ?? "";
|
||||||
|
long oldestTime = dateFilter switch
|
||||||
|
{
|
||||||
|
"thisWeek" => DateTimeOffset.UtcNow.AddDays(-7).ToUnixTimeMilliseconds(),
|
||||||
|
"thisMonth" => DateTimeOffset.UtcNow.AddDays(-31).ToUnixTimeMilliseconds(),
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
if (oldestTime != 0) queryBuilder.AddFilter(new FirstUploadedFilter(oldestTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.GameVersion != GameVersion.LittleBigPlanet3)
|
||||||
|
{
|
||||||
|
if (controller.Request.Query.ContainsKey("move"))
|
||||||
|
{
|
||||||
|
string moveFilter = (string?)controller.Request.Query["move"] ?? "";
|
||||||
|
// By default this will include levels with move so we don't handle true
|
||||||
|
switch (moveFilter)
|
||||||
|
{
|
||||||
|
case "false":
|
||||||
|
queryBuilder.AddFilter(new ExcludeMovePackFilter());
|
||||||
|
break;
|
||||||
|
case "only":
|
||||||
|
queryBuilder.AddFilter(new MovePackFilter());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bool.TryParse(controller.Request.Query["move"], out bool movePack) && !movePack)
|
||||||
|
queryBuilder.AddFilter(new ExcludeMovePackFilter());
|
||||||
|
|
||||||
|
if (bool.TryParse(controller.Request.Query["crosscontrol"], out bool crossControl) && crossControl)
|
||||||
|
queryBuilder.AddFilter(new CrossControlFilter());
|
||||||
|
|
||||||
|
GameVersion targetVersion = token.GameVersion;
|
||||||
|
|
||||||
|
if (controller.Request.Query.ContainsKey("gameFilterType"))
|
||||||
|
{
|
||||||
|
string gameFilter = (string?)controller.Request.Query["gameFilterType"] ?? "";
|
||||||
|
GameVersion filterVersion = GetGameFilter(gameFilter, targetVersion);
|
||||||
|
// Don't serve lbp3 levels to lbp2 just cause of the game filter
|
||||||
|
if (filterVersion <= targetVersion)
|
||||||
|
{
|
||||||
|
targetVersion = filterVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queryBuilder.AddFilter(new GameVersionFilter(targetVersion));
|
||||||
|
}
|
||||||
|
else if (token.GameVersion == GameVersion.LittleBigPlanet3)
|
||||||
|
{
|
||||||
|
void ParseLbp3Query(string key, Action allMust, Action noneCan, Action dontCare)
|
||||||
|
{
|
||||||
|
if (!controller.Request.Query.ContainsKey(key)) return;
|
||||||
|
|
||||||
|
string value = (string?)controller.Request.Query[key] ?? "dontCare";
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case "allMust":
|
||||||
|
allMust();
|
||||||
|
break;
|
||||||
|
case "noneCan":
|
||||||
|
noneCan();
|
||||||
|
break;
|
||||||
|
case "dontCare":
|
||||||
|
dontCare();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseLbp3Query("adventure",
|
||||||
|
() => queryBuilder.AddFilter(new AdventureFilter()),
|
||||||
|
() => queryBuilder.AddFilter(new ExcludeAdventureFilter()),
|
||||||
|
() =>
|
||||||
|
{ });
|
||||||
|
|
||||||
|
ParseLbp3Query("move",
|
||||||
|
() => queryBuilder.AddFilter(new MovePackFilter()),
|
||||||
|
() => queryBuilder.AddFilter(new ExcludeMovePackFilter()),
|
||||||
|
() =>
|
||||||
|
{ });
|
||||||
|
|
||||||
|
string[]? ParseLbp3ArrayQuery(string key)
|
||||||
|
{
|
||||||
|
return !controller.Request.Query.TryGetValue($"{key}[]", out StringValues keys)
|
||||||
|
? null
|
||||||
|
: keys.Where(s => s != null).Select(s => s!).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
string[]? gameFilters = ParseLbp3ArrayQuery("gameFilter");
|
||||||
|
if (gameFilters != null)
|
||||||
|
{
|
||||||
|
queryBuilder.AddFilter(new GameVersionListFilter(gameFilters
|
||||||
|
.Select(s => GetGameFilter(s, token.GameVersion))
|
||||||
|
.ToArray()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
queryBuilder.AddFilter(new GameVersionFilter(GameVersion.LittleBigPlanet3));
|
||||||
|
}
|
||||||
|
|
||||||
|
string[]? resultFilters = ParseLbp3ArrayQuery("resultType");
|
||||||
|
if (resultFilters != null)
|
||||||
|
{
|
||||||
|
queryBuilder.AddFilter(new ResultTypeFilter(resultFilters));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.GameVersion != GameVersion.LittleBigPlanet1)
|
||||||
|
queryBuilder.AddFilter(new ExcludeLBP1OnlyFilter(token.UserId, token.GameVersion));
|
||||||
|
|
||||||
|
queryBuilder.AddFilter(new SubLevelFilter(token.UserId));
|
||||||
|
queryBuilder.AddFilter(new HiddenSlotFilter());
|
||||||
|
queryBuilder.AddFilter(new SlotTypeFilter(SlotType.User));
|
||||||
|
|
||||||
|
return queryBuilder;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
|
|
||||||
|
public static class DatabaseContextExtensions
|
||||||
|
{
|
||||||
|
public static async Task<List<SlotBase>> GetSlots
|
||||||
|
(
|
||||||
|
this IQueryable<SlotEntity> queryable,
|
||||||
|
GameTokenEntity token,
|
||||||
|
SlotQueryBuilder queryBuilder,
|
||||||
|
PaginationData pageData,
|
||||||
|
ISortBuilder<SlotEntity> sortBuilder
|
||||||
|
) =>
|
||||||
|
(await queryable.Where(queryBuilder.Build())
|
||||||
|
.ApplyOrdering(sortBuilder)
|
||||||
|
.ApplyPagination(pageData)
|
||||||
|
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
||||||
|
|
||||||
|
public static async Task<List<SlotBase>> GetSlots
|
||||||
|
(
|
||||||
|
this DatabaseContext database,
|
||||||
|
GameTokenEntity token,
|
||||||
|
SlotQueryBuilder queryBuilder,
|
||||||
|
PaginationData pageData,
|
||||||
|
ISortBuilder<SlotEntity> sortBuilder
|
||||||
|
) =>
|
||||||
|
(await database.Slots.Where(queryBuilder.Build())
|
||||||
|
.ApplyOrdering(sortBuilder)
|
||||||
|
.ApplyPagination(pageData)
|
||||||
|
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
||||||
|
|
||||||
|
public static async Task<List<SlotBase>> GetSlots
|
||||||
|
(
|
||||||
|
this DatabaseContext database,
|
||||||
|
GameTokenEntity token,
|
||||||
|
SlotQueryBuilder queryBuilder,
|
||||||
|
PaginationData pageData,
|
||||||
|
ISortBuilder<SlotMetadata> sortBuilder,
|
||||||
|
Expression<Func<SlotEntity, SlotMetadata>> selectorFunction
|
||||||
|
) =>
|
||||||
|
(await database.Slots.Where(queryBuilder.Build())
|
||||||
|
.AsQueryable()
|
||||||
|
.Select(selectorFunction)
|
||||||
|
.ApplyOrdering(sortBuilder)
|
||||||
|
.Select(s => s.Slot)
|
||||||
|
.ApplyPagination(pageData)
|
||||||
|
.ToListAsync()).ToSerializableList(s => SlotBase.CreateFromEntity(s, token));
|
||||||
|
}
|
|
@ -15,6 +15,8 @@ public static class CategoryHelper
|
||||||
Categories.Add(new NewestLevelsCategory());
|
Categories.Add(new NewestLevelsCategory());
|
||||||
Categories.Add(new MostPlayedCategory());
|
Categories.Add(new MostPlayedCategory());
|
||||||
Categories.Add(new HighestRatedCategory());
|
Categories.Add(new HighestRatedCategory());
|
||||||
|
Categories.Add(new MyHeartedCreatorsCategory());
|
||||||
|
Categories.Add(new MyPlaylistsCategory());
|
||||||
Categories.Add(new QueueCategory());
|
Categories.Add(new QueueCategory());
|
||||||
Categories.Add(new HeartedCategory());
|
Categories.Add(new HeartedCategory());
|
||||||
Categories.Add(new LuckyDipCategory());
|
Categories.Add(new LuckyDipCategory());
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
#nullable enable
|
|
||||||
using System.Diagnostics;
|
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Logging;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
|
||||||
|
|
||||||
public abstract class CategoryWithUser : Category
|
|
||||||
{
|
|
||||||
public abstract SlotEntity? GetPreviewSlot(DatabaseContext database, UserEntity user);
|
|
||||||
public override SlotEntity? GetPreviewSlot(DatabaseContext database)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
Logger.Error("tried to get preview slot without user on CategoryWithUser", LogArea.Category);
|
|
||||||
if (Debugger.IsAttached) Debugger.Break();
|
|
||||||
#endif
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract int GetTotalSlots(DatabaseContext database, UserEntity user);
|
|
||||||
public override int GetTotalSlots(DatabaseContext database)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
Logger.Error("tried to get total slots without user on CategoryWithUser", LogArea.Category);
|
|
||||||
if (Debugger.IsAttached) Debugger.Break();
|
|
||||||
#endif
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract IQueryable<SlotEntity> GetSlots(DatabaseContext database, UserEntity user, int pageStart, int pageSize);
|
|
||||||
public override IList<SlotEntity> GetSlots(DatabaseContext database, int pageStart, int pageSize)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
Logger.Error("tried to get slots without user on CategoryWithUser", LogArea.Category);
|
|
||||||
if (Debugger.IsAttached) Debugger.Break();
|
|
||||||
#endif
|
|
||||||
return new List<SlotEntity>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public new string Serialize(DatabaseContext database)
|
|
||||||
{
|
|
||||||
Logger.Error("tried to serialize without user on CategoryWithUser", LogArea.Category);
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameCategory Serialize(DatabaseContext database, UserEntity user)
|
|
||||||
{
|
|
||||||
List<SlotBase> slots = new();
|
|
||||||
SlotEntity? previewSlot = this.GetPreviewSlot(database, user);
|
|
||||||
if (previewSlot != null)
|
|
||||||
slots.Add(SlotBase.CreateFromEntity(previewSlot, GameVersion.LittleBigPlanet3, user.UserId));
|
|
||||||
|
|
||||||
int totalSlots = this.GetTotalSlots(database, user);
|
|
||||||
return GameCategory.CreateFromEntity(this, new GenericSlotResponse(slots, totalSlots, 2));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +1,15 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
public class CustomCategory : Category
|
public class CustomCategory : SlotCategory
|
||||||
{
|
{
|
||||||
|
private readonly List<int> slotIds;
|
||||||
public List<int> SlotIds;
|
|
||||||
public CustomCategory(string name, string description, string endpoint, string icon, IEnumerable<int> slotIds)
|
public CustomCategory(string name, string description, string endpoint, string icon, IEnumerable<int> slotIds)
|
||||||
{
|
{
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
|
@ -18,7 +17,7 @@ public class CustomCategory : Category
|
||||||
this.IconHash = icon;
|
this.IconHash = icon;
|
||||||
this.Endpoint = endpoint;
|
this.Endpoint = endpoint;
|
||||||
|
|
||||||
this.SlotIds = slotIds.ToList();
|
this.slotIds = slotIds.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CustomCategory(DatabaseCategoryEntity category)
|
public CustomCategory(DatabaseCategoryEntity category)
|
||||||
|
@ -28,16 +27,19 @@ public class CustomCategory : Category
|
||||||
this.IconHash = category.IconHash;
|
this.IconHash = category.IconHash;
|
||||||
this.Endpoint = category.Endpoint;
|
this.Endpoint = category.Endpoint;
|
||||||
|
|
||||||
this.SlotIds = category.SlotIds.ToList();
|
this.slotIds = category.SlotIds.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed override string Name { get; set; }
|
public sealed override string Name { get; set; }
|
||||||
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 SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.FirstOrDefault(s => s.SlotId == this.SlotIds[0] && !s.CrossControllerRequired);
|
|
||||||
public override IQueryable<SlotEntity> GetSlots
|
public override string Tag => "custom_category";
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3).Where(s => this.SlotIds.Contains(s.SlotId) && !s.CrossControllerRequired);
|
public override IQueryable<SlotEntity> GetItems(DatabaseContext database, GameTokenEntity entity, SlotQueryBuilder queryBuilder)
|
||||||
public override int GetTotalSlots(DatabaseContext database) => this.SlotIds.Count;
|
{
|
||||||
|
queryBuilder.Clone().AddFilter(new SlotIdFilter(this.slotIds));
|
||||||
|
return database.Slots.Where(queryBuilder.Build());
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,38 +1,22 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
public class HeartedCategory : CategoryWithUser
|
public class HeartedCategory : SlotCategory
|
||||||
{
|
{
|
||||||
public override string Name { get; set; } = "My Hearted Content";
|
public override string Name { get; set; } = "My Hearted Content";
|
||||||
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_levels";
|
||||||
public override SlotEntity? GetPreviewSlot(DatabaseContext database, UserEntity user) // note: developer slots act up in LBP3 when listed here, so I omitted it
|
public override string Tag => "my_hearted_levels";
|
||||||
=> database.HeartedLevels.Where(h => h.UserId == user.UserId)
|
|
||||||
.Where(h => h.Slot.Type == SlotType.User && !h.Slot.Hidden && h.Slot.GameVersion <= GameVersion.LittleBigPlanet3 && !h.Slot.CrossControllerRequired)
|
|
||||||
.OrderByDescending(h => h.HeartedLevelId)
|
|
||||||
.Include(h => h.Slot.Creator)
|
|
||||||
.Select(h => h.Slot)
|
|
||||||
.ByGameVersion(GameVersion.LittleBigPlanet3, false, false, true)
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
public override IQueryable<SlotEntity> GetSlots(DatabaseContext database, UserEntity user, int pageStart, int pageSize)
|
public override IQueryable<SlotEntity> GetItems(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder) =>
|
||||||
=> database.HeartedLevels.Where(h => h.UserId == user.UserId)
|
database.HeartedLevels.Where(h => h.UserId == token.UserId)
|
||||||
.Where(h => h.Slot.Type == SlotType.User && !h.Slot.Hidden && h.Slot.GameVersion <= GameVersion.LittleBigPlanet3 && !h.Slot.CrossControllerRequired)
|
|
||||||
.OrderByDescending(h => h.HeartedLevelId)
|
.OrderByDescending(h => h.HeartedLevelId)
|
||||||
.Include(h => h.Slot.Creator)
|
|
||||||
.Select(h => h.Slot)
|
.Select(h => h.Slot)
|
||||||
.ByGameVersion(GameVersion.LittleBigPlanet3, false, false, true)
|
.Where(queryBuilder.Build());
|
||||||
.Skip(Math.Max(0, pageStart))
|
|
||||||
.Take(Math.Min(pageSize, 20));
|
|
||||||
|
|
||||||
public override int GetTotalSlots(DatabaseContext database, UserEntity user) => database.HeartedLevels.Count(h => h.UserId == user.UserId);
|
|
||||||
}
|
}
|
|
@ -1,43 +1,27 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
public class HighestRatedCategory : Category
|
public class HighestRatedCategory : SlotCategory
|
||||||
{
|
{
|
||||||
public override string Name { get; set; } = "Highest Rated";
|
public override string Name { get; set; } = "Highest Rated";
|
||||||
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 SlotEntity? GetPreviewSlot(DatabaseContext database) =>
|
public override string Tag => "highest_rated";
|
||||||
database.Slots.Where(s => s.Type == SlotType.User && !s.CrossControllerRequired)
|
|
||||||
.Select(s => new SlotMetadata
|
|
||||||
{
|
|
||||||
Slot = s,
|
|
||||||
ThumbsUp = database.RatedLevels.Count(r => r.SlotId == s.SlotId && r.Rating == 1),
|
|
||||||
})
|
|
||||||
.OrderByDescending(s => s.ThumbsUp)
|
|
||||||
.Select(s => s.Slot)
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
public override IEnumerable<SlotEntity> GetSlots(DatabaseContext database, int pageStart, int pageSize) =>
|
public override IQueryable<SlotEntity> GetItems(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder) =>
|
||||||
database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
database.Slots.Select(s => new SlotMetadata
|
||||||
.Where(s => !s.CrossControllerRequired)
|
|
||||||
.Select(s => new SlotMetadata
|
|
||||||
{
|
{
|
||||||
Slot = s,
|
Slot = s,
|
||||||
ThumbsUp = database.RatedLevels.Count(r => r.SlotId == s.SlotId && r.Rating == 1),
|
ThumbsUp = database.RatedLevels.Count(r => r.SlotId == s.SlotId && r.Rating == 1),
|
||||||
})
|
})
|
||||||
.OrderByDescending(s => s.ThumbsUp)
|
.OrderByDescending(s => s.ThumbsUp)
|
||||||
.ThenBy(_ => EF.Functions.Random())
|
|
||||||
.Select(s => s.Slot)
|
.Select(s => s.Slot)
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
.Where(queryBuilder.Build());
|
||||||
.Take(Math.Min(pageSize, 20));
|
|
||||||
public override int GetTotalSlots(DatabaseContext database) => database.Slots.Count(s => s.Type == SlotType.User);
|
|
||||||
}
|
}
|
|
@ -1,26 +1,22 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
public class LuckyDipCategory : Category
|
public class LuckyDipCategory : SlotCategory
|
||||||
{
|
{
|
||||||
public override string Name { get; set; } = "Lucky Dip";
|
public override string Name { get; set; } = "Lucky Dip";
|
||||||
public override string Description { get; set; } = "A random selection of content";
|
public override string Description { get; set; } = "A random selection of 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; } = "lucky_dip";
|
||||||
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User && !s.CrossControllerRequired).OrderByDescending(_ => EF.Functions.Random()).FirstOrDefault();
|
public override string Tag => "lucky_dip";
|
||||||
public override IQueryable<SlotEntity> GetSlots
|
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
public override IQueryable<SlotEntity> GetItems(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder) =>
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
database.Slots.Where(queryBuilder.Build())
|
||||||
.Where(s => !s.CrossControllerRequired)
|
.ApplyOrdering(new SlotSortBuilder<SlotEntity>().AddSort(new FirstUploadedSort()));
|
||||||
.OrderByDescending(_ => EF.Functions.Random())
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 20));
|
|
||||||
public override int GetTotalSlots(DatabaseContext database) => database.Slots.Count(s => s.Type == SlotType.User);
|
|
||||||
}
|
}
|
|
@ -1,42 +1,29 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Sorts.Metadata;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Misc;
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
public class MostHeartedCategory : Category
|
public class MostHeartedCategory : SlotCategory
|
||||||
{
|
{
|
||||||
public override string Name { get; set; } = "Most Hearted";
|
public override string Name { get; set; } = "Most Hearted";
|
||||||
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; } = "most_hearted";
|
||||||
|
public override string Tag => "most_hearted";
|
||||||
|
|
||||||
public override SlotEntity? GetPreviewSlot(DatabaseContext database) =>
|
public override IQueryable<SlotEntity> GetItems(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder) =>
|
||||||
database.Slots.Where(s => s.Type == SlotType.User && !s.CrossControllerRequired)
|
database.Slots.Select(s => new SlotMetadata
|
||||||
.Select(s => new SlotMetadata
|
|
||||||
{
|
{
|
||||||
Slot = s,
|
Slot = s,
|
||||||
Hearts = database.HeartedLevels.Count(r => r.SlotId == s.SlotId),
|
Hearts = database.HeartedLevels.Count(r => r.SlotId == s.SlotId),
|
||||||
})
|
})
|
||||||
.OrderByDescending(s => s.Hearts)
|
.ApplyOrdering(new SlotSortBuilder<SlotMetadata>().AddSort(new HeartsSort()))
|
||||||
.Select(s => s.Slot)
|
.Select(s => s.Slot)
|
||||||
.FirstOrDefault();
|
.Where(queryBuilder.Build());
|
||||||
|
|
||||||
public override IEnumerable<SlotEntity> GetSlots(DatabaseContext database, int pageStart, int pageSize) =>
|
|
||||||
database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
|
||||||
.Where(s => !s.CrossControllerRequired)
|
|
||||||
.Select(s => new SlotMetadata
|
|
||||||
{
|
|
||||||
Slot = s,
|
|
||||||
Hearts = database.HeartedLevels.Count(r => r.SlotId == s.SlotId),
|
|
||||||
})
|
|
||||||
.OrderByDescending(s => s.Hearts)
|
|
||||||
.Select(s => s.Slot)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 20));
|
|
||||||
public override int GetTotalSlots(DatabaseContext database) => database.Slots.Count(s => s.Type == SlotType.User);
|
|
||||||
}
|
}
|
|
@ -1,30 +1,21 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
public class MostPlayedCategory : Category
|
public class MostPlayedCategory : SlotCategory
|
||||||
{
|
{
|
||||||
public override string Name { get; set; } = "Most Played";
|
public override string Name { get; set; } = "Most Played";
|
||||||
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; } = "most_played";
|
||||||
public override SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots
|
public override string Tag => "most_played";
|
||||||
.Where(s => s.Type == SlotType.User && !s.CrossControllerRequired)
|
|
||||||
.OrderByDescending(s => s.PlaysLBP1Unique + s.PlaysLBP2Unique + s.PlaysLBP3Unique)
|
public override IQueryable<SlotEntity> GetItems(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder) =>
|
||||||
.ThenByDescending(s => s.PlaysLBP1 + s.PlaysLBP2 + s.PlaysLBP3)
|
database.Slots.Where(queryBuilder.Build())
|
||||||
.FirstOrDefault();
|
|
||||||
public override IQueryable<SlotEntity> GetSlots
|
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
|
||||||
.Where(s => !s.CrossControllerRequired)
|
|
||||||
.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);
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 20));
|
|
||||||
public override int GetTotalSlots(DatabaseContext database) => database.Slots.Count(s => s.Type == SlotType.User);
|
|
||||||
}
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
|
public class MyHeartedCreatorsCategory : UserCategory
|
||||||
|
{
|
||||||
|
public override string Name { get; set; } = "My Hearted Creators";
|
||||||
|
public override string Description { get; set; } = "Creators you've hearted";
|
||||||
|
public override string IconHash { get; set; } = "g820612";
|
||||||
|
public override string Endpoint { get; set; } = "favourite_creators";
|
||||||
|
public override string Tag => "favourite_creators";
|
||||||
|
|
||||||
|
public override IQueryable<UserEntity> GetItems(DatabaseContext database, GameTokenEntity token) =>
|
||||||
|
database.HeartedProfiles.Where(h => h.UserId == token.UserId)
|
||||||
|
.OrderByDescending(h => h.UserId)
|
||||||
|
.Include(h => h.HeartedUser)
|
||||||
|
.Select(h => h.HeartedUser);
|
||||||
|
}
|
|
@ -1,25 +1,22 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
public class NewestLevelsCategory : Category
|
public class NewestLevelsCategory : SlotCategory
|
||||||
{
|
{
|
||||||
public override string Name { get; set; } = "Newest Levels";
|
public override string Name { get; set; } = "Newest Levels";
|
||||||
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 SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.Where(s => s.Type == SlotType.User && !s.CrossControllerRequired).OrderByDescending(s => s.FirstUploaded).FirstOrDefault();
|
public override string Tag => "newest";
|
||||||
public override IQueryable<SlotEntity> GetSlots
|
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
public override IQueryable<SlotEntity> GetItems(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder) =>
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
database.Slots.Where(queryBuilder.Build())
|
||||||
.Where(s => !s.CrossControllerRequired)
|
.ApplyOrdering(new SlotSortBuilder<SlotEntity>().AddSort(new FirstUploadedSort()));
|
||||||
.OrderByDescending(s => s.FirstUploaded)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 20));
|
|
||||||
public override int GetTotalSlots(DatabaseContext database) => database.Slots.Count(s => s.Type == SlotType.User);
|
|
||||||
}
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
|
public abstract class PlaylistCategory : Category
|
||||||
|
{
|
||||||
|
public override string[] Types { get; } = { "playlist", };
|
||||||
|
|
||||||
|
public abstract IQueryable<PlaylistEntity> GetItems(DatabaseContext database, GameTokenEntity token);
|
||||||
|
|
||||||
|
public override async Task<GameCategory> Serialize(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder, int numResults = 1)
|
||||||
|
{
|
||||||
|
List<ILbpSerializable> playlists =
|
||||||
|
(await this.GetItems(database, token).Take(numResults).ToListAsync())
|
||||||
|
.ToSerializableList<PlaylistEntity, ILbpSerializable>(GamePlaylist.CreateFromEntity);
|
||||||
|
|
||||||
|
int totalPlaylists = await this.GetItems(database, token).CountAsync();
|
||||||
|
return GameCategory.CreateFromEntity(this, new GenericSerializableList(playlists, totalPlaylists, numResults + 1));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,38 +1,22 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
public class QueueCategory : CategoryWithUser
|
public class QueueCategory : SlotCategory
|
||||||
{
|
{
|
||||||
public override string Name { get; set; } = "My Queue";
|
public override string Name { get; set; } = "My Queue";
|
||||||
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 SlotEntity? GetPreviewSlot(DatabaseContext database, UserEntity user)
|
public override string Tag => "my_queue";
|
||||||
=> database.QueuedLevels.Where(q => q.UserId == user.UserId)
|
|
||||||
.Where(q => q.Slot.Type == SlotType.User && !q.Slot.Hidden && q.Slot.GameVersion <= GameVersion.LittleBigPlanet3)
|
|
||||||
.OrderByDescending(q => q.QueuedLevelId)
|
|
||||||
.Include(q => q.Slot.Creator)
|
|
||||||
.Select(q => q.Slot)
|
|
||||||
.ByGameVersion(GameVersion.LittleBigPlanet3, false, false, true)
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
public override IQueryable<SlotEntity> GetSlots(DatabaseContext database, UserEntity user, int pageStart, int pageSize)
|
public override IQueryable<SlotEntity> GetItems(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder) =>
|
||||||
=> database.QueuedLevels.Where(q => q.UserId == user.UserId)
|
database.QueuedLevels.Where(q => q.UserId == token.UserId)
|
||||||
.Where(q => q.Slot.Type == SlotType.User && !q.Slot.Hidden && q.Slot.GameVersion <= GameVersion.LittleBigPlanet3)
|
|
||||||
.OrderByDescending(q => q.QueuedLevelId)
|
.OrderByDescending(q => q.QueuedLevelId)
|
||||||
.Include(q => q.Slot.Creator)
|
|
||||||
.Select(q => q.Slot)
|
.Select(q => q.Slot)
|
||||||
.ByGameVersion(GameVersion.LittleBigPlanet3, false, false, true)
|
.Where(queryBuilder.Build());
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 20));
|
|
||||||
|
|
||||||
public override int GetTotalSlots(DatabaseContext database, UserEntity user) => database.QueuedLevels.Count(q => q.UserId == user.UserId);
|
|
||||||
}
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
|
public abstract class SlotCategory : Category
|
||||||
|
{
|
||||||
|
public override string[] Types { get; } = { "slot", "adventure", };
|
||||||
|
|
||||||
|
public abstract IQueryable<SlotEntity> GetItems(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder);
|
||||||
|
|
||||||
|
public override async Task<GameCategory> Serialize(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder, int numResults = 1)
|
||||||
|
{
|
||||||
|
List<ILbpSerializable> slots =
|
||||||
|
(await this.GetItems(database, token, queryBuilder).Take(numResults).ToListAsync())
|
||||||
|
.ToSerializableList<SlotEntity, ILbpSerializable>(s => SlotBase.CreateFromEntity(s, token));
|
||||||
|
|
||||||
|
int totalSlots = await this.GetItems(database, token, queryBuilder).CountAsync();
|
||||||
|
return GameCategory.CreateFromEntity(this, new GenericSerializableList(slots, totalSlots, numResults+1));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,23 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
public class TeamPicksCategory : Category
|
public class TeamPicksCategory : SlotCategory
|
||||||
{
|
{
|
||||||
public override string Name { get; set; } = "Team Picks";
|
public override string Name { get; set; } = "Team Picks";
|
||||||
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 SlotEntity? GetPreviewSlot(DatabaseContext database) => database.Slots.OrderByDescending(s => s.FirstUploaded).FirstOrDefault(s => s.TeamPick && !s.CrossControllerRequired);
|
public override string Tag => "team_picks";
|
||||||
public override IQueryable<SlotEntity> GetSlots
|
|
||||||
(DatabaseContext database, int pageStart, int pageSize)
|
public override IQueryable<SlotEntity> GetItems(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder) =>
|
||||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3, false, true)
|
database.Slots.Where(queryBuilder.Clone().AddFilter(new TeamPickFilter()).Build())
|
||||||
.OrderByDescending(s => s.FirstUploaded)
|
.ApplyOrdering(new SlotSortBuilder<SlotEntity>().AddSort(new FirstUploadedSort()));
|
||||||
.Where(s => s.TeamPick && !s.CrossControllerRequired)
|
|
||||||
.Skip(Math.Max(0, pageStart - 1))
|
|
||||||
.Take(Math.Min(pageSize, 20));
|
|
||||||
public override int GetTotalSlots(DatabaseContext database) => database.Slots.Count(s => s.TeamPick);
|
|
||||||
}
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
|
||||||
|
public abstract class UserCategory : Category
|
||||||
|
{
|
||||||
|
public override string[] Types { get; } = { "user", };
|
||||||
|
|
||||||
|
public abstract IQueryable<UserEntity> GetItems(DatabaseContext database, GameTokenEntity token);
|
||||||
|
|
||||||
|
public override async Task<GameCategory> Serialize(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder, int numResults = 1)
|
||||||
|
{
|
||||||
|
List<ILbpSerializable> users =
|
||||||
|
(await this.GetItems(database, token).Take(numResults).ToListAsync())
|
||||||
|
.ToSerializableList<UserEntity, ILbpSerializable>(GameUser.CreateFromEntity);
|
||||||
|
|
||||||
|
int totalUsers = await this.GetItems(database, token).CountAsync();
|
||||||
|
return GameCategory.CreateFromEntity(this, new GenericSerializableList(users, totalUsers, numResults + 1));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Types.Categories;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Types;
|
||||||
|
|
||||||
|
public class MyPlaylistsCategory : PlaylistCategory
|
||||||
|
{
|
||||||
|
public override string Name { get; set; } = "My Playlists";
|
||||||
|
public override string Description { get; set; } = "Your playlists";
|
||||||
|
public override string IconHash { get; set; } = "g820613";
|
||||||
|
public override string Endpoint { get; set; } = "my_playlists";
|
||||||
|
public override string Tag => "my_playlists";
|
||||||
|
public override string[] Types { get; } = { "playlist", };
|
||||||
|
|
||||||
|
public override IQueryable<PlaylistEntity> GetItems(DatabaseContext database, GameTokenEntity token) =>
|
||||||
|
database.Playlists.Where(p => p.CreatorId == token.UserId).OrderByDescending(p => p.PlaylistId);
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
using LBPUnion.ProjectLighthouse.Administration.Maintenance;
|
using LBPUnion.ProjectLighthouse.Administration.Maintenance;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
using LBPUnion.ProjectLighthouse.Servers.Website.Pages.Layouts;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.Website.Types;
|
using LBPUnion.ProjectLighthouse.Servers.Website.Types;
|
||||||
|
@ -29,7 +30,7 @@ public class AdminPanelPage : BaseLayout
|
||||||
if (!user.IsAdmin) return this.NotFound();
|
if (!user.IsAdmin) return this.NotFound();
|
||||||
|
|
||||||
this.Statistics.Add(new AdminPanelStatistic("Users", await StatisticsHelper.UserCount(this.Database), "/admin/users"));
|
this.Statistics.Add(new AdminPanelStatistic("Users", await StatisticsHelper.UserCount(this.Database), "/admin/users"));
|
||||||
this.Statistics.Add(new AdminPanelStatistic("Slots", await StatisticsHelper.SlotCount(this.Database)));
|
this.Statistics.Add(new AdminPanelStatistic("Slots", await StatisticsHelper.SlotCount(this.Database, new SlotQueryBuilder())));
|
||||||
this.Statistics.Add(new AdminPanelStatistic("Photos", await StatisticsHelper.PhotoCount(this.Database)));
|
this.Statistics.Add(new AdminPanelStatistic("Photos", await StatisticsHelper.PhotoCount(this.Database)));
|
||||||
this.Statistics.Add(new AdminPanelStatistic("API Keys", await StatisticsHelper.ApiKeyCount(this.Database), "/admin/keys"));
|
this.Statistics.Add(new AdminPanelStatistic("API Keys", await StatisticsHelper.ApiKeyCount(this.Database), "/admin/keys"));
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Startup;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests.Integration;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Tests.GameApiTests.Integration;
|
||||||
|
|
||||||
|
[Trait("Category", "Integration")]
|
||||||
|
public class SlotFilterTests : LighthouseServerTest<GameServerTestStartup>
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task GetUserSlot_ShouldReturnOk_WhenSlotExists()
|
||||||
|
{
|
||||||
|
DatabaseContext db = await IntegrationHelper.GetIntegrationDatabase();
|
||||||
|
|
||||||
|
db.Users.Add(new UserEntity
|
||||||
|
{
|
||||||
|
UserId = 23,
|
||||||
|
});
|
||||||
|
|
||||||
|
db.Slots.Add(new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 23,
|
||||||
|
CreatorId = 23,
|
||||||
|
});
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
LoginResult loginResult = await this.Authenticate();
|
||||||
|
HttpResponseMessage response = await this.AuthenticatedRequest("/LITTLEBIGPLANETPS3_XML/s/user/23", loginResult.AuthTicket);
|
||||||
|
|
||||||
|
const HttpStatusCode expectedStatusCode = HttpStatusCode.OK;
|
||||||
|
|
||||||
|
Assert.Equal(expectedStatusCode, response.StatusCode);
|
||||||
|
string body = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
Assert.Contains("<id>23</id>", body);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task NewestSlots_ShouldReturnSlotsOrderedByTimestampDescending()
|
||||||
|
{
|
||||||
|
DatabaseContext db = await IntegrationHelper.GetIntegrationDatabase();
|
||||||
|
|
||||||
|
for (int i = 1; i <= 100; i++)
|
||||||
|
{
|
||||||
|
db.Users.Add(new UserEntity
|
||||||
|
{
|
||||||
|
UserId = i,
|
||||||
|
Username = $"user{i}",
|
||||||
|
});
|
||||||
|
db.Slots.Add(new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = i,
|
||||||
|
CreatorId = i,
|
||||||
|
FirstUploaded = i,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
LoginResult loginResult = await this.Authenticate();
|
||||||
|
HttpResponseMessage response =
|
||||||
|
await this.AuthenticatedRequest("/LITTLEBIGPLANETPS3_XML/slots?pageStart=0&pageSize=10", loginResult.AuthTicket);
|
||||||
|
|
||||||
|
const HttpStatusCode expectedStatusCode = HttpStatusCode.OK;
|
||||||
|
|
||||||
|
Assert.Equal(expectedStatusCode, response.StatusCode);
|
||||||
|
string body = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
object? deserialized = LighthouseSerializer
|
||||||
|
.GetSerializer(typeof(GameUserSlotList), new XmlRootAttribute("slots"))
|
||||||
|
.Deserialize(new StringReader(body));
|
||||||
|
Assert.NotNull(deserialized);
|
||||||
|
Assert.IsType<GameUserSlotList>(deserialized);
|
||||||
|
|
||||||
|
GameUserSlotList slotResponse = (GameUserSlotList)deserialized;
|
||||||
|
|
||||||
|
Assert.Equal(100, slotResponse.Total);
|
||||||
|
Assert.Equal(10, slotResponse.Slots.Count);
|
||||||
|
|
||||||
|
Assert.Equal(91, slotResponse.Slots[9].FirstUploaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task NewestSlots_ShouldReturnSlotsWithAuthorLabel()
|
||||||
|
{
|
||||||
|
DatabaseContext db = await IntegrationHelper.GetIntegrationDatabase();
|
||||||
|
|
||||||
|
db.Users.Add(new UserEntity()
|
||||||
|
{
|
||||||
|
UserId = 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
db.Slots.Add(new SlotEntity
|
||||||
|
{
|
||||||
|
CreatorId = 1,
|
||||||
|
SlotId = 1,
|
||||||
|
AuthorLabels = "LABEL_SinglePlayer,LABEL_Quick,LABEL_Funny",
|
||||||
|
FirstUploaded = 1,
|
||||||
|
});
|
||||||
|
db.Slots.Add(new SlotEntity
|
||||||
|
{
|
||||||
|
CreatorId = 1,
|
||||||
|
SlotId = 2,
|
||||||
|
AuthorLabels = "LABEL_SinglePlayer",
|
||||||
|
FirstUploaded = 2,
|
||||||
|
});
|
||||||
|
db.Slots.Add(new SlotEntity
|
||||||
|
{
|
||||||
|
CreatorId = 1,
|
||||||
|
SlotId = 3,
|
||||||
|
AuthorLabels = "LABEL_Quick",
|
||||||
|
FirstUploaded = 3,
|
||||||
|
});
|
||||||
|
db.Slots.Add(new SlotEntity
|
||||||
|
{
|
||||||
|
CreatorId = 1,
|
||||||
|
SlotId = 4,
|
||||||
|
AuthorLabels = "LABEL_Funny",
|
||||||
|
FirstUploaded = 4,
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
LoginResult loginResult = await this.Authenticate();
|
||||||
|
HttpResponseMessage response =
|
||||||
|
await this.AuthenticatedRequest("/LITTLEBIGPLANETPS3_XML/slots?pageStart=0&pageSize=10&labelFilter0=LABEL_Funny",
|
||||||
|
loginResult.AuthTicket);
|
||||||
|
|
||||||
|
const HttpStatusCode expectedStatusCode = HttpStatusCode.OK;
|
||||||
|
|
||||||
|
Assert.Equal(expectedStatusCode, response.StatusCode);
|
||||||
|
string body = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
object? deserialized = LighthouseSerializer
|
||||||
|
.GetSerializer(typeof(GameUserSlotList), new XmlRootAttribute("slots"))
|
||||||
|
.Deserialize(new StringReader(body));
|
||||||
|
Assert.NotNull(deserialized);
|
||||||
|
Assert.IsType<GameUserSlotList>(deserialized);
|
||||||
|
|
||||||
|
GameUserSlotList slotResponse = (GameUserSlotList)deserialized;
|
||||||
|
|
||||||
|
const int expectedCount = 2;
|
||||||
|
|
||||||
|
Assert.Equal(expectedCount, slotResponse.Slots.Count);
|
||||||
|
Assert.True(slotResponse.Slots.TrueForAll(s => s.AuthorLabels.Contains("LABEL_Funny")));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task NewestSlots_ShouldReturnEmpty_WhenAuthorLabelsDontMatch()
|
||||||
|
{
|
||||||
|
DatabaseContext db = await IntegrationHelper.GetIntegrationDatabase();
|
||||||
|
|
||||||
|
db.Users.Add(new UserEntity
|
||||||
|
{
|
||||||
|
UserId = 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
db.Slots.Add(new SlotEntity
|
||||||
|
{
|
||||||
|
CreatorId = 1,
|
||||||
|
SlotId = 1,
|
||||||
|
AuthorLabels = "LABEL_SinglePlayer,LABEL_Quick,LABEL_Funny",
|
||||||
|
FirstUploaded = 1,
|
||||||
|
});
|
||||||
|
db.Slots.Add(new SlotEntity
|
||||||
|
{
|
||||||
|
CreatorId = 1,
|
||||||
|
SlotId = 2,
|
||||||
|
AuthorLabels = "LABEL_SinglePlayer",
|
||||||
|
FirstUploaded = 2,
|
||||||
|
});
|
||||||
|
db.Slots.Add(new SlotEntity
|
||||||
|
{
|
||||||
|
CreatorId = 1,
|
||||||
|
SlotId = 3,
|
||||||
|
AuthorLabels = "LABEL_Quick",
|
||||||
|
FirstUploaded = 3,
|
||||||
|
});
|
||||||
|
db.Slots.Add(new SlotEntity
|
||||||
|
{
|
||||||
|
CreatorId = 1,
|
||||||
|
SlotId = 4,
|
||||||
|
AuthorLabels = "LABEL_Funny",
|
||||||
|
FirstUploaded = 4,
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
|
||||||
|
LoginResult loginResult = await this.Authenticate();
|
||||||
|
HttpResponseMessage response =
|
||||||
|
await this.AuthenticatedRequest("/LITTLEBIGPLANETPS3_XML/slots?pageStart=0&pageSize=10&labelFilter0=LABEL_Funny&labelFilter1=LABEL_Quick&labelFilter2=LABEL_Gallery",
|
||||||
|
loginResult.AuthTicket);
|
||||||
|
|
||||||
|
const HttpStatusCode expectedStatusCode = HttpStatusCode.OK;
|
||||||
|
|
||||||
|
Assert.Equal(expectedStatusCode, response.StatusCode);
|
||||||
|
string body = await response.Content.ReadAsStringAsync();
|
||||||
|
|
||||||
|
object? deserialized = LighthouseSerializer
|
||||||
|
.GetSerializer(typeof(GameUserSlotList), new XmlRootAttribute("slots"))
|
||||||
|
.Deserialize(new StringReader(body));
|
||||||
|
Assert.NotNull(deserialized);
|
||||||
|
Assert.IsType<GameUserSlotList>(deserialized);
|
||||||
|
|
||||||
|
GameUserSlotList slotResponse = (GameUserSlotList)deserialized;
|
||||||
|
|
||||||
|
Assert.Empty(slotResponse.Slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
[XmlRoot("slots")]
|
||||||
|
public class GameUserSlotList
|
||||||
|
{
|
||||||
|
[XmlElement("slot")]
|
||||||
|
public List<GameUserSlot> Slots { get; set; } = new();
|
||||||
|
|
||||||
|
[XmlAttribute("total")]
|
||||||
|
public int Total { get; set; }
|
||||||
|
|
||||||
|
[XmlAttribute("hint_start")]
|
||||||
|
public int HintStart { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,388 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Tests.GameApiTests.Unit.Controllers;
|
||||||
|
|
||||||
|
[Trait("Category", "Unit")]
|
||||||
|
public class ControllerExtensionTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void GetDefaultFilters_ShouldReturnFilterBuilder()
|
||||||
|
{
|
||||||
|
SlotQueryBuilder queryBuilder = new SlotsController(null!).GetDefaultFilters(MockHelper.GetUnitTestToken());
|
||||||
|
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(GameVersionFilter)));
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(SubLevelFilter)));
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(HiddenSlotFilter)));
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(SlotTypeFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddExcludeLbp1Filter_WhenTokenNotLbp1()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet2;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(ExcludeLBP1OnlyFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldReturnFilters_WhenQueryEmpty()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet2;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(GameVersionFilter)));
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(ExcludeLBP1OnlyFilter)));
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(SubLevelFilter)));
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(HiddenSlotFilter)));
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(SlotTypeFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<ISlotFilter> GetDefaultFilters
|
||||||
|
(SlotQueryBuilder queryBuilder) =>
|
||||||
|
queryBuilder.GetFilters(typeof(GameVersionFilter))
|
||||||
|
.Union(queryBuilder.GetFilters(typeof(SubLevelFilter))
|
||||||
|
.Union(queryBuilder.GetFilters(typeof(HiddenSlotFilter))
|
||||||
|
.Union(queryBuilder.GetFilters(typeof(SlotTypeFilter)))))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddLabelFilter_WhenAuthorLabelPresent()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet2;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?labelFilter0=LABEL_TEST"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(AuthorLabelFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddPlayerCountFilter_WhenPlayersPresent()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet2;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?players=1"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(PlayerCountFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddTextFilter_WhenTextFilterPresent()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet2;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?textFilter=test"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(TextFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddFirstUploadedFilter_WhenDateFilterPresent()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet2;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?dateFilterType=thisWeek"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(FirstUploadedFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddExcludeMoveFilter_WhenMoveEqualsFalse()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet2;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?move=false"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(ExcludeMovePackFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddMoveFilter_WhenMoveEqualsOnly()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet2;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?move=only"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(MovePackFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddCrossControlFilter_WhenCrossControlEqualsTrue()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet2;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?crosscontrol=true"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(CrossControlFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddAdventureFilter_WhenAdventureEqualsAllMust()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet3;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?adventure=allMust"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(AdventureFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddExcludeAdventureFilter_WhenAdventureEqualsNoneCan()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet3;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?adventure=noneCan"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(ExcludeAdventureFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddMovePackFilter_WhenMoveEqualsAllMust()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet3;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?move=allMust"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(MovePackFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddExcludeMoveFilter_WhenMoveEqualsNoneCan()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet3;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?move=noneCan"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(ExcludeMovePackFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddGameVersionListFilter_WhenGameFilterIsPresent()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet3;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?gameFilter[]=lbp1&gameFilter[]=lbp3"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(GameVersionListFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FilterFromRequest_ShouldAddResultTypeFilter_WhenResultTypeIsPresent()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet3;
|
||||||
|
SlotsController controller = new(null!)
|
||||||
|
{
|
||||||
|
ControllerContext =
|
||||||
|
{
|
||||||
|
HttpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
QueryString = new QueryString("?resultType[]=slot&resultType[]=playlist"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
|
||||||
|
Assert.NotEmpty(queryBuilder.GetFilters(typeof(ResultTypeFilter)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,11 +41,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\n";
|
||||||
|
|
||||||
IActionResult result = messageController.Eula();
|
IActionResult result = messageController.Eula();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string eulaMsg = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? okObjectResult = result as OkObjectResult;
|
Assert.Equal(expected, eulaMsg);
|
||||||
Assert.NotNull(okObjectResult);
|
|
||||||
Assert.NotNull(okObjectResult.Value);
|
|
||||||
Assert.Equal(expected, (string)okObjectResult.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -72,11 +69,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\nuni
|
||||||
|
|
||||||
IActionResult result = messageController.Eula();
|
IActionResult result = messageController.Eula();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string eulaMsg = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? okObjectResult = result as OkObjectResult;
|
Assert.Equal(expected, eulaMsg);
|
||||||
Assert.NotNull(okObjectResult);
|
|
||||||
Assert.NotNull(okObjectResult.Value);
|
|
||||||
Assert.Equal(expected, (string)okObjectResult.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -92,11 +86,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\nuni
|
||||||
|
|
||||||
IActionResult result = await messageController.Announce();
|
IActionResult result = await messageController.Announce();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string announceMsg = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? okObjectResult = result as OkObjectResult;
|
Assert.Equal(expected, announceMsg);
|
||||||
Assert.NotNull(okObjectResult);
|
|
||||||
Assert.NotNull(okObjectResult.Value);
|
|
||||||
Assert.Equal(expected, (string)okObjectResult.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -112,11 +103,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\nuni
|
||||||
|
|
||||||
IActionResult result = await messageController.Announce();
|
IActionResult result = await messageController.Announce();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string announceMsg = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? okObjectResult = result as OkObjectResult;
|
Assert.Equal(expected, announceMsg);
|
||||||
Assert.NotNull(okObjectResult);
|
|
||||||
Assert.NotNull(okObjectResult.Value);
|
|
||||||
Assert.Equal(expected, (string)okObjectResult.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -147,11 +135,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\nuni
|
||||||
|
|
||||||
IActionResult result = await messageController.Filter(new NullMailService());
|
IActionResult result = await messageController.Filter(new NullMailService());
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string filteredMessage = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? okObjectResult = result as OkObjectResult;
|
Assert.Equal(expectedBody, filteredMessage);
|
||||||
Assert.NotNull(okObjectResult);
|
|
||||||
Assert.NotNull(okObjectResult.Value);
|
|
||||||
Assert.Equal(expectedBody, (string)okObjectResult.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
@ -173,11 +158,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\nuni
|
||||||
|
|
||||||
IActionResult result = await messageController.Filter(new NullMailService());
|
IActionResult result = await messageController.Filter(new NullMailService());
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string filteredMessage = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? okObjectResult = result as OkObjectResult;
|
Assert.Equal(expectedBody, filteredMessage);
|
||||||
Assert.NotNull(okObjectResult);
|
|
||||||
Assert.NotNull(okObjectResult.Value);
|
|
||||||
Assert.Equal(expectedBody, (string)okObjectResult.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Mock<IMailService> getMailServiceMock()
|
private static Mock<IMailService> getMailServiceMock()
|
||||||
|
@ -189,7 +171,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\nuni
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Filter_ShouldNotSendEmail_WhenMailDisabled()
|
public async Task Filter_ShouldNotSendEmail_WhenMailDisabled()
|
||||||
{
|
{
|
||||||
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
||||||
Mock<IMailService> mailMock = getMailServiceMock();
|
Mock<IMailService> mailMock = getMailServiceMock();
|
||||||
|
@ -200,20 +182,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\nuni
|
||||||
ServerConfiguration.Instance.Mail.MailEnabled = false;
|
ServerConfiguration.Instance.Mail.MailEnabled = false;
|
||||||
CensorConfiguration.Instance.FilteredWordList = new List<string>();
|
CensorConfiguration.Instance.FilteredWordList = new List<string>();
|
||||||
|
|
||||||
const int expectedStatus = 200;
|
|
||||||
const string expected = "/setemail unittest@unittest.com";
|
const string expected = "/setemail unittest@unittest.com";
|
||||||
|
|
||||||
IActionResult result = await messageController.Filter(mailMock.Object);
|
IActionResult result = await messageController.Filter(mailMock.Object);
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string filteredMessage = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? okObjectResult = result as OkObjectResult;
|
Assert.Equal(expected, filteredMessage);
|
||||||
Assert.NotNull(okObjectResult);
|
|
||||||
Assert.Equal(expectedStatus, okObjectResult.StatusCode);
|
|
||||||
Assert.Equal(expected, okObjectResult.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Filter_ShouldSendEmail_WhenMailEnabled_AndEmailNotTaken()
|
public async Task Filter_ShouldSendEmail_WhenMailEnabled_AndEmailNotTaken()
|
||||||
{
|
{
|
||||||
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
||||||
|
|
||||||
|
@ -236,7 +214,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\nuni
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Filter_ShouldNotSendEmail_WhenMailEnabled_AndEmailTaken()
|
public async Task Filter_ShouldNotSendEmail_WhenMailEnabled_AndEmailTaken()
|
||||||
{
|
{
|
||||||
List<UserEntity> users = new()
|
List<UserEntity> users = new()
|
||||||
{
|
{
|
||||||
|
@ -265,7 +243,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\nuni
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Filter_ShouldNotSendEmail_WhenMailEnabled_AndEmailAlreadyVerified()
|
public async Task Filter_ShouldNotSendEmail_WhenMailEnabled_AndEmailAlreadyVerified()
|
||||||
{
|
{
|
||||||
UserEntity unitTestUser = MockHelper.GetUnitTestUser();
|
UserEntity unitTestUser = MockHelper.GetUnitTestUser();
|
||||||
unitTestUser.EmailAddressVerified = true;
|
unitTestUser.EmailAddressVerified = true;
|
||||||
|
@ -290,7 +268,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>." + "\nuni
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void Filter_ShouldNotSendEmail_WhenMailEnabled_AndEmailFormatInvalid()
|
public async Task Filter_ShouldNotSendEmail_WhenMailEnabled_AndEmailFormatInvalid()
|
||||||
{
|
{
|
||||||
UserEntity unitTestUser = MockHelper.GetUnitTestUser();
|
UserEntity unitTestUser = MockHelper.GetUnitTestUser();
|
||||||
unitTestUser.EmailAddressVerified = true;
|
unitTestUser.EmailAddressVerified = true;
|
||||||
|
|
|
@ -0,0 +1,380 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
||||||
|
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace ProjectLighthouse.Tests.GameApiTests.Unit.Controllers;
|
||||||
|
|
||||||
|
[Trait("Category", "Unit")]
|
||||||
|
public class SlotControllerTests
|
||||||
|
{
|
||||||
|
#region SlotsBy
|
||||||
|
[Fact]
|
||||||
|
public async Task SlotsBy_ShouldReturnNotFound_WhenUserInvalid()
|
||||||
|
{
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase();
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.SlotsBy("bytest");
|
||||||
|
|
||||||
|
Assert.IsType<NotFoundResult>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SlotsBy_ShouldFetchLevelsByUser()
|
||||||
|
{
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 1,
|
||||||
|
CreatorId = 2,
|
||||||
|
},
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 2,
|
||||||
|
CreatorId = 2,
|
||||||
|
},
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 3,
|
||||||
|
CreatorId = 3,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
List<UserEntity> users = new()
|
||||||
|
{
|
||||||
|
MockHelper.GetUnitTestUser(),
|
||||||
|
new UserEntity
|
||||||
|
{
|
||||||
|
Username = "bytest",
|
||||||
|
UserId = 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new IList[]
|
||||||
|
{
|
||||||
|
slots, users,
|
||||||
|
});
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.SlotsBy("bytest");
|
||||||
|
|
||||||
|
const int expectedElements = 2;
|
||||||
|
|
||||||
|
GenericSlotResponse slotResponse = result.CastTo<OkObjectResult, GenericSlotResponse>();
|
||||||
|
Assert.Equal(expectedElements, slotResponse.Slots.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task SlotsBy_ResultsAreOrderedByFirstUploadedTimestampDescending()
|
||||||
|
{
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 1,
|
||||||
|
CreatorId = 2,
|
||||||
|
FirstUploaded = 3,
|
||||||
|
},
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 2,
|
||||||
|
CreatorId = 2,
|
||||||
|
FirstUploaded = 1,
|
||||||
|
},
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 3,
|
||||||
|
CreatorId = 2,
|
||||||
|
FirstUploaded = 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
List<UserEntity> users = new()
|
||||||
|
{
|
||||||
|
MockHelper.GetUnitTestUser(),
|
||||||
|
new UserEntity
|
||||||
|
{
|
||||||
|
Username = "bytest",
|
||||||
|
UserId = 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new IList[]
|
||||||
|
{
|
||||||
|
slots, users,
|
||||||
|
});
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.SlotsBy("bytest");
|
||||||
|
|
||||||
|
const int expectedElements = 3;
|
||||||
|
const int expectedFirstSlotId = 1;
|
||||||
|
const int expectedSecondSlotId = 3;
|
||||||
|
const int expectedThirdSlotId = 2;
|
||||||
|
|
||||||
|
GenericSlotResponse slotResponse = result.CastTo<OkObjectResult, GenericSlotResponse>();
|
||||||
|
Assert.Equal(expectedElements, slotResponse.Slots.Count);
|
||||||
|
|
||||||
|
Assert.Equal(expectedFirstSlotId, ((GameUserSlot)slotResponse.Slots[0]).SlotId);
|
||||||
|
Assert.Equal(expectedSecondSlotId, ((GameUserSlot)slotResponse.Slots[1]).SlotId);
|
||||||
|
Assert.Equal(expectedThirdSlotId, ((GameUserSlot)slotResponse.Slots[2]).SlotId);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region UserSlot
|
||||||
|
[Fact]
|
||||||
|
public async Task UserSlot_ShouldFetch_WhenSlotIsValid()
|
||||||
|
{
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new[]
|
||||||
|
{
|
||||||
|
slots,
|
||||||
|
});
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.UserSlot(2);
|
||||||
|
|
||||||
|
Assert.IsType<OkObjectResult>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UserSlot_ShouldNotFetch_WhenGameVersionMismatch()
|
||||||
|
{
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 2,
|
||||||
|
GameVersion = GameVersion.LittleBigPlanet2,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new[]
|
||||||
|
{
|
||||||
|
slots,
|
||||||
|
});
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.UserSlot(2);
|
||||||
|
|
||||||
|
Assert.IsType<NotFoundResult>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UserSlot_ShouldFetch_WhenGameVersionEqual()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanetVita;
|
||||||
|
List<GameTokenEntity> tokens = new()
|
||||||
|
{
|
||||||
|
token,
|
||||||
|
};
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 2,
|
||||||
|
GameVersion = GameVersion.LittleBigPlanetVita,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new IList[]
|
||||||
|
{
|
||||||
|
slots, tokens,
|
||||||
|
});
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController(token);
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.UserSlot(2);
|
||||||
|
|
||||||
|
Assert.IsType<OkObjectResult>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UserSlot_ShouldFetch_WhenGameVersionIsGreater()
|
||||||
|
{
|
||||||
|
GameTokenEntity token = MockHelper.GetUnitTestToken();
|
||||||
|
token.GameVersion = GameVersion.LittleBigPlanet3;
|
||||||
|
List<GameTokenEntity> tokens = new()
|
||||||
|
{
|
||||||
|
token,
|
||||||
|
};
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 2,
|
||||||
|
GameVersion = GameVersion.LittleBigPlanet1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new IList[]
|
||||||
|
{
|
||||||
|
slots, tokens,
|
||||||
|
});
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController(token);
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.UserSlot(2);
|
||||||
|
|
||||||
|
Assert.IsType<OkObjectResult>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UserSlot_ShouldReturnNotFound_WhenSlotDoesNotExist()
|
||||||
|
{
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase();
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.UserSlot(20);
|
||||||
|
|
||||||
|
Assert.IsType<NotFoundResult>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UserSlot_ShouldFetch_WhenSlotIsNotSubLevel()
|
||||||
|
{
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 27,
|
||||||
|
CreatorId = 4,
|
||||||
|
SubLevel = false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new[]
|
||||||
|
{
|
||||||
|
slots,
|
||||||
|
});
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.UserSlot(27);
|
||||||
|
|
||||||
|
Assert.IsType<OkObjectResult>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UserSlot_ShouldNotFetch_WhenSlotIsHidden()
|
||||||
|
{
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 27,
|
||||||
|
CreatorId = 4,
|
||||||
|
Hidden = true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new[]
|
||||||
|
{
|
||||||
|
slots,
|
||||||
|
});
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.UserSlot(27);
|
||||||
|
|
||||||
|
Assert.IsType<NotFoundResult>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UserSlot_ShouldNotFetch_WhenSlotIsWrongType()
|
||||||
|
{
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 27,
|
||||||
|
Type = SlotType.Developer,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new[]
|
||||||
|
{
|
||||||
|
slots,
|
||||||
|
});
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.UserSlot(27);
|
||||||
|
|
||||||
|
Assert.IsType<NotFoundResult>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task UserSlot_ShouldNotFetch_WhenSlotIsSubLevel()
|
||||||
|
{
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 27,
|
||||||
|
CreatorId = 4,
|
||||||
|
SubLevel = true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new []{slots,});
|
||||||
|
SlotsController slotsController = new(db);
|
||||||
|
slotsController.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await slotsController.UserSlot(27);
|
||||||
|
|
||||||
|
Assert.IsType<NotFoundResult>(result);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region DeveloperSlot
|
||||||
|
[Fact]
|
||||||
|
public async Task DeveloperSlot_ShouldFetch_WhenSlotIdIsValid()
|
||||||
|
{
|
||||||
|
List<SlotEntity> slots = new()
|
||||||
|
{
|
||||||
|
new SlotEntity
|
||||||
|
{
|
||||||
|
SlotId = 1,
|
||||||
|
InternalSlotId = 25,
|
||||||
|
Type = SlotType.Developer,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase(new[]
|
||||||
|
{
|
||||||
|
slots,
|
||||||
|
});
|
||||||
|
SlotsController controller = new(db);
|
||||||
|
controller.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await controller.DeveloperSlot(25);
|
||||||
|
Assert.IsType<OkObjectResult>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DeveloperSlot_ShouldFetch_WhenSlotIdIsInvalid()
|
||||||
|
{
|
||||||
|
DatabaseContext db = await MockHelper.GetTestDatabase();
|
||||||
|
SlotsController controller = new(db);
|
||||||
|
controller.SetupTestController();
|
||||||
|
|
||||||
|
IActionResult result = await controller.DeveloperSlot(26);
|
||||||
|
Assert.IsType<OkObjectResult>(result);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
|
@ -14,7 +15,7 @@ namespace ProjectLighthouse.Tests.GameApiTests.Unit.Controllers;
|
||||||
public class StatisticsControllerTests
|
public class StatisticsControllerTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void PlanetStats_ShouldReturnCorrectCounts_WhenEmpty()
|
public async Task PlanetStats_ShouldReturnCorrectCounts_WhenEmpty()
|
||||||
{
|
{
|
||||||
await using DatabaseContext db = await MockHelper.GetTestDatabase();
|
await using DatabaseContext db = await MockHelper.GetTestDatabase();
|
||||||
|
|
||||||
|
@ -26,17 +27,13 @@ public class StatisticsControllerTests
|
||||||
|
|
||||||
IActionResult result = await statsController.PlanetStats();
|
IActionResult result = await statsController.PlanetStats();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
PlanetStatsResponse statsResponse = result.CastTo<OkObjectResult, PlanetStatsResponse>();
|
||||||
OkObjectResult? objectResult = result as OkObjectResult;
|
Assert.Equal(expectedSlots, statsResponse.TotalSlotCount);
|
||||||
Assert.NotNull(objectResult);
|
Assert.Equal(expectedTeamPicks, statsResponse.TeamPickCount);
|
||||||
PlanetStatsResponse? response = objectResult.Value as PlanetStatsResponse;
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(expectedSlots, response.TotalSlotCount);
|
|
||||||
Assert.Equal(expectedTeamPicks, response.TeamPickCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void PlanetStats_ShouldReturnCorrectCounts_WhenNotEmpty()
|
public async Task PlanetStats_ShouldReturnCorrectCounts_WhenNotEmpty()
|
||||||
{
|
{
|
||||||
List<SlotEntity> slots = new()
|
List<SlotEntity> slots = new()
|
||||||
{
|
{
|
||||||
|
@ -64,17 +61,13 @@ public class StatisticsControllerTests
|
||||||
|
|
||||||
IActionResult result = await statsController.PlanetStats();
|
IActionResult result = await statsController.PlanetStats();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
PlanetStatsResponse statsResponse = result.CastTo<OkObjectResult, PlanetStatsResponse>();
|
||||||
OkObjectResult? objectResult = result as OkObjectResult;
|
Assert.Equal(expectedSlots, statsResponse.TotalSlotCount);
|
||||||
Assert.NotNull(objectResult);
|
Assert.Equal(expectedTeamPicks, statsResponse.TeamPickCount);
|
||||||
PlanetStatsResponse? response = objectResult.Value as PlanetStatsResponse;
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(expectedSlots, response.TotalSlotCount);
|
|
||||||
Assert.Equal(expectedTeamPicks, response.TeamPickCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void PlanetStats_ShouldReturnCorrectCounts_WhenSlotsAreIncompatibleGameVersion()
|
public async Task PlanetStats_ShouldReturnCorrectCounts_WhenSlotsAreIncompatibleGameVersion()
|
||||||
{
|
{
|
||||||
List<SlotEntity> slots = new()
|
List<SlotEntity> slots = new()
|
||||||
{
|
{
|
||||||
|
@ -105,17 +98,13 @@ public class StatisticsControllerTests
|
||||||
|
|
||||||
IActionResult result = await statsController.PlanetStats();
|
IActionResult result = await statsController.PlanetStats();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
PlanetStatsResponse statsResponse = result.CastTo<OkObjectResult, PlanetStatsResponse>();
|
||||||
OkObjectResult? objectResult = result as OkObjectResult;
|
Assert.Equal(expectedSlots, statsResponse.TotalSlotCount);
|
||||||
Assert.NotNull(objectResult);
|
Assert.Equal(expectedTeamPicks, statsResponse.TeamPickCount);
|
||||||
PlanetStatsResponse? response = objectResult.Value as PlanetStatsResponse;
|
|
||||||
Assert.NotNull(response);
|
|
||||||
Assert.Equal(expectedSlots, response.TotalSlotCount);
|
|
||||||
Assert.Equal(expectedTeamPicks, response.TeamPickCount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void TotalLevelCount_ShouldReturnCorrectCount_WhenSlotsAreCompatible()
|
public async Task TotalLevelCount_ShouldReturnCorrectCount_WhenSlotsAreCompatible()
|
||||||
{
|
{
|
||||||
List<SlotEntity> slots = new()
|
List<SlotEntity> slots = new()
|
||||||
{
|
{
|
||||||
|
@ -145,14 +134,12 @@ public class StatisticsControllerTests
|
||||||
|
|
||||||
IActionResult result = await statsController.TotalLevelCount();
|
IActionResult result = await statsController.TotalLevelCount();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string totalSlotsResponse = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? objectResult = result as OkObjectResult;
|
Assert.Equal(expectedTotal, totalSlotsResponse);
|
||||||
Assert.NotNull(objectResult);
|
|
||||||
Assert.Equal(expectedTotal, objectResult.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void TotalLevelCount_ShouldReturnCorrectCount_WhenSlotsAreNotCompatible()
|
public async Task TotalLevelCount_ShouldReturnCorrectCount_WhenSlotsAreNotCompatible()
|
||||||
{
|
{
|
||||||
List<SlotEntity> slots = new()
|
List<SlotEntity> slots = new()
|
||||||
{
|
{
|
||||||
|
@ -178,15 +165,11 @@ public class StatisticsControllerTests
|
||||||
StatisticsController statsController = new(dbMock);
|
StatisticsController statsController = new(dbMock);
|
||||||
statsController.SetupTestController();
|
statsController.SetupTestController();
|
||||||
|
|
||||||
const int expectedStatusCode = 200;
|
|
||||||
const string expectedTotal = "0";
|
const string expectedTotal = "0";
|
||||||
|
|
||||||
IActionResult result = await statsController.TotalLevelCount();
|
IActionResult result = await statsController.TotalLevelCount();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string totalSlots = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? objectResult = result as OkObjectResult;
|
Assert.Equal(expectedTotal, totalSlots);
|
||||||
Assert.NotNull(objectResult);
|
|
||||||
Assert.Equal(expectedStatusCode, objectResult.StatusCode);
|
|
||||||
Assert.Equal(expectedTotal, objectResult.Value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
using LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
|
||||||
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
using LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
|
@ -14,7 +15,7 @@ namespace ProjectLighthouse.Tests.GameApiTests.Unit.Controllers;
|
||||||
public class UserControllerTests
|
public class UserControllerTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void GetUser_WithValidUser_ShouldReturnUser()
|
public async Task GetUser_WithValidUser_ShouldReturnUser()
|
||||||
{
|
{
|
||||||
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
||||||
|
|
||||||
|
@ -25,16 +26,12 @@ public class UserControllerTests
|
||||||
|
|
||||||
IActionResult result = await userController.GetUser("unittest");
|
IActionResult result = await userController.GetUser("unittest");
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
GameUser gameUser = result.CastTo<OkObjectResult, GameUser>();
|
||||||
OkObjectResult? okObject = result as OkObjectResult;
|
|
||||||
Assert.NotNull(okObject);
|
|
||||||
GameUser? gameUser = okObject.Value as GameUser;
|
|
||||||
Assert.NotNull(gameUser);
|
|
||||||
Assert.Equal(expectedId, gameUser.UserId);
|
Assert.Equal(expectedId, gameUser.UserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void GetUser_WithInvalidUser_ShouldReturnNotFound()
|
public async Task GetUser_WithInvalidUser_ShouldReturnNotFound()
|
||||||
{
|
{
|
||||||
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
||||||
|
|
||||||
|
@ -47,7 +44,7 @@ public class UserControllerTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void GetUserAlt_WithInvalidUser_ShouldReturnEmptyList()
|
public async Task GetUserAlt_WithInvalidUser_ShouldReturnEmptyList()
|
||||||
{
|
{
|
||||||
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
||||||
|
|
||||||
|
@ -56,16 +53,12 @@ public class UserControllerTests
|
||||||
|
|
||||||
IActionResult result = await userController.GetUserAlt(new[]{"notfound",});
|
IActionResult result = await userController.GetUserAlt(new[]{"notfound",});
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
MinimalUserListResponse userList = result.CastTo<OkObjectResult, MinimalUserListResponse>();
|
||||||
OkObjectResult? okObject = result as OkObjectResult;
|
Assert.Empty(userList.Users);
|
||||||
Assert.NotNull(okObject);
|
|
||||||
MinimalUserListResponse? userList = okObject.Value as MinimalUserListResponse? ?? default;
|
|
||||||
Assert.NotNull(userList);
|
|
||||||
Assert.Empty(userList.Value.Users);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void GetUserAlt_WithOnlyInvalidUsers_ShouldReturnEmptyList()
|
public async Task GetUserAlt_WithOnlyInvalidUsers_ShouldReturnEmptyList()
|
||||||
{
|
{
|
||||||
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
||||||
|
|
||||||
|
@ -77,16 +70,12 @@ public class UserControllerTests
|
||||||
"notfound", "notfound2", "notfound3",
|
"notfound", "notfound2", "notfound3",
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
MinimalUserListResponse userList = result.CastTo<OkObjectResult, MinimalUserListResponse>();
|
||||||
OkObjectResult? okObject = result as OkObjectResult;
|
Assert.Empty(userList.Users);
|
||||||
Assert.NotNull(okObject);
|
|
||||||
MinimalUserListResponse? userList = okObject.Value as MinimalUserListResponse? ?? default;
|
|
||||||
Assert.NotNull(userList);
|
|
||||||
Assert.Empty(userList.Value.Users);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void GetUserAlt_WithTwoInvalidUsers_AndOneValidUser_ShouldReturnOne()
|
public async Task GetUserAlt_WithTwoInvalidUsers_AndOneValidUser_ShouldReturnOne()
|
||||||
{
|
{
|
||||||
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
||||||
|
|
||||||
|
@ -99,16 +88,12 @@ public class UserControllerTests
|
||||||
"notfound", "unittest", "notfound3",
|
"notfound", "unittest", "notfound3",
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
MinimalUserListResponse userList = result.CastTo<OkObjectResult, MinimalUserListResponse>();
|
||||||
OkObjectResult? okObject = result as OkObjectResult;
|
Assert.Single(userList.Users);
|
||||||
Assert.NotNull(okObject);
|
|
||||||
MinimalUserListResponse? userList = okObject.Value as MinimalUserListResponse? ?? default;
|
|
||||||
Assert.NotNull(userList);
|
|
||||||
Assert.Single(userList.Value.Users);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void GetUserAlt_WithTwoValidUsers_ShouldReturnTwo()
|
public async Task GetUserAlt_WithTwoValidUsers_ShouldReturnTwo()
|
||||||
{
|
{
|
||||||
List<UserEntity> users = new()
|
List<UserEntity> users = new()
|
||||||
{
|
{
|
||||||
|
@ -132,16 +117,12 @@ public class UserControllerTests
|
||||||
"unittest2", "unittest",
|
"unittest2", "unittest",
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
MinimalUserListResponse userList = result.CastTo<OkObjectResult, MinimalUserListResponse>();
|
||||||
OkObjectResult? okObject = result as OkObjectResult;
|
Assert.Equal(expectedLength, userList.Users.Count);
|
||||||
Assert.NotNull(okObject);
|
|
||||||
MinimalUserListResponse? userList = okObject.Value as MinimalUserListResponse? ?? default;
|
|
||||||
Assert.NotNull(userList);
|
|
||||||
Assert.Equal(expectedLength, userList.Value.Users.Count);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void UpdateMyPins_ShouldReturnBadRequest_WhenBodyIsInvalid()
|
public async Task UpdateMyPins_ShouldReturnBadRequest_WhenBodyIsInvalid()
|
||||||
{
|
{
|
||||||
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
||||||
|
|
||||||
|
@ -155,7 +136,7 @@ public class UserControllerTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void UpdateMyPins_ShouldUpdatePins()
|
public async Task UpdateMyPins_ShouldUpdatePins()
|
||||||
{
|
{
|
||||||
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
await using DatabaseContext dbMock = await MockHelper.GetTestDatabase();
|
||||||
|
|
||||||
|
@ -167,15 +148,13 @@ public class UserControllerTests
|
||||||
|
|
||||||
IActionResult result = await userController.UpdateMyPins();
|
IActionResult result = await userController.UpdateMyPins();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string pinsResponse = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? okObject = result as OkObjectResult;
|
|
||||||
Assert.NotNull(okObject);
|
|
||||||
Assert.Equal(expectedPins, dbMock.Users.First().Pins);
|
Assert.Equal(expectedPins, dbMock.Users.First().Pins);
|
||||||
Assert.Equal(expectedResponse, okObject.Value);
|
Assert.Equal(expectedResponse, pinsResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void UpdateMyPins_ShouldNotSave_WhenPinsAreEqual()
|
public async Task UpdateMyPins_ShouldNotSave_WhenPinsAreEqual()
|
||||||
{
|
{
|
||||||
UserEntity entity = MockHelper.GetUnitTestUser();
|
UserEntity entity = MockHelper.GetUnitTestUser();
|
||||||
entity.Pins = "1234";
|
entity.Pins = "1234";
|
||||||
|
@ -193,10 +172,9 @@ public class UserControllerTests
|
||||||
|
|
||||||
IActionResult result = await userController.UpdateMyPins();
|
IActionResult result = await userController.UpdateMyPins();
|
||||||
|
|
||||||
Assert.IsType<OkObjectResult>(result);
|
string pinsResponse = result.CastTo<OkObjectResult, string>();
|
||||||
OkObjectResult? okObject = result as OkObjectResult;
|
|
||||||
Assert.NotNull(okObject);
|
|
||||||
Assert.Equal(expectedPins, dbMock.Users.First().Pins);
|
Assert.Equal(expectedPins, dbMock.Users.First().Pins);
|
||||||
Assert.Equal(expectedResponse, okObject.Value);
|
Assert.Equal(expectedResponse, pinsResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,7 +16,7 @@ public class DigestMiddlewareTests
|
||||||
{
|
{
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldNotComputeDigests_WhenDigestsDisabled()
|
public async Task DigestMiddleware_ShouldNotComputeDigests_WhenDigestsDisabled()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,7 @@ public class DigestMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldReject_WhenDigestHeaderIsMissing()
|
public async Task DigestMiddleware_ShouldReject_WhenDigestHeaderIsMissing()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -77,7 +77,7 @@ public class DigestMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldReject_WhenRequestDigestInvalid()
|
public async Task DigestMiddleware_ShouldReject_WhenRequestDigestInvalid()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -112,7 +112,7 @@ public class DigestMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldUseAlternateDigest_WhenPrimaryDigestInvalid()
|
public async Task DigestMiddleware_ShouldUseAlternateDigest_WhenPrimaryDigestInvalid()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -150,8 +150,8 @@ public class DigestMiddlewareTests
|
||||||
Assert.Equal(expectedClientDigest, context.Response.Headers["X-Digest-B"][0]);
|
Assert.Equal(expectedClientDigest, context.Response.Headers["X-Digest-B"][0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldNotReject_WhenRequestingAnnounce()
|
public async Task DigestMiddleware_ShouldNotReject_WhenRequestingAnnounce()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -188,7 +188,7 @@ public class DigestMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldCalculate_WhenAuthCookieEmpty()
|
public async Task DigestMiddleware_ShouldCalculate_WhenAuthCookieEmpty()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -225,7 +225,7 @@ public class DigestMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldComputeDigestsWithNoBody_WhenDigestsEnabled()
|
public async Task DigestMiddleware_ShouldComputeDigestsWithNoBody_WhenDigestsEnabled()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -263,7 +263,7 @@ public class DigestMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldComputeDigestsWithBody_WhenDigestsEnabled_AndNoResponseBody()
|
public async Task DigestMiddleware_ShouldComputeDigestsWithBody_WhenDigestsEnabled_AndNoResponseBody()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -301,7 +301,7 @@ public class DigestMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldComputeDigestsWithBody_WhenDigestsEnabled_AndResponseBody()
|
public async Task DigestMiddleware_ShouldComputeDigestsWithBody_WhenDigestsEnabled_AndResponseBody()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -339,7 +339,7 @@ public class DigestMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldComputeDigestsWithBody_WhenUploading()
|
public async Task DigestMiddleware_ShouldComputeDigestsWithBody_WhenUploading()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -377,7 +377,7 @@ public class DigestMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void DigestMiddleware_ShouldCompressResponse_WhenAcceptEncodingHeaderIsPresent()
|
public async Task DigestMiddleware_ShouldCompressResponse_WhenAcceptEncodingHeaderIsPresent()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,9 +17,8 @@ namespace ProjectLighthouse.Tests.GameApiTests.Unit.Middlewares;
|
||||||
[Trait("Category", "Unit")]
|
[Trait("Category", "Unit")]
|
||||||
public class SetLastContactMiddlewareTests
|
public class SetLastContactMiddlewareTests
|
||||||
{
|
{
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void SetLastContact_ShouldAddLastContact_WhenTokenIsLBP1()
|
public async Task SetLastContact_ShouldAddLastContact_WhenTokenIsLBP1()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -56,7 +55,7 @@ public class SetLastContactMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void SetLastContact_ShouldUpdateLastContact_WhenTokenIsLBP1()
|
public async Task SetLastContact_ShouldUpdateLastContact_WhenTokenIsLBP1()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -106,7 +105,7 @@ public class SetLastContactMiddlewareTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void SetLastContact_ShouldNotAddLastContact_WhenTokenIsNotLBP1()
|
public async Task SetLastContact_ShouldNotAddLastContact_WhenTokenIsNotLBP1()
|
||||||
{
|
{
|
||||||
DefaultHttpContext context = new()
|
DefaultHttpContext context = new()
|
||||||
{
|
{
|
||||||
|
@ -146,5 +145,4 @@ public class SetLastContactMiddlewareTests
|
||||||
LastContactEntity? lastContactEntity = dbMock.LastContacts.FirstOrDefault();
|
LastContactEntity? lastContactEntity = dbMock.LastContacts.FirstOrDefault();
|
||||||
Assert.Null(lastContactEntity);
|
Assert.Null(lastContactEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,7 +8,6 @@ namespace LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
|
|
||||||
public static class IntegrationHelper
|
public static class IntegrationHelper
|
||||||
{
|
{
|
||||||
|
|
||||||
private static readonly Lazy<bool> dbConnected = new(IsDbConnected);
|
private static readonly Lazy<bool> dbConnected = new(IsDbConnected);
|
||||||
|
|
||||||
private static bool IsDbConnected() => ServerStatics.DbConnected;
|
private static bool IsDbConnected() => ServerStatics.DbConnected;
|
||||||
|
|
|
@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Tests.Helpers;
|
namespace LBPUnion.ProjectLighthouse.Tests.Helpers;
|
||||||
|
|
||||||
|
@ -38,6 +39,18 @@ public static class MockHelper
|
||||||
UserToken = "unittest",
|
UserToken = "unittest",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static T2 CastTo<T1, T2>(this IActionResult result) where T1 : ObjectResult
|
||||||
|
{
|
||||||
|
Assert.IsType<T1>(result);
|
||||||
|
T1? typedResult = result as T1;
|
||||||
|
Assert.NotNull(typedResult);
|
||||||
|
Assert.NotNull(typedResult.Value);
|
||||||
|
Assert.IsType<T2?>(typedResult.Value);
|
||||||
|
T2? finalResult = (T2?)typedResult.Value;
|
||||||
|
Assert.NotNull(finalResult);
|
||||||
|
return finalResult;
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<DatabaseContext> GetTestDatabase(IEnumerable<IList> sets, [CallerMemberName] string caller = "", [CallerLineNumber] int lineNum = 0)
|
public static async Task<DatabaseContext> GetTestDatabase(IEnumerable<IList> sets, [CallerMemberName] string caller = "", [CallerLineNumber] int lineNum = 0)
|
||||||
{
|
{
|
||||||
Dictionary<Type, IList> setDict = new();
|
Dictionary<Type, IList> setDict = new();
|
||||||
|
@ -109,9 +122,14 @@ public static class MockHelper
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetupTestController(this ControllerBase controllerBase, string? body = null)
|
public static void SetupTestController(this ControllerBase controllerBase, string? body = null)
|
||||||
|
{
|
||||||
|
SetupTestController(controllerBase, GetUnitTestToken(), body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetupTestController(this ControllerBase controllerBase, GameTokenEntity token, string? body = null)
|
||||||
{
|
{
|
||||||
controllerBase.ControllerContext = GetMockControllerContext(body);
|
controllerBase.ControllerContext = GetMockControllerContext(body);
|
||||||
SetupTestGameToken(controllerBase, GetUnitTestToken());
|
SetupTestGameToken(controllerBase, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ControllerContext GetMockControllerContext() =>
|
public static ControllerContext GetMockControllerContext() =>
|
||||||
|
|
|
@ -88,6 +88,8 @@ public class LighthouseServerTest<TStartup> where TStartup : class
|
||||||
|
|
||||||
private Task<HttpResponseMessage> AuthenticatedRequest(string endpoint, string mmAuth, HttpMethod method)
|
private Task<HttpResponseMessage> AuthenticatedRequest(string endpoint, string mmAuth, HttpMethod method)
|
||||||
{
|
{
|
||||||
|
if (!endpoint.StartsWith("/")) endpoint = $"/{endpoint}";
|
||||||
|
|
||||||
using HttpRequestMessage requestMessage = new(method, endpoint);
|
using HttpRequestMessage requestMessage = new(method, endpoint);
|
||||||
requestMessage.Headers.Add("Cookie", mmAuth);
|
requestMessage.Headers.Add("Cookie", mmAuth);
|
||||||
string path = endpoint.Split("?", StringSplitOptions.RemoveEmptyEntries)[0];
|
string path = endpoint.Split("?", StringSplitOptions.RemoveEmptyEntries)[0];
|
||||||
|
|
841
ProjectLighthouse.Tests/Unit/FilterTests.cs
Normal file
841
ProjectLighthouse.Tests/Unit/FilterTests.cs
Normal file
|
@ -0,0 +1,841 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Tests.Unit;
|
||||||
|
|
||||||
|
[Trait("Category", "Unit")]
|
||||||
|
public class FilterTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void QueryBuilder_DoesDeepClone()
|
||||||
|
{
|
||||||
|
SlotQueryBuilder queryBuilder = new();
|
||||||
|
queryBuilder.AddFilter(new CrossControlFilter());
|
||||||
|
|
||||||
|
SlotQueryBuilder clonedBuilder = queryBuilder.Clone();
|
||||||
|
|
||||||
|
Assert.NotEqual(queryBuilder, clonedBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AdventureFilter_ShouldAccept_WhenAdventure()
|
||||||
|
{
|
||||||
|
AdventureFilter adventureFilter = new();
|
||||||
|
Func<SlotEntity, bool> adventureFunc = adventureFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
IsAdventurePlanet = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(adventureFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AdventureFilter_ShouldReject_WhenNotAdventure()
|
||||||
|
{
|
||||||
|
AdventureFilter adventureFilter = new();
|
||||||
|
Func<SlotEntity, bool> adventureFunc = adventureFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
IsAdventurePlanet = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(adventureFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AuthorLabelFilter_ShouldAccept_WhenExactMatch()
|
||||||
|
{
|
||||||
|
string[] filters =
|
||||||
|
{
|
||||||
|
"LABEL_Test", "LABEL_Unit",
|
||||||
|
};
|
||||||
|
AuthorLabelFilter labelFilter = new(filters);
|
||||||
|
Func<SlotEntity, bool> labelFunc = labelFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
AuthorLabels = "LABEL_Test,LABEL_Unit",
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(labelFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AuthorLabelFilter_ShouldAccept_WhenExactMatch_AndExtraLabelsPresent()
|
||||||
|
{
|
||||||
|
string[] filters =
|
||||||
|
{
|
||||||
|
"LABEL_Test", "LABEL_Unit",
|
||||||
|
};
|
||||||
|
AuthorLabelFilter labelFilter = new(filters);
|
||||||
|
Func<SlotEntity, bool> labelFunc = labelFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
AuthorLabels = "LABEL_Test,LABEL_Unit,LABEL_Lighthouse,LABEL_Bruh",
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(labelFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AuthorLabelFilter_ShouldAccept_WhenFilterEmpty_AndLabelsEmpty()
|
||||||
|
{
|
||||||
|
string[] filters = Array.Empty<string>();
|
||||||
|
AuthorLabelFilter labelFilter = new(filters);
|
||||||
|
Func<SlotEntity, bool> labelFunc = labelFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slotWithNoLabels = new()
|
||||||
|
{
|
||||||
|
AuthorLabels = "",
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(labelFunc(slotWithNoLabels));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void AuthorLabelFilter_ShouldReject_WhenNoneMatch()
|
||||||
|
{
|
||||||
|
string[] filters =
|
||||||
|
{
|
||||||
|
"LABEL_Test", "LABEL_Unit",
|
||||||
|
};
|
||||||
|
AuthorLabelFilter labelFilter = new(filters);
|
||||||
|
Func<SlotEntity, bool> labelFunc = labelFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
AuthorLabels = "LABEL_Adventure,LABEL_Versus",
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(labelFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreatorFilter_ShouldAccept_WhenCreatorIdMatch()
|
||||||
|
{
|
||||||
|
const int creatorId = 27;
|
||||||
|
CreatorFilter creatorFilter = new(creatorId);
|
||||||
|
Func<SlotEntity, bool> creatorFunc = creatorFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
CreatorId = creatorId,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(creatorFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CreatorFilter_ShouldReject_WhenCreatorIdMismatch()
|
||||||
|
{
|
||||||
|
const int filterCreatorId = 27;
|
||||||
|
const int slotCreatorId = 28;
|
||||||
|
CreatorFilter creatorFilter = new(filterCreatorId);
|
||||||
|
Func<SlotEntity, bool> creatorFunc = creatorFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
CreatorId = slotCreatorId,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(creatorFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CrossControlFilter_ShouldAccept_WhenCrossControlRequired()
|
||||||
|
{
|
||||||
|
CrossControlFilter crossControlFilter = new();
|
||||||
|
Func<SlotEntity, bool> ccFunc = crossControlFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
CrossControllerRequired = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(ccFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CrossControlFilter_ShouldReject_WhenCrossControlNotRequired()
|
||||||
|
{
|
||||||
|
CrossControlFilter crossControlFilter = new();
|
||||||
|
Func<SlotEntity, bool> ccFunc = crossControlFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
CrossControllerRequired = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(ccFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExcludeAdventureFilter_ShouldReject_WhenAdventure()
|
||||||
|
{
|
||||||
|
ExcludeAdventureFilter excludeAdventureFilter = new();
|
||||||
|
Func<SlotEntity, bool> adventureFunc = excludeAdventureFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
IsAdventurePlanet = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(adventureFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExcludeAdventureFilter_ShouldAccept_WhenNotAdventure()
|
||||||
|
{
|
||||||
|
ExcludeAdventureFilter excludeAdventureFilter = new();
|
||||||
|
Func<SlotEntity, bool> adventureFunc = excludeAdventureFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
IsAdventurePlanet = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(adventureFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExcludeLBP1OnlyFilter_ShouldReject_WhenLbp1Only_AndTokenNotLbp1_AndNotCreator()
|
||||||
|
{
|
||||||
|
ExcludeLBP1OnlyFilter excludeLBP1 = new(10, GameVersion.LittleBigPlanet2);
|
||||||
|
Func<SlotEntity, bool> excludeFunc = excludeLBP1.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Lbp1Only = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(excludeFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExcludeLBP1OnlyFilter_ShouldAccept_WhenLbp1Only_AndTokenLbp1()
|
||||||
|
{
|
||||||
|
ExcludeLBP1OnlyFilter excludeLBP1 = new(10, GameVersion.LittleBigPlanet1);
|
||||||
|
Func<SlotEntity, bool> excludeFunc = excludeLBP1.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Lbp1Only = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(excludeFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExcludeLBP1OnlyFilter_ShouldAccept_WhenLbp1Only_AndTokenNotLbp1_AndIsCreator()
|
||||||
|
{
|
||||||
|
ExcludeLBP1OnlyFilter excludeLBP1 = new(10, GameVersion.LittleBigPlanet2);
|
||||||
|
Func<SlotEntity, bool> excludeFunc = excludeLBP1.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
CreatorId = 10,
|
||||||
|
Lbp1Only = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(excludeFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExcludeMovePackFilter_ShouldReject_WhenMoveRequired()
|
||||||
|
{
|
||||||
|
ExcludeMovePackFilter excludeMove = new();
|
||||||
|
Func<SlotEntity, bool> excludeFunc = excludeMove.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
MoveRequired = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(excludeFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ExcludeMovePackFilter_ShouldAccept_WhenMoveNotRequired()
|
||||||
|
{
|
||||||
|
ExcludeMovePackFilter excludeMove = new();
|
||||||
|
Func<SlotEntity, bool> excludeFunc = excludeMove.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
MoveRequired = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(excludeFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FirstUploadedFilter_ShouldReject_WhenOlderThanStartTime()
|
||||||
|
{
|
||||||
|
FirstUploadedFilter uploadFilter = new(1000);
|
||||||
|
Func<SlotEntity, bool> uploadFunc = uploadFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
FirstUploaded = 999,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(uploadFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FirstUploadedFilter_ShouldAccept_WhenNewerThanStartTime()
|
||||||
|
{
|
||||||
|
FirstUploadedFilter uploadFilter = new(1000);
|
||||||
|
Func<SlotEntity, bool> uploadFunc = uploadFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
FirstUploaded = 1001,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(uploadFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FirstUploadedFilter_ShouldReject_WhenOlderThanEndTime()
|
||||||
|
{
|
||||||
|
FirstUploadedFilter uploadFilter = new(0, 1000);
|
||||||
|
Func<SlotEntity, bool> uploadFunc = uploadFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
FirstUploaded = 1001,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(uploadFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FirstUploadedFilter_ShouldAccept_WhenNewerThanEndTime()
|
||||||
|
{
|
||||||
|
FirstUploadedFilter uploadFilter = new(0, 1000);
|
||||||
|
Func<SlotEntity, bool> uploadFunc = uploadFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
FirstUploaded = 999,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(uploadFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GameVersionFilter_ShouldAccept_WhenExact_AndEqual()
|
||||||
|
{
|
||||||
|
GameVersionFilter gameVersionFilter = new(GameVersion.LittleBigPlanet1, true);
|
||||||
|
Func<SlotEntity, bool> versionFunc = gameVersionFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
GameVersion = GameVersion.LittleBigPlanet1,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(versionFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GameVersionFilter_ShouldReject_WhenExact_AndNotEqual()
|
||||||
|
{
|
||||||
|
GameVersionFilter gameVersionFilter = new(GameVersion.LittleBigPlanet2, true);
|
||||||
|
Func<SlotEntity, bool> versionFunc = gameVersionFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
GameVersion = GameVersion.LittleBigPlanet1,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(versionFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GameVersionFilter_ShouldAccept_WhenNotExact_AndGreaterThan()
|
||||||
|
{
|
||||||
|
GameVersionFilter gameVersionFilter = new(GameVersion.LittleBigPlanet2);
|
||||||
|
Func<SlotEntity, bool> versionFunc = gameVersionFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
GameVersion = GameVersion.LittleBigPlanet1,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(versionFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GameVersionFilter_ShouldAccept_WhenNotExact_AndEqual()
|
||||||
|
{
|
||||||
|
GameVersionFilter gameVersionFilter = new(GameVersion.LittleBigPlanet2);
|
||||||
|
Func<SlotEntity, bool> versionFunc = gameVersionFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
GameVersion = GameVersion.LittleBigPlanet2,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(versionFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GameVersionFilter_ShouldReject_WhenNotExact_AndLessThan()
|
||||||
|
{
|
||||||
|
GameVersionFilter gameVersionFilter = new(GameVersion.LittleBigPlanet1);
|
||||||
|
Func<SlotEntity, bool> versionFunc = gameVersionFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
GameVersion = GameVersion.LittleBigPlanet2,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(versionFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GameVersionFilter_ShouldReject_WhenVersionNotInList()
|
||||||
|
{
|
||||||
|
GameVersionListFilter gameVersionListFilter = new(GameVersion.LittleBigPlanet1, GameVersion.LittleBigPlanet2);
|
||||||
|
Func<SlotEntity, bool> versionFunc = gameVersionListFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
GameVersion = GameVersion.LittleBigPlanet3,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(versionFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GameVersionFilter_ShouldAccept_WhenVersionIsInList()
|
||||||
|
{
|
||||||
|
GameVersionListFilter gameVersionListFilter = new(GameVersion.LittleBigPlanet1, GameVersion.LittleBigPlanet2);
|
||||||
|
Func<SlotEntity, bool> versionFunc = gameVersionListFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
GameVersion = GameVersion.LittleBigPlanet1,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(versionFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HiddenSlotFilter_ShouldReject_WhenHidden()
|
||||||
|
{
|
||||||
|
HiddenSlotFilter hiddenSlotFilter = new();
|
||||||
|
Func<SlotEntity, bool> hiddenFunc = hiddenSlotFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Hidden = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(hiddenFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HiddenSlotFilter_ShouldAccept_WhenNotHidden()
|
||||||
|
{
|
||||||
|
HiddenSlotFilter hiddenSlotFilter = new();
|
||||||
|
Func<SlotEntity, bool> hiddenFunc = hiddenSlotFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Hidden = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(hiddenFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MoveFilter_ShouldAccept_WhenMoveRequired()
|
||||||
|
{
|
||||||
|
MovePackFilter movePackFilter = new();
|
||||||
|
Func<SlotEntity, bool> moveFunc = movePackFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
MoveRequired = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(moveFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MoveFilter_ShouldReject_WhenMoveNotRequired()
|
||||||
|
{
|
||||||
|
MovePackFilter movePackFilter = new();
|
||||||
|
Func<SlotEntity, bool> moveFunc = movePackFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
MoveRequired = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(moveFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PlayerCountFilter_ShouldReject_WhenHigherThanMaxPlayers()
|
||||||
|
{
|
||||||
|
PlayerCountFilter playerCountFilter = new(maxPlayers: 2);
|
||||||
|
Func<SlotEntity, bool> countFunc = playerCountFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
MinimumPlayers = 1,
|
||||||
|
MaximumPlayers = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(countFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PlayerCountFilter_ShouldReject_WhenLowerThanMinPlayers()
|
||||||
|
{
|
||||||
|
PlayerCountFilter playerCountFilter = new(minPlayers: 2);
|
||||||
|
Func<SlotEntity, bool> countFunc = playerCountFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
MinimumPlayers = 1,
|
||||||
|
MaximumPlayers = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(countFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PlayerCountFilter_ShouldAccept_WhenLowerThanMaxPlayers()
|
||||||
|
{
|
||||||
|
PlayerCountFilter playerCountFilter = new(maxPlayers: 3);
|
||||||
|
Func<SlotEntity, bool> countFunc = playerCountFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
MinimumPlayers = 1,
|
||||||
|
MaximumPlayers = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(countFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PlayerCountFilter_ShouldAccept_WhenHigherThanMinPlayers()
|
||||||
|
{
|
||||||
|
PlayerCountFilter playerCountFilter = new(minPlayers: 2);
|
||||||
|
Func<SlotEntity, bool> countFunc = playerCountFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
MinimumPlayers = 3,
|
||||||
|
MaximumPlayers = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(countFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ResultTypeFilter_ShouldReject_WhenSlotNotPresent()
|
||||||
|
{
|
||||||
|
ResultTypeFilter resultFilter = new();
|
||||||
|
Func<SlotEntity, bool> resultFunc = resultFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new();
|
||||||
|
|
||||||
|
Assert.False(resultFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ResultTypeFilter_ShouldAccept_WhenSlotPresent()
|
||||||
|
{
|
||||||
|
ResultTypeFilter resultFilter = new("slot");
|
||||||
|
Func<SlotEntity, bool> resultFunc = resultFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new();
|
||||||
|
|
||||||
|
Assert.True(resultFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SlotIdFilter_ShouldReject_WhenSlotIdNotPresent()
|
||||||
|
{
|
||||||
|
SlotIdFilter idFilter = new(new List<int>
|
||||||
|
{
|
||||||
|
2,
|
||||||
|
});
|
||||||
|
Func<SlotEntity, bool> idFunc = idFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
SlotId = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(idFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SlotIdFilter_ShouldAccept_WhenSlotIdPresent()
|
||||||
|
{
|
||||||
|
SlotIdFilter idFilter = new(new List<int>
|
||||||
|
{
|
||||||
|
2,
|
||||||
|
});
|
||||||
|
Func<SlotEntity, bool> idFunc = idFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
SlotId = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(idFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SlotTypeFilter_ShouldAccept_WhenSlotTypeMatches()
|
||||||
|
{
|
||||||
|
SlotTypeFilter slotTypeFilter = new(SlotType.User);
|
||||||
|
Func<SlotEntity, bool> typeFunc = slotTypeFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Type = SlotType.User,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(typeFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SlotTypeFilter_ShouldAccept_WhenSlotTypeDoesNotMatch()
|
||||||
|
{
|
||||||
|
SlotTypeFilter slotTypeFilter = new(SlotType.User);
|
||||||
|
Func<SlotEntity, bool> typeFunc = slotTypeFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Type = SlotType.Developer,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(typeFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubLevelFilter_ShouldAccept_WhenUserIsCreator_AndNotSubLevel()
|
||||||
|
{
|
||||||
|
SubLevelFilter subLevelFilter = new(2);
|
||||||
|
Func<SlotEntity, bool> subLevelFunc = subLevelFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
CreatorId = 2,
|
||||||
|
SubLevel = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(subLevelFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubLevelFilter_ShouldAccept_WhenUserIsCreator_AndSubLevel()
|
||||||
|
{
|
||||||
|
SubLevelFilter subLevelFilter = new(2);
|
||||||
|
Func<SlotEntity, bool> subLevelFunc = subLevelFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
CreatorId = 2,
|
||||||
|
SubLevel = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(subLevelFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubLevelFilter_ShouldReject_WhenUserIsNotCreator_AndSubLevel()
|
||||||
|
{
|
||||||
|
SubLevelFilter subLevelFilter = new(2);
|
||||||
|
Func<SlotEntity, bool> subLevelFunc = subLevelFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
CreatorId = 1,
|
||||||
|
SubLevel = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(subLevelFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SubLevelFilter_ShouldAccept_WhenUserIsNotCreator_AndNotSubLevel()
|
||||||
|
{
|
||||||
|
SubLevelFilter subLevelFilter = new(2);
|
||||||
|
Func<SlotEntity, bool> subLevelFunc = subLevelFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
CreatorId = 1,
|
||||||
|
SubLevel = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(subLevelFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TeamPickFilter_ShouldAccept_WhenTeamPick()
|
||||||
|
{
|
||||||
|
TeamPickFilter teamPickFilter = new();
|
||||||
|
Func<SlotEntity, bool> teamPickFunc = teamPickFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
TeamPick = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(teamPickFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TeamPickFilter_ShouldReject_WhenNotTeamPick()
|
||||||
|
{
|
||||||
|
TeamPickFilter teamPickFilter = new();
|
||||||
|
Func<SlotEntity, bool> teamPickFunc = teamPickFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
TeamPick = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(teamPickFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TextFilter_ShouldAccept_WhenDescriptionContainsText()
|
||||||
|
{
|
||||||
|
TextFilter textFilter = new("test");
|
||||||
|
Func<SlotEntity, bool> textFunc = textFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Description = "unit test",
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(textFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TextFilter_ShouldReject_WhenDescriptionDoesNotContainText()
|
||||||
|
{
|
||||||
|
TextFilter textFilter = new("test");
|
||||||
|
Func<SlotEntity, bool> textFunc = textFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Description = "fraction exam",
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(textFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TextFilter_ShouldAccept_WhenNameContainsText()
|
||||||
|
{
|
||||||
|
TextFilter textFilter = new("test");
|
||||||
|
Func<SlotEntity, bool> textFunc = textFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Name = "unit test",
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(textFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TextFilter_ShouldReject_WhenNameDoesNotContainText()
|
||||||
|
{
|
||||||
|
TextFilter textFilter = new("test");
|
||||||
|
Func<SlotEntity, bool> textFunc = textFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Name = "fraction exam",
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(textFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TextFilter_ShouldAccept_WhenIdContainsText()
|
||||||
|
{
|
||||||
|
TextFilter textFilter = new("21");
|
||||||
|
Func<SlotEntity, bool> textFunc = textFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
SlotId = 21,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(textFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TextFilter_ShouldReject_WhenIdDoesNotContainText()
|
||||||
|
{
|
||||||
|
TextFilter textFilter = new("21");
|
||||||
|
Func<SlotEntity, bool> textFunc = textFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
SlotId = 19,
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(textFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TextFilter_ShouldAccept_WhenCreatorUsernameContainsText()
|
||||||
|
{
|
||||||
|
TextFilter textFilter = new("test");
|
||||||
|
Func<SlotEntity, bool> textFunc = textFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Creator = new UserEntity
|
||||||
|
{
|
||||||
|
Username = "test",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.True(textFunc(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TextFilter_ShouldReject_WhenCreatorUsernameDoesNotContainText()
|
||||||
|
{
|
||||||
|
TextFilter textFilter = new("test");
|
||||||
|
Func<SlotEntity, bool> textFunc = textFilter.GetPredicate().Compile();
|
||||||
|
|
||||||
|
SlotEntity slot = new()
|
||||||
|
{
|
||||||
|
Creator = new UserEntity
|
||||||
|
{
|
||||||
|
Username = "bruh",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.False(textFunc(slot));
|
||||||
|
}
|
||||||
|
}
|
238
ProjectLighthouse.Tests/Unit/PaginationTests.cs
Normal file
238
ProjectLighthouse.Tests/Unit/PaginationTests.cs
Normal file
|
@ -0,0 +1,238 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Tests.Unit;
|
||||||
|
|
||||||
|
[Trait("Category", "Unit")]
|
||||||
|
public class PaginationTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void GetPaginationData_IsReadFromQuery()
|
||||||
|
{
|
||||||
|
DefaultHttpContext defaultHttpContext = new()
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
Query = new QueryCollection(new Dictionary<string, StringValues>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"pageStart", new StringValues("10")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pageSize", new StringValues("15")
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
PaginationData pageData = defaultHttpContext.Request.GetPaginationData();
|
||||||
|
|
||||||
|
const int expectedPageStart = 10;
|
||||||
|
const int expectedPageSize = 15;
|
||||||
|
|
||||||
|
Assert.Equal(expectedPageStart, pageData.PageStart);
|
||||||
|
Assert.Equal(expectedPageSize, pageData.PageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetPaginationData_IsPageStartSetToDefault_WhenMissing()
|
||||||
|
{
|
||||||
|
DefaultHttpContext defaultHttpContext = new()
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
Query = new QueryCollection(new Dictionary<string, StringValues>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"pageSize", new StringValues("15")
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
PaginationData pageData = defaultHttpContext.Request.GetPaginationData();
|
||||||
|
|
||||||
|
const int expectedPageStart = 0;
|
||||||
|
const int expectedPageSize = 15;
|
||||||
|
|
||||||
|
Assert.Equal(expectedPageStart, pageData.PageStart);
|
||||||
|
Assert.Equal(expectedPageSize, pageData.PageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetPaginationData_IsPageSizeSetToDefault_WhenMissing()
|
||||||
|
{
|
||||||
|
ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots = 50;
|
||||||
|
|
||||||
|
DefaultHttpContext defaultHttpContext = new()
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
Query = new QueryCollection(new Dictionary<string, StringValues>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"pageStart", new StringValues("10")
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
PaginationData pageData = defaultHttpContext.Request.GetPaginationData();
|
||||||
|
|
||||||
|
const int expectedPageStart = 10;
|
||||||
|
const int expectedPageSize = 50;
|
||||||
|
|
||||||
|
Assert.Equal(expectedPageStart, pageData.PageStart);
|
||||||
|
Assert.Equal(expectedPageSize, pageData.PageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetPaginationData_NegativeValuesAreSetToZero()
|
||||||
|
{
|
||||||
|
ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots = 50;
|
||||||
|
|
||||||
|
DefaultHttpContext defaultHttpContext = new()
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
Query = new QueryCollection(new Dictionary<string, StringValues>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"pageStart", new StringValues("-10")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pageSize", new StringValues("-10")
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
PaginationData pageData = defaultHttpContext.Request.GetPaginationData();
|
||||||
|
|
||||||
|
const int expectedPageStart = 0;
|
||||||
|
const int expectedPageSize = 10;
|
||||||
|
|
||||||
|
Assert.Equal(expectedPageStart, pageData.PageStart);
|
||||||
|
Assert.Equal(expectedPageSize, pageData.PageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyPagination_ShouldApplyCorrectPagination()
|
||||||
|
{
|
||||||
|
List<GameUser> users = new();
|
||||||
|
for (int i = 0; i < 30; i++)
|
||||||
|
{
|
||||||
|
users.Add(new GameUser
|
||||||
|
{
|
||||||
|
UserId = i+1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PaginationData pageData = new()
|
||||||
|
{
|
||||||
|
PageSize = 5,
|
||||||
|
PageStart = 6,
|
||||||
|
};
|
||||||
|
List<GameUser> pagedUsers = users.AsQueryable().ApplyPagination(pageData).ToList();
|
||||||
|
|
||||||
|
Assert.Equal(pageData.PageSize, pagedUsers.Count);
|
||||||
|
Assert.Equal(6, pagedUsers[0].UserId);
|
||||||
|
Assert.Equal(10, pagedUsers[4].UserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyPagination_ShouldClampPageStart_WhenNegative()
|
||||||
|
{
|
||||||
|
List<GameUser> users = new();
|
||||||
|
for (int i = 0; i < 30; i++)
|
||||||
|
{
|
||||||
|
users.Add(new GameUser
|
||||||
|
{
|
||||||
|
UserId = i + 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PaginationData pageData = new()
|
||||||
|
{
|
||||||
|
PageSize = 5,
|
||||||
|
PageStart = -5,
|
||||||
|
};
|
||||||
|
List<GameUser> pagedUsers = users.AsQueryable().ApplyPagination(pageData).ToList();
|
||||||
|
|
||||||
|
Assert.Equal(pageData.PageSize, pagedUsers.Count);
|
||||||
|
Assert.Equal(1, pagedUsers[0].UserId);
|
||||||
|
Assert.Equal(5, pagedUsers[4].UserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyPagination_ShouldReturnEmpty_WhenPageSizeNegative()
|
||||||
|
{
|
||||||
|
List<GameUser> users = new();
|
||||||
|
for (int i = 0; i < 30; i++)
|
||||||
|
{
|
||||||
|
users.Add(new GameUser
|
||||||
|
{
|
||||||
|
UserId = i + 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PaginationData pageData = new()
|
||||||
|
{
|
||||||
|
PageSize = -5,
|
||||||
|
PageStart = 0,
|
||||||
|
};
|
||||||
|
List<GameUser> pagedUsers = users.AsQueryable().ApplyPagination(pageData).ToList();
|
||||||
|
|
||||||
|
Assert.Empty(pagedUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyPagination_ShouldClampPageSize_WhenSizeExceedsMaxElements()
|
||||||
|
{
|
||||||
|
List<GameUser> users = new();
|
||||||
|
for (int i = 0; i < 30; i++)
|
||||||
|
{
|
||||||
|
users.Add(new GameUser
|
||||||
|
{
|
||||||
|
UserId = i + 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PaginationData pageData = new()
|
||||||
|
{
|
||||||
|
PageSize = 10,
|
||||||
|
PageStart = 0,
|
||||||
|
MaxElements = 1,
|
||||||
|
};
|
||||||
|
List<GameUser> pagedUsers = users.AsQueryable().ApplyPagination(pageData).ToList();
|
||||||
|
|
||||||
|
Assert.Single(pagedUsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyPagination_ShouldClampPageSize_WhenSizeExceedsInternalLimit()
|
||||||
|
{
|
||||||
|
List<GameUser> users = new();
|
||||||
|
for (int i = 0; i < 1001; i++)
|
||||||
|
{
|
||||||
|
users.Add(new GameUser
|
||||||
|
{
|
||||||
|
UserId = i + 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
PaginationData pageData = new()
|
||||||
|
{
|
||||||
|
PageSize = int.MaxValue,
|
||||||
|
PageStart = 0,
|
||||||
|
MaxElements = int.MaxValue,
|
||||||
|
};
|
||||||
|
List<GameUser> pagedUsers = users.AsQueryable().ApplyPagination(pageData).ToList();
|
||||||
|
|
||||||
|
Assert.Equal(1000, pagedUsers.Count);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Files;
|
using LBPUnion.ProjectLighthouse.Files;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Resources;
|
using LBPUnion.ProjectLighthouse.Types.Resources;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
@ -44,7 +45,7 @@ public class ResourceTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async void ShouldDeleteResourceAndImage()
|
public async Task ShouldDeleteResourceAndImage()
|
||||||
{
|
{
|
||||||
FileHelper.EnsureDirectoryCreated(FileHelper.ResourcePath);
|
FileHelper.EnsureDirectoryCreated(FileHelper.ResourcePath);
|
||||||
FileHelper.EnsureDirectoryCreated(FileHelper.ImagePath);
|
FileHelper.EnsureDirectoryCreated(FileHelper.ImagePath);
|
||||||
|
|
|
@ -2,56 +2,12 @@ using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Extensions;
|
namespace LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
|
||||||
public static class DatabaseExtensions
|
public static class DatabaseExtensions
|
||||||
{
|
{
|
||||||
public static IQueryable<SlotEntity> ByGameVersion
|
|
||||||
(this DbSet<SlotEntity> set, GameVersion gameVersion, bool includeSublevels = false, bool includeCreator = false)
|
|
||||||
=> set.AsQueryable().ByGameVersion(gameVersion, includeSublevels, includeCreator);
|
|
||||||
|
|
||||||
public static IQueryable<SlotEntity> ByGameVersion
|
|
||||||
(this IQueryable<SlotEntity> query, GameVersion gameVersion, bool includeSublevels = false, bool includeCreator = false, bool includeDeveloperLevels = false)
|
|
||||||
{
|
|
||||||
query = query.Where(s => s.Type == SlotType.User || (s.Type == SlotType.Developer && includeDeveloperLevels));
|
|
||||||
|
|
||||||
if (gameVersion == GameVersion.LittleBigPlanetVita || gameVersion == GameVersion.LittleBigPlanetPSP || gameVersion == GameVersion.Unknown)
|
|
||||||
{
|
|
||||||
query = query.Where(s => s.GameVersion == gameVersion);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
query = query.Where(s => s.GameVersion <= gameVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!includeSublevels) query = query.Where(s => !s.SubLevel);
|
|
||||||
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IQueryable<ReviewEntity> ByGameVersion(this IQueryable<ReviewEntity> queryable, GameVersion gameVersion, bool includeSublevels = false)
|
|
||||||
{
|
|
||||||
IQueryable<ReviewEntity> query = queryable;
|
|
||||||
|
|
||||||
if (gameVersion == GameVersion.LittleBigPlanetVita || gameVersion == GameVersion.LittleBigPlanetPSP || gameVersion == GameVersion.Unknown)
|
|
||||||
{
|
|
||||||
query = query.Where(r => r.Slot.GameVersion == gameVersion);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
query = query.Where(r => r.Slot.GameVersion <= gameVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!includeSublevels) query = query.Where(r => !r.Slot.SubLevel);
|
|
||||||
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<bool> Has<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> predicate)
|
public static async Task<bool> Has<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> predicate)
|
||||||
=> await queryable.FirstOrDefaultAsync(predicate) != null;
|
=> await queryable.FirstOrDefaultAsync(predicate) != null;
|
||||||
|
|
||||||
|
|
30
ProjectLighthouse/Extensions/PredicateExtensions.cs
Normal file
30
ProjectLighthouse/Extensions/PredicateExtensions.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
|
||||||
|
public static class PredicateExtensions
|
||||||
|
{
|
||||||
|
public static Expression<Func<T, bool>> True<T>()
|
||||||
|
{
|
||||||
|
return f => true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expression<Func<T, bool>> False<T>()
|
||||||
|
{
|
||||||
|
return f => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
|
||||||
|
{
|
||||||
|
InvocationExpression invokedExpr = Expression.Invoke(expr2, expr1.Parameters);
|
||||||
|
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Expression<Func<T, bool>> And<T>
|
||||||
|
(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
|
||||||
|
{
|
||||||
|
InvocationExpression invokedExpr = Expression.Invoke(expr2, expr1.Parameters);
|
||||||
|
return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,11 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Logging;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Extensions;
|
namespace LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
|
||||||
|
@ -8,4 +13,19 @@ public static class QueryExtensions
|
||||||
{
|
{
|
||||||
public static List<T2> ToSerializableList<T, T2>(this IEnumerable<T> enumerable, Func<T, T2> selector)
|
public static List<T2> ToSerializableList<T, T2>(this IEnumerable<T> enumerable, Func<T, T2> selector)
|
||||||
=> enumerable.Select(selector).ToList();
|
=> enumerable.Select(selector).ToList();
|
||||||
|
|
||||||
|
public static IQueryable<T> ApplyPagination<T>(this IQueryable<T> queryable, PaginationData pagination)
|
||||||
|
{
|
||||||
|
if (pagination.MaxElements <= 0)
|
||||||
|
{
|
||||||
|
Logger.Warn($"ApplyPagination() called with MaxElements of {pagination.MaxElements}\n{queryable.ToQueryString()}", LogArea.Database);
|
||||||
|
pagination.MaxElements = pagination.PageSize;
|
||||||
|
}
|
||||||
|
queryable = queryable.Skip(Math.Max(0, pagination.PageStart - 1));
|
||||||
|
return queryable.Take(Math.Min(pagination.PageSize, Math.Min(1000, pagination.MaxElements)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IOrderedQueryable<T> ApplyOrdering<T>
|
||||||
|
(this IQueryable<T> queryable, ISortBuilder<T> sortBuilder) =>
|
||||||
|
sortBuilder.Build(queryable);
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
||||||
|
@ -7,6 +9,25 @@ namespace LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
|
||||||
public static partial class RequestExtensions
|
public static partial class RequestExtensions
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public static PaginationData GetPaginationData(this HttpRequest request)
|
||||||
|
{
|
||||||
|
int start = int.TryParse(request.Query["pageStart"], out int pageStart) ? pageStart : 0;
|
||||||
|
int size = int.TryParse(request.Query["pageSize"], out int pageSize)
|
||||||
|
? pageSize
|
||||||
|
: ServerConfiguration.Instance.UserGeneratedContentLimits.EntitledSlots;
|
||||||
|
|
||||||
|
if (start < 0) start = 0;
|
||||||
|
if (size <= 0) size = 10;
|
||||||
|
|
||||||
|
PaginationData paginationData = new()
|
||||||
|
{
|
||||||
|
PageStart = start,
|
||||||
|
PageSize = size,
|
||||||
|
};
|
||||||
|
return paginationData;
|
||||||
|
}
|
||||||
|
|
||||||
#region Mobile Checking
|
#region Mobile Checking
|
||||||
|
|
||||||
// yoinked and adapted from https://stackoverflow.com/a/68641796
|
// yoinked and adapted from https://stackoverflow.com/a/68641796
|
||||||
|
|
13
ProjectLighthouse/Filter/Filters/AdventureFilter.cs
Normal file
13
ProjectLighthouse/Filter/Filters/AdventureFilter.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class AdventureFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
PredicateExtensions.True<SlotEntity>().And(s => s.IsAdventurePlanet);
|
||||||
|
}
|
26
ProjectLighthouse/Filter/Filters/AuthorLabelFilter.cs
Normal file
26
ProjectLighthouse/Filter/Filters/AuthorLabelFilter.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class AuthorLabelFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly string[] labels;
|
||||||
|
|
||||||
|
public AuthorLabelFilter(params string[] labels)
|
||||||
|
{
|
||||||
|
this.labels = labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate()
|
||||||
|
{
|
||||||
|
Expression<Func<SlotEntity, bool>> predicate = PredicateExtensions.True<SlotEntity>();
|
||||||
|
predicate = this.labels.Aggregate(predicate,
|
||||||
|
(current, label) => current.And(s => s.AuthorLabels.Contains(label)));
|
||||||
|
return predicate;
|
||||||
|
}
|
||||||
|
}
|
20
ProjectLighthouse/Filter/Filters/CreatorFilter.cs
Normal file
20
ProjectLighthouse/Filter/Filters/CreatorFilter.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class CreatorFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly int creatorId;
|
||||||
|
|
||||||
|
public CreatorFilter(int creatorId)
|
||||||
|
{
|
||||||
|
this.creatorId = creatorId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
PredicateExtensions.True<SlotEntity>().And(s => s.CreatorId == this.creatorId);
|
||||||
|
}
|
13
ProjectLighthouse/Filter/Filters/CrossControlFilter.cs
Normal file
13
ProjectLighthouse/Filter/Filters/CrossControlFilter.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class CrossControlFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
PredicateExtensions.True<SlotEntity>().And(s => s.CrossControllerRequired);
|
||||||
|
}
|
13
ProjectLighthouse/Filter/Filters/ExcludeAdventureFilter.cs
Normal file
13
ProjectLighthouse/Filter/Filters/ExcludeAdventureFilter.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class ExcludeAdventureFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
PredicateExtensions.True<SlotEntity>().And(s => !s.IsAdventurePlanet);
|
||||||
|
}
|
27
ProjectLighthouse/Filter/Filters/ExcludeLBP1OnlyFilter.cs
Normal file
27
ProjectLighthouse/Filter/Filters/ExcludeLBP1OnlyFilter.cs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class ExcludeLBP1OnlyFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly int userId;
|
||||||
|
private readonly GameVersion targetGameVersion;
|
||||||
|
|
||||||
|
public ExcludeLBP1OnlyFilter(int userId, GameVersion targetGameVersion)
|
||||||
|
{
|
||||||
|
this.userId = userId;
|
||||||
|
this.targetGameVersion = targetGameVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate()
|
||||||
|
{
|
||||||
|
Expression<Func<SlotEntity, bool>> predicate = PredicateExtensions.True<SlotEntity>();
|
||||||
|
predicate = predicate.And(s => !s.Lbp1Only || s.CreatorId == this.userId || this.targetGameVersion == GameVersion.LittleBigPlanet1);
|
||||||
|
return predicate;
|
||||||
|
}
|
||||||
|
}
|
13
ProjectLighthouse/Filter/Filters/ExcludeMovePackFilter.cs
Normal file
13
ProjectLighthouse/Filter/Filters/ExcludeMovePackFilter.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class ExcludeMovePackFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
PredicateExtensions.True<SlotEntity>().And(s => !s.MoveRequired);
|
||||||
|
}
|
30
ProjectLighthouse/Filter/Filters/FirstUploadedFilter.cs
Normal file
30
ProjectLighthouse/Filter/Filters/FirstUploadedFilter.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class FirstUploadedFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly long start;
|
||||||
|
private readonly long end;
|
||||||
|
|
||||||
|
public FirstUploadedFilter(long start, long end = long.MaxValue)
|
||||||
|
{
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate()
|
||||||
|
{
|
||||||
|
Expression<Func<SlotEntity, bool>> predicate = PredicateExtensions.True<SlotEntity>();
|
||||||
|
predicate = predicate.And(s => s.FirstUploaded > this.start);
|
||||||
|
|
||||||
|
// Exclude to optimize query
|
||||||
|
if (this.end != long.MaxValue) predicate = predicate.And(s => s.FirstUploaded < this.end);
|
||||||
|
|
||||||
|
return predicate;
|
||||||
|
}
|
||||||
|
}
|
29
ProjectLighthouse/Filter/Filters/GameVersionFilter.cs
Normal file
29
ProjectLighthouse/Filter/Filters/GameVersionFilter.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class GameVersionFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly GameVersion targetVersion;
|
||||||
|
private readonly bool matchExactly;
|
||||||
|
|
||||||
|
public GameVersionFilter(GameVersion targetVersion, bool matchExactly = false)
|
||||||
|
{
|
||||||
|
this.targetVersion = targetVersion;
|
||||||
|
this.matchExactly = matchExactly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate()
|
||||||
|
{
|
||||||
|
Expression<Func<SlotEntity, bool>> predicate = PredicateExtensions.True<SlotEntity>();
|
||||||
|
predicate = this.matchExactly || this.targetVersion is GameVersion.LittleBigPlanetVita or GameVersion.LittleBigPlanetPSP or GameVersion.Unknown
|
||||||
|
? predicate.And(s => s.GameVersion == this.targetVersion)
|
||||||
|
: predicate.And(s => s.GameVersion <= this.targetVersion);
|
||||||
|
return predicate;
|
||||||
|
}
|
||||||
|
}
|
23
ProjectLighthouse/Filter/Filters/GameVersionListFilter.cs
Normal file
23
ProjectLighthouse/Filter/Filters/GameVersionListFilter.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class GameVersionListFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly GameVersion[] versions;
|
||||||
|
|
||||||
|
public GameVersionListFilter(params GameVersion[] versions)
|
||||||
|
{
|
||||||
|
this.versions = versions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
this.versions.Aggregate(PredicateExtensions.False<SlotEntity>(),
|
||||||
|
(current, version) => current.Or(s => s.GameVersion == version));
|
||||||
|
}
|
13
ProjectLighthouse/Filter/Filters/HiddenSlotFilter.cs
Normal file
13
ProjectLighthouse/Filter/Filters/HiddenSlotFilter.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class HiddenSlotFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
PredicateExtensions.True<SlotEntity>().And(s => !s.Hidden);
|
||||||
|
}
|
13
ProjectLighthouse/Filter/Filters/MovePackFilter.cs
Normal file
13
ProjectLighthouse/Filter/Filters/MovePackFilter.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class MovePackFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
PredicateExtensions.True<SlotEntity>().And(s => s.MoveRequired);
|
||||||
|
}
|
28
ProjectLighthouse/Filter/Filters/PlayerCountFilter.cs
Normal file
28
ProjectLighthouse/Filter/Filters/PlayerCountFilter.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class PlayerCountFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly int minPlayers;
|
||||||
|
private readonly int maxPlayers;
|
||||||
|
|
||||||
|
public PlayerCountFilter(int minPlayers = 1, int maxPlayers = 4)
|
||||||
|
{
|
||||||
|
this.minPlayers = minPlayers;
|
||||||
|
this.maxPlayers = maxPlayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate()
|
||||||
|
{
|
||||||
|
Expression<Func<SlotEntity, bool>> predicate = PredicateExtensions.True<SlotEntity>();
|
||||||
|
predicate = predicate.And(s => s.MinimumPlayers >= this.minPlayers);
|
||||||
|
predicate = predicate.And(s => s.MaximumPlayers <= this.maxPlayers);
|
||||||
|
|
||||||
|
return predicate;
|
||||||
|
}
|
||||||
|
}
|
23
ProjectLighthouse/Filter/Filters/ResultTypeFilter.cs
Normal file
23
ProjectLighthouse/Filter/Filters/ResultTypeFilter.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class ResultTypeFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly string[] results;
|
||||||
|
|
||||||
|
public ResultTypeFilter(params string[] results)
|
||||||
|
{
|
||||||
|
this.results = results;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
this.results.Contains("slot")
|
||||||
|
? PredicateExtensions.True<SlotEntity>()
|
||||||
|
: PredicateExtensions.False<SlotEntity>();
|
||||||
|
}
|
26
ProjectLighthouse/Filter/Filters/SlotIdFilter.cs
Normal file
26
ProjectLighthouse/Filter/Filters/SlotIdFilter.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class SlotIdFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly List<int> slotIds;
|
||||||
|
|
||||||
|
public SlotIdFilter(List<int> slotIds)
|
||||||
|
{
|
||||||
|
this.slotIds = slotIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate()
|
||||||
|
{
|
||||||
|
Expression<Func<SlotEntity, bool>> predicate = PredicateExtensions.False<SlotEntity>();
|
||||||
|
predicate = this.slotIds.Aggregate(predicate, (current, slotId) => current.Or(s => s.SlotId == slotId));
|
||||||
|
return predicate;
|
||||||
|
}
|
||||||
|
}
|
21
ProjectLighthouse/Filter/Filters/SlotTypeFilter.cs
Normal file
21
ProjectLighthouse/Filter/Filters/SlotTypeFilter.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class SlotTypeFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly SlotType slotType;
|
||||||
|
|
||||||
|
public SlotTypeFilter(SlotType slotType)
|
||||||
|
{
|
||||||
|
this.slotType = slotType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
PredicateExtensions.True<SlotEntity>().And(s => s.Type == this.slotType);
|
||||||
|
}
|
20
ProjectLighthouse/Filter/Filters/SubLevelFilter.cs
Normal file
20
ProjectLighthouse/Filter/Filters/SubLevelFilter.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class SubLevelFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly int userId;
|
||||||
|
|
||||||
|
public SubLevelFilter(int userId)
|
||||||
|
{
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
PredicateExtensions.True<SlotEntity>().And(s => !s.SubLevel || s.CreatorId == this.userId);
|
||||||
|
}
|
13
ProjectLighthouse/Filter/Filters/TeamPickFilter.cs
Normal file
13
ProjectLighthouse/Filter/Filters/TeamPickFilter.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class TeamPickFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
|
||||||
|
PredicateExtensions.True<SlotEntity>().And(s => s.TeamPick);
|
||||||
|
}
|
32
ProjectLighthouse/Filter/Filters/TextFilter.cs
Normal file
32
ProjectLighthouse/Filter/Filters/TextFilter.cs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
|
||||||
|
|
||||||
|
public class TextFilter : ISlotFilter
|
||||||
|
{
|
||||||
|
private readonly string filter;
|
||||||
|
|
||||||
|
public TextFilter(string filter)
|
||||||
|
{
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> GetPredicate()
|
||||||
|
{
|
||||||
|
Expression<Func<SlotEntity, bool>> predicate = PredicateExtensions.False<SlotEntity>();
|
||||||
|
string[] keywords = this.filter.Split(" ", StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
foreach (string keyword in keywords)
|
||||||
|
{
|
||||||
|
predicate = predicate.Or(s =>
|
||||||
|
s.Name.Contains(keyword) ||
|
||||||
|
s.Description.ToLower().Contains(keyword) ||
|
||||||
|
s.SlotId.ToString().Equals(keyword));
|
||||||
|
predicate = predicate.Or(s => s.Creator != null && s.Creator.Username.Contains(keyword));
|
||||||
|
}
|
||||||
|
return predicate;
|
||||||
|
}
|
||||||
|
}
|
55
ProjectLighthouse/Filter/SlotQueryBuilder.cs
Normal file
55
ProjectLighthouse/Filter/SlotQueryBuilder.cs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Extensions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
|
||||||
|
public class SlotQueryBuilder : IQueryBuilder<SlotEntity>
|
||||||
|
{
|
||||||
|
private readonly List<ISlotFilter> filters;
|
||||||
|
|
||||||
|
public SlotQueryBuilder()
|
||||||
|
{
|
||||||
|
this.filters = new List<ISlotFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, bool>> Build()
|
||||||
|
{
|
||||||
|
Expression<Func<SlotEntity, bool>> predicate = PredicateExtensions.True<SlotEntity>();
|
||||||
|
predicate = this.filters.Aggregate(predicate, (current, filter) => current.And(filter.GetPredicate()));
|
||||||
|
return predicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotQueryBuilder RemoveFilter(Type type)
|
||||||
|
{
|
||||||
|
this.filters.RemoveAll(f => f.GetType() == type);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
public IEnumerable<ISlotFilter> GetFilters(Type type) => this.filters.Where(f => f.GetType() == type).ToList();
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
public SlotQueryBuilder AddFilter(int index, ISlotFilter filter)
|
||||||
|
{
|
||||||
|
this.filters.Insert(index, filter);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotQueryBuilder Clone()
|
||||||
|
{
|
||||||
|
SlotQueryBuilder clone = new();
|
||||||
|
clone.filters.AddRange(this.filters);
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotQueryBuilder AddFilter(ISlotFilter filter)
|
||||||
|
{
|
||||||
|
this.filters.Add(filter);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
56
ProjectLighthouse/Filter/SlotSortBuilder.cs
Normal file
56
ProjectLighthouse/Filter/SlotSortBuilder.cs
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
|
||||||
|
public class SlotSortBuilder<T> : ISortBuilder<T>
|
||||||
|
{
|
||||||
|
private readonly List<ISort<T>> sorts;
|
||||||
|
private bool sortDescending;
|
||||||
|
|
||||||
|
public SlotSortBuilder()
|
||||||
|
{
|
||||||
|
this.sorts = new List<ISort<T>>();
|
||||||
|
this.sortDescending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotSortBuilder<T> AddSort(ISort<T> sort)
|
||||||
|
{
|
||||||
|
this.sorts.Add(sort);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotSortBuilder<T> SortDescending(bool descending)
|
||||||
|
{
|
||||||
|
this.sortDescending = descending;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IOrderedQueryable<T> Build(IQueryable<T> queryable)
|
||||||
|
{
|
||||||
|
IOrderedQueryable<T> orderedQueryable = (IOrderedQueryable<T>)queryable;
|
||||||
|
// Probably not the best way to do this but to convert from IQueryable to IOrderedQueryable you have to
|
||||||
|
// OrderBy some field before you can call ThenBy. One way to do this is call OrderBy(s => 0) but this
|
||||||
|
// generates some extra SQL so I've settled on this
|
||||||
|
bool usedFirstOrder = false;
|
||||||
|
foreach (ISort<T> sort in this.sorts)
|
||||||
|
{
|
||||||
|
if (this.sortDescending)
|
||||||
|
{
|
||||||
|
orderedQueryable = !usedFirstOrder
|
||||||
|
? orderedQueryable.OrderByDescending(sort.GetExpression())
|
||||||
|
: orderedQueryable.ThenByDescending(sort.GetExpression());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
orderedQueryable = !usedFirstOrder
|
||||||
|
? orderedQueryable.OrderBy(sort.GetExpression())
|
||||||
|
: orderedQueryable.ThenBy(sort.GetExpression());
|
||||||
|
}
|
||||||
|
|
||||||
|
usedFirstOrder = true;
|
||||||
|
}
|
||||||
|
return orderedQueryable;
|
||||||
|
}
|
||||||
|
}
|
11
ProjectLighthouse/Filter/Sorts/FirstUploadedSort.cs
Normal file
11
ProjectLighthouse/Filter/Sorts/FirstUploadedSort.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
|
||||||
|
public class FirstUploadedSort : ISlotSort
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, dynamic>> GetExpression() => s => s.FirstUploaded;
|
||||||
|
}
|
11
ProjectLighthouse/Filter/Sorts/LastUpdatedSort.cs
Normal file
11
ProjectLighthouse/Filter/Sorts/LastUpdatedSort.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
|
||||||
|
public class LastUpdatedSort : ISlotSort
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, dynamic>> GetExpression() => s => s.LastUpdated;
|
||||||
|
}
|
11
ProjectLighthouse/Filter/Sorts/Metadata/HeartsSort.cs
Normal file
11
ProjectLighthouse/Filter/Sorts/Metadata/HeartsSort.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts.Metadata;
|
||||||
|
|
||||||
|
public class HeartsSort : ISort<SlotMetadata>
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotMetadata, dynamic>> GetExpression() => s => s.Hearts;
|
||||||
|
}
|
11
ProjectLighthouse/Filter/Sorts/Metadata/RatingLBP1Sort.cs
Normal file
11
ProjectLighthouse/Filter/Sorts/Metadata/RatingLBP1Sort.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts.Metadata;
|
||||||
|
|
||||||
|
public class RatingLBP1Sort : ISort<SlotMetadata>
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotMetadata, dynamic>> GetExpression() => s => s.RatingLbp1;
|
||||||
|
}
|
11
ProjectLighthouse/Filter/Sorts/Metadata/ThumbsUpSort.cs
Normal file
11
ProjectLighthouse/Filter/Sorts/Metadata/ThumbsUpSort.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Misc;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts.Metadata;
|
||||||
|
|
||||||
|
public class ThumbsUpSort : ISort<SlotMetadata>
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotMetadata, dynamic>> GetExpression() => s => s.ThumbsUp;
|
||||||
|
}
|
30
ProjectLighthouse/Filter/Sorts/PlaysForGameSort.cs
Normal file
30
ProjectLighthouse/Filter/Sorts/PlaysForGameSort.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
|
||||||
|
public class PlaysForGameSort : ISlotSort
|
||||||
|
{
|
||||||
|
private readonly GameVersion targetVersion;
|
||||||
|
|
||||||
|
public PlaysForGameSort(GameVersion targetVersion)
|
||||||
|
{
|
||||||
|
this.targetVersion = targetVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetColName() =>
|
||||||
|
this.targetVersion switch
|
||||||
|
{
|
||||||
|
GameVersion.LittleBigPlanet1 => "LBP1",
|
||||||
|
GameVersion.LittleBigPlanet2 => "LBP2",
|
||||||
|
GameVersion.LittleBigPlanet3 => "LBP3",
|
||||||
|
GameVersion.LittleBigPlanetVita => "LBP2",
|
||||||
|
_ => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, dynamic>> GetExpression() => s => EF.Property<dynamic>(s, $"Plays{this.GetColName()}");
|
||||||
|
}
|
15
ProjectLighthouse/Filter/Sorts/RandomFirstUploadedSort.cs
Normal file
15
ProjectLighthouse/Filter/Sorts/RandomFirstUploadedSort.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
|
||||||
|
public class RandomFirstUploadedSort : ISlotSort
|
||||||
|
{
|
||||||
|
private const double biasFactor = .8f;
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, dynamic>> GetExpression() =>
|
||||||
|
s => EF.Functions.Random() * (s.FirstUploaded * biasFactor);
|
||||||
|
}
|
12
ProjectLighthouse/Filter/Sorts/RandomSort.cs
Normal file
12
ProjectLighthouse/Filter/Sorts/RandomSort.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
|
||||||
|
public class RandomSort : ISlotSort
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, dynamic>> GetExpression() => _ => EF.Functions.Random();
|
||||||
|
}
|
11
ProjectLighthouse/Filter/Sorts/SlotIdSort.cs
Normal file
11
ProjectLighthouse/Filter/Sorts/SlotIdSort.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
|
||||||
|
public class SlotIdSort : ISlotSort
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, dynamic>> GetExpression() => s => s.SlotId;
|
||||||
|
}
|
11
ProjectLighthouse/Filter/Sorts/TotalPlaysSort.cs
Normal file
11
ProjectLighthouse/Filter/Sorts/TotalPlaysSort.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
|
||||||
|
public class TotalPlaysSort : ISlotSort
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, dynamic>> GetExpression() => s => s.PlaysLBP1 + s.PlaysLBP2 + s.PlaysLBP3;
|
||||||
|
}
|
30
ProjectLighthouse/Filter/Sorts/UniquePlaysForGameSort.cs
Normal file
30
ProjectLighthouse/Filter/Sorts/UniquePlaysForGameSort.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
|
||||||
|
public class UniquePlaysForGameSort : ISlotSort
|
||||||
|
{
|
||||||
|
private readonly GameVersion targetVersion;
|
||||||
|
|
||||||
|
public UniquePlaysForGameSort(GameVersion targetVersion)
|
||||||
|
{
|
||||||
|
this.targetVersion = targetVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetColName() =>
|
||||||
|
this.targetVersion switch
|
||||||
|
{
|
||||||
|
GameVersion.LittleBigPlanet1 => "LBP1",
|
||||||
|
GameVersion.LittleBigPlanet2 => "LBP2",
|
||||||
|
GameVersion.LittleBigPlanet3 => "LBP3",
|
||||||
|
GameVersion.LittleBigPlanetVita => "LBP2",
|
||||||
|
_ => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
public Expression<Func<SlotEntity, dynamic>> GetExpression() => s => EF.Property<dynamic>(s, $"Plays{this.GetColName()}Unique");
|
||||||
|
}
|
12
ProjectLighthouse/Filter/Sorts/UniquePlaysTotalSort.cs
Normal file
12
ProjectLighthouse/Filter/Sorts/UniquePlaysTotalSort.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Filter.Sorts;
|
||||||
|
|
||||||
|
public class UniquePlaysTotalSort : ISlotSort
|
||||||
|
{
|
||||||
|
public Expression<Func<SlotEntity, dynamic>> GetExpression() =>
|
||||||
|
s => s.PlaysLBP1Unique + s.PlaysLBP2Unique + s.PlaysLBP3Unique;
|
||||||
|
}
|
|
@ -4,9 +4,11 @@ using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
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.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
@ -14,7 +16,6 @@ namespace LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
|
||||||
public static class SlotHelper
|
public static class SlotHelper
|
||||||
{
|
{
|
||||||
|
|
||||||
public static SlotType ParseType(string? slotType)
|
public static SlotType ParseType(string? slotType)
|
||||||
{
|
{
|
||||||
if (slotType == null) return SlotType.Unknown;
|
if (slotType == null) return SlotType.Unknown;
|
||||||
|
@ -41,7 +42,8 @@ public static class SlotHelper
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly SemaphoreSlim semaphore = new(1, 1);
|
private static readonly SemaphoreSlim slotSemaphore = new(1, 1);
|
||||||
|
private static readonly SemaphoreSlim userSemaphore = new(1, 1);
|
||||||
|
|
||||||
public static async Task<int> GetPlaceholderUserId(DatabaseContext database)
|
public static async Task<int> GetPlaceholderUserId(DatabaseContext database)
|
||||||
{
|
{
|
||||||
|
@ -50,7 +52,13 @@ public static class SlotHelper
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
if (devCreatorId != 0) return devCreatorId;
|
if (devCreatorId != 0) return devCreatorId;
|
||||||
|
|
||||||
await semaphore.WaitAsync(TimeSpan.FromSeconds(5));
|
bool acquired = await userSemaphore.WaitAsync(TimeSpan.FromSeconds(5));
|
||||||
|
if (!acquired)
|
||||||
|
{
|
||||||
|
Logger.Warn($"Failed to acquire lock for placeholder user, semaphoreCount={userSemaphore.CurrentCount}",
|
||||||
|
LogArea.Synchronization);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UserEntity devCreator = new()
|
UserEntity devCreator = new()
|
||||||
|
@ -66,7 +74,7 @@ public static class SlotHelper
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
semaphore.Release();
|
if (acquired) userSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +83,14 @@ public static class SlotHelper
|
||||||
int slotId = await database.Slots.Where(s => s.Type == slotType && s.InternalSlotId == guid).Select(s => s.SlotId).FirstOrDefaultAsync();
|
int slotId = await database.Slots.Where(s => s.Type == slotType && s.InternalSlotId == guid).Select(s => s.SlotId).FirstOrDefaultAsync();
|
||||||
if (slotId != 0) return slotId;
|
if (slotId != 0) return slotId;
|
||||||
|
|
||||||
await semaphore.WaitAsync(TimeSpan.FromSeconds(5));
|
bool acquired = await slotSemaphore.WaitAsync(TimeSpan.FromSeconds(5));
|
||||||
|
if (!acquired)
|
||||||
|
{
|
||||||
|
Logger.Warn(
|
||||||
|
$"Failed to acquire lock for placeholder slot, guid={guid}, slotType={slotType}, semaphoreCount={slotSemaphore.CurrentCount}",
|
||||||
|
LogArea.Synchronization);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// if two requests come in at the same time for the same story level which hasn't been generated
|
// if two requests come in at the same time for the same story level which hasn't been generated
|
||||||
|
@ -104,7 +119,7 @@ public static class SlotHelper
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
semaphore.Release();
|
if(acquired) slotSemaphore.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,9 +1,7 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Extensions;
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Matchmaking.Rooms;
|
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
using LBPUnion.ProjectLighthouse.Types.Users;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
@ -17,18 +15,12 @@ public static class StatisticsHelper
|
||||||
public static async Task<int> RecentMatchesForGame(DatabaseContext database, GameVersion gameVersion)
|
public static async Task<int> RecentMatchesForGame(DatabaseContext database, GameVersion gameVersion)
|
||||||
=> await database.LastContacts.Where(l => TimeHelper.Timestamp - l.Timestamp < 300 && l.GameVersion == gameVersion).CountAsync();
|
=> await database.LastContacts.Where(l => TimeHelper.Timestamp - l.Timestamp < 300 && l.GameVersion == gameVersion).CountAsync();
|
||||||
|
|
||||||
public static async Task<int> SlotCount(DatabaseContext database) => await database.Slots.Where(s => s.Type == SlotType.User).CountAsync();
|
public static async Task<int> SlotCount(DatabaseContext database, SlotQueryBuilder queryBuilder) => await database.Slots.Where(queryBuilder.Build()).CountAsync();
|
||||||
|
|
||||||
public static async Task<int> SlotCountForGame(DatabaseContext database, GameVersion gameVersion, bool includeSublevels = false) => await database.Slots.ByGameVersion(gameVersion, includeSublevels).CountAsync();
|
|
||||||
|
|
||||||
public static async Task<int> UserCount(DatabaseContext database) => await database.Users.CountAsync(u => u.PermissionLevel != PermissionLevel.Banned);
|
public static async Task<int> UserCount(DatabaseContext database) => await database.Users.CountAsync(u => u.PermissionLevel != PermissionLevel.Banned);
|
||||||
|
|
||||||
public static int RoomCountForPlatform(Platform targetPlatform) => RoomHelper.Rooms.Count(r => r.IsLookingForPlayers && r.RoomPlatform == targetPlatform);
|
public static int RoomCountForPlatform(Platform targetPlatform) => RoomHelper.Rooms.Count(r => r.IsLookingForPlayers && r.RoomPlatform == targetPlatform);
|
||||||
|
|
||||||
public static async Task<int> TeamPickCount(DatabaseContext database) => await database.Slots.CountAsync(s => s.TeamPick);
|
|
||||||
|
|
||||||
public static async Task<int> TeamPickCountForGame(DatabaseContext database, GameVersion gameVersion, bool? crosscontrol = null) => await database.Slots.ByGameVersion(gameVersion).CountAsync(s => s.TeamPick && (crosscontrol == null || s.CrossControllerRequired == crosscontrol));
|
|
||||||
|
|
||||||
public static async Task<int> PhotoCount(DatabaseContext database) => await database.Photos.CountAsync();
|
public static async Task<int> PhotoCount(DatabaseContext database) => await database.Photos.CountAsync();
|
||||||
|
|
||||||
#region Moderator/Admin specific
|
#region Moderator/Admin specific
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class MailQueueService : IMailService, IDisposable
|
||||||
this.emailThread = Task.Factory.StartNew(this.EmailQueue);
|
this.emailThread = Task.Factory.StartNew(this.EmailQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void EmailQueue()
|
private async Task EmailQueue()
|
||||||
{
|
{
|
||||||
while (!this.stopSignal)
|
while (!this.stopSignal)
|
||||||
{
|
{
|
||||||
|
|
9
ProjectLighthouse/Types/Filter/IFilter.cs
Normal file
9
ProjectLighthouse/Types/Filter/IFilter.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
public interface IFilter<T>
|
||||||
|
{
|
||||||
|
public Expression<Func<T, bool>> GetPredicate();
|
||||||
|
}
|
9
ProjectLighthouse/Types/Filter/IQueryBuilder.cs
Normal file
9
ProjectLighthouse/Types/Filter/IQueryBuilder.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
public interface IQueryBuilder<T>
|
||||||
|
{
|
||||||
|
public Expression<Func<T, bool>> Build();
|
||||||
|
}
|
6
ProjectLighthouse/Types/Filter/ISlotFilter.cs
Normal file
6
ProjectLighthouse/Types/Filter/ISlotFilter.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
public interface ISlotFilter : IFilter<SlotEntity>
|
||||||
|
{ }
|
16
ProjectLighthouse/Types/Filter/PaginationData.cs
Normal file
16
ProjectLighthouse/Types/Filter/PaginationData.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Filter;
|
||||||
|
|
||||||
|
public struct PaginationData
|
||||||
|
{
|
||||||
|
public PaginationData()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public int PageStart { get; init; } = 0;
|
||||||
|
public int PageSize { get; init; } = 0;
|
||||||
|
public int TotalElements { get; set; } = 0;
|
||||||
|
public int MaxElements { get; set; } = 30;
|
||||||
|
|
||||||
|
public int HintStart => this.PageStart + Math.Min(this.PageSize, this.MaxElements);
|
||||||
|
}
|
6
ProjectLighthouse/Types/Filter/Sorts/ISlotSort.cs
Normal file
6
ProjectLighthouse/Types/Filter/Sorts/ISlotSort.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
|
||||||
|
public interface ISlotSort : ISort<SlotEntity>
|
||||||
|
{ }
|
9
ProjectLighthouse/Types/Filter/Sorts/ISort.cs
Normal file
9
ProjectLighthouse/Types/Filter/Sorts/ISort.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
|
||||||
|
public interface ISort<T>
|
||||||
|
{
|
||||||
|
public Expression<Func<T, dynamic>> GetExpression();
|
||||||
|
}
|
8
ProjectLighthouse/Types/Filter/Sorts/ISortBuilder.cs
Normal file
8
ProjectLighthouse/Types/Filter/Sorts/ISortBuilder.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Types.Filter.Sorts;
|
||||||
|
|
||||||
|
public interface ISortBuilder<T>
|
||||||
|
{
|
||||||
|
public IOrderedQueryable<T> Build(IQueryable<T> queryable);
|
||||||
|
}
|
|
@ -1,49 +1,31 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Xml.Serialization;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Database;
|
using LBPUnion.ProjectLighthouse.Database;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
|
using LBPUnion.ProjectLighthouse.Filter;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Users;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Levels;
|
namespace LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
|
||||||
[XmlType("category")]
|
|
||||||
[XmlRoot("category")]
|
|
||||||
public abstract class Category
|
public abstract class Category
|
||||||
{
|
{
|
||||||
[XmlElement("name")]
|
|
||||||
public abstract string Name { get; set; }
|
public abstract string Name { get; set; }
|
||||||
|
|
||||||
[XmlElement("description")]
|
|
||||||
public abstract string Description { get; set; }
|
public abstract string Description { get; set; }
|
||||||
|
|
||||||
[XmlElement("icon")]
|
|
||||||
public abstract string IconHash { get; set; }
|
public abstract string IconHash { get; set; }
|
||||||
|
|
||||||
[XmlIgnore]
|
|
||||||
public abstract string Endpoint { get; set; }
|
public abstract string Endpoint { get; set; }
|
||||||
|
|
||||||
[XmlElement("url")]
|
public string[] Sorts { get; } = { "relevance", "likes", "plays", "hearts", "date", };
|
||||||
public string IngameEndpoint {
|
|
||||||
get => $"/searches/{this.Endpoint}";
|
|
||||||
set => this.Endpoint = value.Replace("/searches/", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract SlotEntity? GetPreviewSlot(DatabaseContext database);
|
public abstract string[] Types { get; }
|
||||||
|
|
||||||
public abstract IEnumerable<SlotEntity> GetSlots(DatabaseContext database, int pageStart, int pageSize);
|
public abstract string Tag { get; }
|
||||||
|
|
||||||
public abstract int GetTotalSlots(DatabaseContext database);
|
public string IngameEndpoint => $"/searches/{this.Endpoint}";
|
||||||
|
|
||||||
public GameCategory Serialize(DatabaseContext database)
|
public virtual Task<GameCategory> Serialize(DatabaseContext database, GameTokenEntity token, SlotQueryBuilder queryBuilder, int numResults = 1) =>
|
||||||
{
|
Task.FromResult(GameCategory.CreateFromEntity(this, new GenericSerializableList(new List<ILbpSerializable>(), 0, 0)));
|
||||||
List<SlotBase> slots = new();
|
|
||||||
SlotEntity? previewSlot = this.GetPreviewSlot(database);
|
|
||||||
if (previewSlot != null)
|
|
||||||
slots.Add(SlotBase.CreateFromEntity(previewSlot, GameVersion.LittleBigPlanet3, -1));
|
|
||||||
|
|
||||||
int totalSlots = this.GetTotalSlots(database);
|
|
||||||
return GameCategory.CreateFromEntity(this, new GenericSlotResponse(slots, totalSlots, 2));
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -27,4 +27,5 @@ public enum LogArea
|
||||||
Deserialization,
|
Deserialization,
|
||||||
Email,
|
Email,
|
||||||
Serialization,
|
Serialization,
|
||||||
|
Synchronization,
|
||||||
}
|
}
|
|
@ -8,4 +8,5 @@ public class SlotMetadata
|
||||||
public double RatingLbp1 { get; init; }
|
public double RatingLbp1 { get; init; }
|
||||||
public int ThumbsUp { get; init; }
|
public int ThumbsUp { get; init; }
|
||||||
public int Hearts { get; init; }
|
public int Hearts { get; init; }
|
||||||
|
public bool Played { get; set; }
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@ public class CategoryListResponse : ILbpSerializable
|
||||||
{
|
{
|
||||||
public CategoryListResponse() { }
|
public CategoryListResponse() { }
|
||||||
|
|
||||||
public CategoryListResponse(List<GameCategory> categories, int total, int hint, int hintStart)
|
public CategoryListResponse(List<GameCategory> categories, int total, string hint, int hintStart)
|
||||||
{
|
{
|
||||||
this.Categories = categories;
|
this.Categories = categories;
|
||||||
this.Total = total;
|
this.Total = total;
|
||||||
|
@ -20,7 +20,7 @@ public class CategoryListResponse : ILbpSerializable
|
||||||
public int Total { get; set; }
|
public int Total { get; set; }
|
||||||
|
|
||||||
[XmlAttribute("hint")]
|
[XmlAttribute("hint")]
|
||||||
public int Hint { get; set; }
|
public string Hint { get; set; } = "";
|
||||||
|
|
||||||
[XmlAttribute("hint_start")]
|
[XmlAttribute("hint_start")]
|
||||||
public int HintStart { get; set; }
|
public int HintStart { get; set; }
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Xml.Serialization;
|
using System.ComponentModel;
|
||||||
|
using System.Xml.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
namespace LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||||
|
@ -18,19 +19,32 @@ public class GameCategory : ILbpSerializable
|
||||||
[XmlElement("icon")]
|
[XmlElement("icon")]
|
||||||
public string Icon { get; set; }
|
public string Icon { get; set; }
|
||||||
|
|
||||||
[XmlElement("results")]
|
[DefaultValue("")]
|
||||||
public GenericSlotResponse Results { get; set; }
|
[XmlArray("sorts")]
|
||||||
|
[XmlArrayItem("sort")]
|
||||||
|
public string[] Sorts { get; set; }
|
||||||
|
|
||||||
public static GameCategory CreateFromEntity(Category category, GenericSlotResponse results) =>
|
[DefaultValue("")]
|
||||||
|
[XmlArray("types")]
|
||||||
|
[XmlArrayItem("type")]
|
||||||
|
public string[] Types { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("tag")]
|
||||||
|
public string Tag { get; set; }
|
||||||
|
|
||||||
|
[XmlElement("results")]
|
||||||
|
public GenericSerializableList Results { get; set; }
|
||||||
|
|
||||||
|
public static GameCategory CreateFromEntity(Category category, GenericSerializableList results) =>
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
Name = category.Name,
|
Name = category.Name,
|
||||||
Description = category.Description,
|
Description = category.Description,
|
||||||
Icon = category.IconHash,
|
Icon = category.IconHash,
|
||||||
Url = category.IngameEndpoint,
|
Url = category.IngameEndpoint,
|
||||||
|
Sorts = category.Sorts,
|
||||||
|
Types = category.Types,
|
||||||
|
Tag = category.Tag,
|
||||||
Results = results,
|
Results = results,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -33,10 +33,12 @@ public class GameDeveloperSlot : SlotBase, INeedsPreparationForSerialization
|
||||||
public async Task PrepareSerialization(DatabaseContext database)
|
public async Task PrepareSerialization(DatabaseContext database)
|
||||||
{
|
{
|
||||||
var stats = await database.Slots.Select(_ => new
|
var stats = await database.Slots.Select(_ => new
|
||||||
{
|
{
|
||||||
CommentCount = database.Comments.Count(c => c.TargetId == this.SlotId && c.Type == CommentType.Level),
|
CommentCount = database.Comments.Count(c => c.TargetId == this.SlotId && c.Type == CommentType.Level),
|
||||||
PhotoCount = database.Photos.Count(p => p.SlotId == this.SlotId),
|
PhotoCount = database.Photos.Count(p => p.SlotId == this.SlotId),
|
||||||
}).FirstAsync();
|
})
|
||||||
|
.OrderBy(_ => 1)
|
||||||
|
.FirstAsync();
|
||||||
ReflectionHelper.CopyAllFields(stats, this);
|
ReflectionHelper.CopyAllFields(stats, this);
|
||||||
this.PlayerCount = RoomHelper.Rooms
|
this.PlayerCount = RoomHelper.Rooms
|
||||||
.Where(r => r.Slot.SlotType == SlotType.Developer && r.Slot.SlotId == this.InternalSlotId)
|
.Where(r => r.Slot.SlotType == SlotType.Developer && r.Slot.SlotId == this.InternalSlotId)
|
||||||
|
|
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