Simplify filters and make cross control slots not show by default (#782)

* Simplify filters and make cross control slots not show by default
Also sort author levels by oldest levels first rather than newest levels first.

* Fix unit test expecting slots to sorted by timestamp descending

* Remove errant whitespace
This commit is contained in:
Josh 2023-06-05 17:53:41 -05:00 committed by GitHub
parent 2a85b6a136
commit a69d94054b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 114 additions and 58 deletions

View file

@ -49,7 +49,9 @@ public class SlotsController : ControllerBase
SlotQueryBuilder queryBuilder = this.FilterFromRequest(token).AddFilter(new CreatorFilter(targetUserId));
SlotSortBuilder<SlotEntity> sortBuilder = new SlotSortBuilder<SlotEntity>().AddSort(new FirstUploadedSort());
SlotSortBuilder<SlotEntity> sortBuilder = new SlotSortBuilder<SlotEntity>()
.AddSort(new FirstUploadedSort())
.SortDescending(false);
List<SlotBase> slots = await this.database.GetSlots(token, queryBuilder, pageData, sortBuilder);

View file

@ -92,8 +92,8 @@ public static class ControllerExtensions
}
}
if (bool.TryParse(controller.Request.Query["crosscontrol"], out bool crossControl) && crossControl)
queryBuilder.AddFilter(new CrossControlFilter());
bool _ = bool.TryParse(controller.Request.Query["crosscontrol"], out bool showCrossControl);
if (showCrossControl) queryBuilder.AddFilter(new CrossControlFilter());
GameVersion targetVersion = token.GameVersion;
@ -171,6 +171,9 @@ public static class ControllerExtensions
if (token.GameVersion != GameVersion.LittleBigPlanet1)
queryBuilder.AddFilter(new ExcludeLBP1OnlyFilter(token.UserId, token.GameVersion));
if (!queryBuilder.GetFilters(typeof(CrossControlFilter)).Any())
queryBuilder.AddFilter(new ExcludeCrossControlFilter());
queryBuilder.AddFilter(new SubLevelFilter(token.UserId));
queryBuilder.AddFilter(new HiddenSlotFilter());
queryBuilder.AddFilter(new SlotTypeFilter(SlotType.User));

View file

@ -271,6 +271,52 @@ public class ControllerExtensionTests
Assert.NotEmpty(queryBuilder.GetFilters(typeof(CrossControlFilter)));
}
[Fact]
public void FilterFromRequest_ShouldAddExcludeCrossControlFilter_WhenCrossControlNotTrue()
{
GameTokenEntity token = MockHelper.GetUnitTestToken();
token.GameVersion = GameVersion.LittleBigPlanet2;
SlotsController controller = new(null!)
{
ControllerContext =
{
HttpContext = new DefaultHttpContext
{
Request =
{
QueryString = new QueryString("?crosscontrol=false"),
},
},
},
};
SlotQueryBuilder queryBuilder = controller.FilterFromRequest(token);
Assert.NotEmpty(queryBuilder.GetFilters(typeof(ExcludeCrossControlFilter)));
}
[Fact]
public void FilterFromRequest_ShouldAddExcludeCrossControlFilter_WhenCrossControlMissing()
{
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(ExcludeCrossControlFilter)));
}
[Fact]
public void FilterFromRequest_ShouldAddAdventureFilter_WhenAdventureEqualsAllMust()
{

View file

@ -77,7 +77,7 @@ public class SlotControllerTests
}
[Fact]
public async Task SlotsBy_ResultsAreOrderedByFirstUploadedTimestampDescending()
public async Task SlotsBy_ResultsAreOrderedByFirstUploadedTimestampAscending()
{
List<SlotEntity> slots = new()
{
@ -119,9 +119,9 @@ public class SlotControllerTests
IActionResult result = await slotsController.SlotsBy("bytest");
const int expectedElements = 3;
const int expectedFirstSlotId = 1;
const int expectedFirstSlotId = 2;
const int expectedSecondSlotId = 3;
const int expectedThirdSlotId = 2;
const int expectedThirdSlotId = 1;
GenericSlotResponse slotResponse = result.CastTo<OkObjectResult, GenericSlotResponse>();
Assert.Equal(expectedElements, slotResponse.Slots.Count);

View file

@ -208,6 +208,34 @@ public class FilterTests
Assert.True(adventureFunc(slot));
}
[Fact]
public void ExcludeCrossControlFilter_ShouldAccept_WhenNotCrossControl()
{
ExcludeCrossControlFilter crossControlFilter = new();
Func<SlotEntity, bool> crossControlFunc = crossControlFilter.GetPredicate().Compile();
SlotEntity slot = new()
{
CrossControllerRequired = false,
};
Assert.True(crossControlFunc(slot));
}
[Fact]
public void ExcludeCrossControlFilter_ShouldReject_WhenCrossControl()
{
ExcludeCrossControlFilter crossControlFilter = new();
Func<SlotEntity, bool> crossControlFunc = crossControlFilter.GetPredicate().Compile();
SlotEntity slot = new()
{
CrossControllerRequired = true,
};
Assert.False(crossControlFunc(slot));
}
[Fact]
public void ExcludeLBP1OnlyFilter_ShouldReject_WhenLbp1Only_AndTokenNotLbp1_AndNotCreator()
{

View file

@ -1,6 +1,5 @@
using System;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
@ -8,6 +7,5 @@ namespace LBPUnion.ProjectLighthouse.Filter.Filters;
public class AdventureFilter : ISlotFilter
{
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
PredicateExtensions.True<SlotEntity>().And(s => s.IsAdventurePlanet);
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => s.IsAdventurePlanet;
}

View file

@ -1,6 +1,5 @@
using System;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
@ -15,6 +14,5 @@ public class CreatorFilter : ISlotFilter
this.creatorId = creatorId;
}
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
PredicateExtensions.True<SlotEntity>().And(s => s.CreatorId == this.creatorId);
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => s.CreatorId == this.creatorId;
}

View file

@ -1,6 +1,5 @@
using System;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
@ -8,6 +7,5 @@ namespace LBPUnion.ProjectLighthouse.Filter.Filters;
public class CrossControlFilter : ISlotFilter
{
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
PredicateExtensions.True<SlotEntity>().And(s => s.CrossControllerRequired);
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => s.CrossControllerRequired;
}

View file

@ -1,6 +1,5 @@
using System;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
@ -8,6 +7,5 @@ namespace LBPUnion.ProjectLighthouse.Filter.Filters;
public class ExcludeAdventureFilter : ISlotFilter
{
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
PredicateExtensions.True<SlotEntity>().And(s => !s.IsAdventurePlanet);
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => !s.IsAdventurePlanet;
}

View file

@ -0,0 +1,11 @@
using System;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
namespace LBPUnion.ProjectLighthouse.Filter.Filters;
public class ExcludeCrossControlFilter : ISlotFilter
{
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => !s.CrossControllerRequired;
}

View file

@ -1,6 +1,5 @@
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;
@ -18,10 +17,6 @@ public class ExcludeLBP1OnlyFilter : ISlotFilter
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;
}
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
s => !s.Lbp1Only || s.CreatorId == this.userId || this.targetGameVersion == GameVersion.LittleBigPlanet1;
}

View file

@ -1,6 +1,5 @@
using System;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
@ -8,6 +7,5 @@ namespace LBPUnion.ProjectLighthouse.Filter.Filters;
public class ExcludeMovePackFilter : ISlotFilter
{
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
PredicateExtensions.True<SlotEntity>().And(s => !s.MoveRequired);
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => !s.MoveRequired;
}

View file

@ -1,6 +1,5 @@
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;
@ -18,12 +17,9 @@ public class GameVersionFilter : ISlotFilter
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;
}
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
this.matchExactly ||
this.targetVersion is GameVersion.LittleBigPlanetVita or GameVersion.LittleBigPlanetPSP or GameVersion.Unknown
? s => s.GameVersion == this.targetVersion
: s => s.GameVersion <= this.targetVersion;
}

View file

@ -1,6 +1,5 @@
using System;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
@ -8,6 +7,5 @@ namespace LBPUnion.ProjectLighthouse.Filter.Filters;
public class HiddenSlotFilter : ISlotFilter
{
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
PredicateExtensions.True<SlotEntity>().And(s => !s.Hidden);
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => !s.Hidden;
}

View file

@ -1,6 +1,5 @@
using System;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
@ -8,6 +7,5 @@ namespace LBPUnion.ProjectLighthouse.Filter.Filters;
public class MovePackFilter : ISlotFilter
{
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
PredicateExtensions.True<SlotEntity>().And(s => s.MoveRequired);
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => s.MoveRequired;
}

View file

@ -1,7 +1,6 @@
using System;
using System.Linq;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
@ -16,8 +15,5 @@ public class ResultTypeFilter : ISlotFilter
this.results = results;
}
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
this.results.Contains("slot")
? PredicateExtensions.True<SlotEntity>()
: PredicateExtensions.False<SlotEntity>();
public Expression<Func<SlotEntity, bool>> GetPredicate() => this.results.Contains("slot") ? s => true : s => false;
}

View file

@ -1,6 +1,5 @@
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;
@ -16,6 +15,5 @@ public class SlotTypeFilter : ISlotFilter
this.slotType = slotType;
}
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
PredicateExtensions.True<SlotEntity>().And(s => s.Type == this.slotType);
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => s.Type == this.slotType;
}

View file

@ -1,6 +1,5 @@
using System;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
@ -15,6 +14,5 @@ public class SubLevelFilter : ISlotFilter
this.userId = userId;
}
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
PredicateExtensions.True<SlotEntity>().And(s => !s.SubLevel || s.CreatorId == this.userId);
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => !s.SubLevel || s.CreatorId == this.userId;
}

View file

@ -1,6 +1,5 @@
using System;
using System.Linq.Expressions;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Filter;
@ -8,6 +7,5 @@ namespace LBPUnion.ProjectLighthouse.Filter.Filters;
public class TeamPickFilter : ISlotFilter
{
public Expression<Func<SlotEntity, bool>> GetPredicate() =>
PredicateExtensions.True<SlotEntity>().And(s => s.TeamPick);
public Expression<Func<SlotEntity, bool>> GetPredicate() => s => s.TeamPick;
}

View file

@ -10,7 +10,6 @@ namespace LBPUnion.ProjectLighthouse.Helpers;
public static class LastContactHelper
{
public static async Task SetLastContact(DatabaseContext database, UserEntity user, GameVersion gameVersion, Platform platform)
{
LastContactEntity? lastContact = await database.LastContacts.Where(l => l.UserId == user.UserId).FirstOrDefaultAsync();