mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-07-14 09:11:28 +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,14 +1,16 @@
|
|||
#nullable enable
|
||||
using LBPUnion.ProjectLighthouse.Database;
|
||||
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.Token;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using LBPUnion.ProjectLighthouse.Types.Filter;
|
||||
using LBPUnion.ProjectLighthouse.Types.Serialization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
|
||||
|
||||
|
@ -25,102 +27,29 @@ public class SearchController : ControllerBase
|
|||
}
|
||||
|
||||
[HttpGet("searchLBP3")]
|
||||
public Task<IActionResult> SearchSlotsLBP3([FromQuery] int pageSize, [FromQuery] int pageStart, [FromQuery] string textFilter,
|
||||
[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)
|
||||
=> this.SearchSlots(textFilter, pageSize, pageStart, "results", false, players+1, labelFilter0, labelFilter1, labelFilter2, labelFilter3, labelFilter4, move, adventure);
|
||||
public Task<IActionResult> SearchSlotsLBP3([FromQuery] string textFilter)
|
||||
=> this.SearchSlots(textFilter, "results");
|
||||
|
||||
[HttpGet("search")]
|
||||
public async Task<IActionResult> SearchSlots(
|
||||
[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
|
||||
)
|
||||
public async Task<IActionResult> SearchSlots([FromQuery] string query, string? keyName = "slots")
|
||||
{
|
||||
GameTokenEntity token = this.GetToken();
|
||||
|
||||
if (pageSize <= 0) return this.BadRequest();
|
||||
PaginationData pageData = this.Request.GetPaginationData();
|
||||
|
||||
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)
|
||||
.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
|
||||
pageData.TotalElements = await this.database.Slots.Where(queryBuilder.Build()).CountAsync();
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (string keyword in keywords)
|
||||
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<SlotBase> slots = await this.database.Slots.Include(s => s.Creator)
|
||||
.GetSlots(token, queryBuilder, pageData, new SlotSortBuilder<SlotEntity>());
|
||||
|
||||
List<SlotEntity> slots = (await dbQuery.Skip(Math.Max(0, pageStart - 1))
|
||||
.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));
|
||||
return this.Ok(new GenericSlotResponse(keyName, slots, pageData));
|
||||
}
|
||||
|
||||
// /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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue