Reading List Polish (#1879)
* Use Reading Order to count epub pages rather than raw HTML files. * Send email on background thread for initial invite flow. * Reorder default writing style for new users so Horizontal is default * Changed reading activity to use average hours read rather than events to bring more meaningful data. * added ability to start reading incognito from the top of series detail, needs a bit of styling help though. * Refactored extensions out into their own package, added new fields for reading list to cover total run, cbl import now takes those dates and overrides on import. Replaced many instances of numbers to be comma separated. * Added ability to edit reading list run start and end year/month. Refactored some code for valid month/year into a helper method. * Added a way to see the reading list's release years. * Added some merged image code, but had to remove due to cover dimensions not fixed. * tweaked style for accessibility mode on reading list items * Tweaked css for non virtualized and virtualized containers * Fixed release updates failing * Commented out the merge code. * Typo on words read per year * Fixed unit tests * Fixed virtualized scroll * Cleanup CSS
This commit is contained in:
parent
266f302823
commit
fd6ee42f5f
60 changed files with 2847 additions and 430 deletions
|
@ -1,6 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using API.Entities;
|
||||
using API.Helpers;
|
||||
using API.Parser;
|
||||
|
||||
namespace API.Extensions;
|
||||
|
@ -39,6 +40,6 @@ public static class ChapterListExtensions
|
|||
/// <returns></returns>
|
||||
public static int MinimumReleaseYear(this IList<Chapter> chapters)
|
||||
{
|
||||
return chapters.Select(v => v.ReleaseDate.Year).Where(y => y >= 1000).DefaultIfEmpty().Min();
|
||||
return chapters.Select(v => v.ReleaseDate.Year).Where(y => NumberHelper.IsValidYear(y)).DefaultIfEmpty().Min();
|
||||
}
|
||||
}
|
||||
|
|
148
API/Extensions/QueryExtensions/IncludesExtensions.cs
Normal file
148
API/Extensions/QueryExtensions/IncludesExtensions.cs
Normal file
|
@ -0,0 +1,148 @@
|
|||
using System.Linq;
|
||||
using API.Data.Repositories;
|
||||
using API.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Extensions.QueryExtensions;
|
||||
|
||||
/// <summary>
|
||||
/// All extensions against IQueryable that enables the dynamic including based on bitwise flag pattern
|
||||
/// </summary>
|
||||
public static class IncludesExtensions
|
||||
{
|
||||
public static IQueryable<CollectionTag> Includes(this IQueryable<CollectionTag> queryable,
|
||||
CollectionTagIncludes includes)
|
||||
{
|
||||
if (includes.HasFlag(CollectionTagIncludes.SeriesMetadata))
|
||||
{
|
||||
queryable = queryable.Include(c => c.SeriesMetadatas);
|
||||
}
|
||||
|
||||
return queryable.AsSplitQuery();
|
||||
}
|
||||
|
||||
public static IQueryable<Chapter> Includes(this IQueryable<Chapter> queryable,
|
||||
ChapterIncludes includes)
|
||||
{
|
||||
if (includes.HasFlag(ChapterIncludes.Volumes))
|
||||
{
|
||||
queryable = queryable.Include(v => v.Volume);
|
||||
}
|
||||
|
||||
if (includes.HasFlag(ChapterIncludes.Files))
|
||||
{
|
||||
queryable = queryable
|
||||
.Include(c => c.Files);
|
||||
}
|
||||
|
||||
|
||||
return queryable.AsSplitQuery();
|
||||
}
|
||||
|
||||
public static IQueryable<Series> Includes(this IQueryable<Series> query,
|
||||
SeriesIncludes includeFlags)
|
||||
{
|
||||
if (includeFlags.HasFlag(SeriesIncludes.Library))
|
||||
{
|
||||
query = query.Include(u => u.Library);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(SeriesIncludes.Volumes))
|
||||
{
|
||||
query = query.Include(s => s.Volumes);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(SeriesIncludes.Chapters))
|
||||
{
|
||||
query = query
|
||||
.Include(s => s.Volumes)
|
||||
.ThenInclude(v => v.Chapters);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(SeriesIncludes.Related))
|
||||
{
|
||||
query = query.Include(s => s.Relations)
|
||||
.ThenInclude(r => r.TargetSeries)
|
||||
.Include(s => s.RelationOf);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(SeriesIncludes.Metadata))
|
||||
{
|
||||
query = query.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.CollectionTags.OrderBy(g => g.NormalizedTitle))
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.Genres.OrderBy(g => g.NormalizedTitle))
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.People)
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.Tags.OrderBy(g => g.NormalizedTitle));
|
||||
}
|
||||
|
||||
|
||||
return query.AsSplitQuery();
|
||||
}
|
||||
|
||||
public static IQueryable<AppUser> Includes(this IQueryable<AppUser> query, AppUserIncludes includeFlags)
|
||||
{
|
||||
if (includeFlags.HasFlag(AppUserIncludes.Bookmarks))
|
||||
{
|
||||
query = query.Include(u => u.Bookmarks);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.Progress))
|
||||
{
|
||||
query = query.Include(u => u.Progresses);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.ReadingLists))
|
||||
{
|
||||
query = query.Include(u => u.ReadingLists);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.ReadingListsWithItems))
|
||||
{
|
||||
query = query.Include(u => u.ReadingLists)
|
||||
.ThenInclude(r => r.Items);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.Ratings))
|
||||
{
|
||||
query = query.Include(u => u.Ratings);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.UserPreferences))
|
||||
{
|
||||
query = query.Include(u => u.UserPreferences);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.WantToRead))
|
||||
{
|
||||
query = query.Include(u => u.WantToRead);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.Devices))
|
||||
{
|
||||
query = query.Include(u => u.Devices);
|
||||
}
|
||||
|
||||
return query.AsSplitQuery();
|
||||
}
|
||||
|
||||
public static IQueryable<ReadingList> Includes(this IQueryable<ReadingList> queryable,
|
||||
ReadingListIncludes includes)
|
||||
{
|
||||
if (includes.HasFlag(ReadingListIncludes.Items))
|
||||
{
|
||||
queryable = queryable.Include(r => r.Items.OrderBy(item => item.Order));
|
||||
}
|
||||
|
||||
if (includes.HasFlag(ReadingListIncludes.ItemChapter))
|
||||
{
|
||||
queryable = queryable
|
||||
.Include(r => r.Items.OrderBy(item => item.Order))
|
||||
.ThenInclude(ri => ri.Chapter);
|
||||
}
|
||||
|
||||
return queryable.AsSplitQuery();
|
||||
}
|
||||
}
|
92
API/Extensions/QueryExtensions/QueryableExtensions.cs
Normal file
92
API/Extensions/QueryExtensions/QueryableExtensions.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data.Misc;
|
||||
using API.Data.Repositories;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Extensions.QueryExtensions;
|
||||
|
||||
public static class QueryableExtensions
|
||||
{
|
||||
public static Task<AgeRestriction> GetUserAgeRestriction(this DbSet<AppUser> queryable, int userId)
|
||||
{
|
||||
if (userId < 1)
|
||||
{
|
||||
return Task.FromResult(new AgeRestriction()
|
||||
{
|
||||
AgeRating = AgeRating.NotApplicable,
|
||||
IncludeUnknowns = true
|
||||
});
|
||||
}
|
||||
return queryable
|
||||
.AsNoTracking()
|
||||
.Where(u => u.Id == userId)
|
||||
.Select(u =>
|
||||
new AgeRestriction(){
|
||||
AgeRating = u.AgeRestriction,
|
||||
IncludeUnknowns = u.AgeRestrictionIncludeUnknowns
|
||||
})
|
||||
.SingleAsync();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Applies restriction based on if the Library has restrictions (like include in search)
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<Library> IsRestricted(this IQueryable<Library> query, QueryContext context)
|
||||
{
|
||||
if (context.HasFlag(QueryContext.None)) return query;
|
||||
|
||||
if (context.HasFlag(QueryContext.Dashboard))
|
||||
{
|
||||
query = query.Where(l => l.IncludeInDashboard);
|
||||
}
|
||||
|
||||
if (context.HasFlag(QueryContext.Recommended))
|
||||
{
|
||||
query = query.Where(l => l.IncludeInRecommended);
|
||||
}
|
||||
|
||||
if (context.HasFlag(QueryContext.Search))
|
||||
{
|
||||
query = query.Where(l => l.IncludeInSearch);
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all libraries for a given user
|
||||
/// </summary>
|
||||
/// <param name="library"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="queryContext"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<int> GetUserLibraries(this IQueryable<Library> library, int userId, QueryContext queryContext = QueryContext.None)
|
||||
{
|
||||
return library
|
||||
.Include(l => l.AppUsers)
|
||||
.Where(lib => lib.AppUsers.Any(user => user.Id == userId))
|
||||
.IsRestricted(queryContext)
|
||||
.AsNoTracking()
|
||||
.AsSplitQuery()
|
||||
.Select(lib => lib.Id);
|
||||
}
|
||||
|
||||
public static IEnumerable<DateTime> Range(this DateTime startDate, int numberOfDays) =>
|
||||
Enumerable.Range(0, numberOfDays).Select(e => startDate.AddDays(e));
|
||||
|
||||
public static IQueryable<T> WhereIf<T>(this IQueryable<T> queryable, bool condition,
|
||||
Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
return condition ? queryable.Where(predicate) : queryable;
|
||||
}
|
||||
}
|
96
API/Extensions/QueryExtensions/RestrictByAgeExtensions.cs
Normal file
96
API/Extensions/QueryExtensions/RestrictByAgeExtensions.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using System.Linq;
|
||||
using API.Data.Misc;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
|
||||
namespace API.Extensions.QueryExtensions;
|
||||
|
||||
/// <summary>
|
||||
/// Responsible for restricting Entities based on an AgeRestriction
|
||||
/// </summary>
|
||||
public static class RestrictByAgeExtensions
|
||||
{
|
||||
public static IQueryable<Series> RestrictAgainstAgeRestriction(this IQueryable<Series> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
var q = queryable.Where(s => s.Metadata.AgeRating <= restriction.AgeRating);
|
||||
|
||||
if (!restriction.IncludeUnknowns)
|
||||
{
|
||||
return q.Where(s => s.Metadata.AgeRating != AgeRating.Unknown);
|
||||
}
|
||||
|
||||
//q.WhereIf(!restriction.IncludeUnknowns, s => s.Metadata.AgeRating != AgeRating.Unknown);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
public static IQueryable<CollectionTag> RestrictAgainstAgeRestriction(this IQueryable<CollectionTag> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
}
|
||||
|
||||
public static IQueryable<Genre> RestrictAgainstAgeRestriction(this IQueryable<Genre> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
}
|
||||
|
||||
public static IQueryable<Tag> RestrictAgainstAgeRestriction(this IQueryable<Tag> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
}
|
||||
|
||||
public static IQueryable<Person> RestrictAgainstAgeRestriction(this IQueryable<Person> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
}
|
||||
|
||||
public static IQueryable<ReadingList> RestrictAgainstAgeRestriction(this IQueryable<ReadingList> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
var q = queryable.Where(rl => rl.AgeRating <= restriction.AgeRating);
|
||||
|
||||
if (!restriction.IncludeUnknowns)
|
||||
{
|
||||
return q.Where(rl => rl.AgeRating != AgeRating.Unknown);
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
}
|
|
@ -1,290 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data.Misc;
|
||||
using API.Data.Repositories;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Extensions;
|
||||
|
||||
public static class QueryableExtensions
|
||||
{
|
||||
public static IQueryable<Series> RestrictAgainstAgeRestriction(this IQueryable<Series> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
var q = queryable.Where(s => s.Metadata.AgeRating <= restriction.AgeRating);
|
||||
if (!restriction.IncludeUnknowns)
|
||||
{
|
||||
return q.Where(s => s.Metadata.AgeRating != AgeRating.Unknown);
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
public static IQueryable<CollectionTag> RestrictAgainstAgeRestriction(this IQueryable<CollectionTag> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
}
|
||||
|
||||
public static IQueryable<Genre> RestrictAgainstAgeRestriction(this IQueryable<Genre> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
}
|
||||
|
||||
public static IQueryable<Tag> RestrictAgainstAgeRestriction(this IQueryable<Tag> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
}
|
||||
|
||||
public static IQueryable<Person> RestrictAgainstAgeRestriction(this IQueryable<Person> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
}
|
||||
|
||||
public static IQueryable<ReadingList> RestrictAgainstAgeRestriction(this IQueryable<ReadingList> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
var q = queryable.Where(rl => rl.AgeRating <= restriction.AgeRating);
|
||||
|
||||
if (!restriction.IncludeUnknowns)
|
||||
{
|
||||
return q.Where(rl => rl.AgeRating != AgeRating.Unknown);
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
public static Task<AgeRestriction> GetUserAgeRestriction(this DbSet<AppUser> queryable, int userId)
|
||||
{
|
||||
if (userId < 1)
|
||||
{
|
||||
return Task.FromResult(new AgeRestriction()
|
||||
{
|
||||
AgeRating = AgeRating.NotApplicable,
|
||||
IncludeUnknowns = true
|
||||
});
|
||||
}
|
||||
return queryable
|
||||
.AsNoTracking()
|
||||
.Where(u => u.Id == userId)
|
||||
.Select(u =>
|
||||
new AgeRestriction(){
|
||||
AgeRating = u.AgeRestriction,
|
||||
IncludeUnknowns = u.AgeRestrictionIncludeUnknowns
|
||||
})
|
||||
.SingleAsync();
|
||||
}
|
||||
|
||||
public static IQueryable<CollectionTag> Includes(this IQueryable<CollectionTag> queryable,
|
||||
CollectionTagIncludes includes)
|
||||
{
|
||||
if (includes.HasFlag(CollectionTagIncludes.SeriesMetadata))
|
||||
{
|
||||
queryable = queryable.Include(c => c.SeriesMetadatas);
|
||||
}
|
||||
|
||||
return queryable.AsSplitQuery();
|
||||
}
|
||||
|
||||
public static IQueryable<Chapter> Includes(this IQueryable<Chapter> queryable,
|
||||
ChapterIncludes includes)
|
||||
{
|
||||
if (includes.HasFlag(ChapterIncludes.Volumes))
|
||||
{
|
||||
queryable = queryable.Include(v => v.Volume);
|
||||
}
|
||||
|
||||
if (includes.HasFlag(ChapterIncludes.Files))
|
||||
{
|
||||
queryable = queryable
|
||||
.Include(c => c.Files);
|
||||
}
|
||||
|
||||
|
||||
return queryable.AsSplitQuery();
|
||||
}
|
||||
|
||||
public static IQueryable<Series> Includes(this IQueryable<Series> query,
|
||||
SeriesIncludes includeFlags)
|
||||
{
|
||||
if (includeFlags.HasFlag(SeriesIncludes.Library))
|
||||
{
|
||||
query = query.Include(u => u.Library);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(SeriesIncludes.Volumes))
|
||||
{
|
||||
query = query.Include(s => s.Volumes);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(SeriesIncludes.Chapters))
|
||||
{
|
||||
query = query
|
||||
.Include(s => s.Volumes)
|
||||
.ThenInclude(v => v.Chapters);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(SeriesIncludes.Related))
|
||||
{
|
||||
query = query.Include(s => s.Relations)
|
||||
.ThenInclude(r => r.TargetSeries)
|
||||
.Include(s => s.RelationOf);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(SeriesIncludes.Metadata))
|
||||
{
|
||||
query = query.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.CollectionTags.OrderBy(g => g.NormalizedTitle))
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.Genres.OrderBy(g => g.NormalizedTitle))
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.People)
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.Tags.OrderBy(g => g.NormalizedTitle));
|
||||
}
|
||||
|
||||
|
||||
return query.AsSplitQuery();
|
||||
}
|
||||
|
||||
public static IQueryable<AppUser> Includes(this IQueryable<AppUser> query, AppUserIncludes includeFlags)
|
||||
{
|
||||
if (includeFlags.HasFlag(AppUserIncludes.Bookmarks))
|
||||
{
|
||||
query = query.Include(u => u.Bookmarks);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.Progress))
|
||||
{
|
||||
query = query.Include(u => u.Progresses);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.ReadingLists))
|
||||
{
|
||||
query = query.Include(u => u.ReadingLists);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.ReadingListsWithItems))
|
||||
{
|
||||
query = query.Include(u => u.ReadingLists)
|
||||
.ThenInclude(r => r.Items);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.Ratings))
|
||||
{
|
||||
query = query.Include(u => u.Ratings);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.UserPreferences))
|
||||
{
|
||||
query = query.Include(u => u.UserPreferences);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.WantToRead))
|
||||
{
|
||||
query = query.Include(u => u.WantToRead);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.Devices))
|
||||
{
|
||||
query = query.Include(u => u.Devices);
|
||||
}
|
||||
|
||||
return query.AsSplitQuery();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies restriction based on if the Library has restrictions (like include in search)
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<Library> IsRestricted(this IQueryable<Library> query, QueryContext context)
|
||||
{
|
||||
if (context.HasFlag(QueryContext.None)) return query;
|
||||
|
||||
if (context.HasFlag(QueryContext.Dashboard))
|
||||
{
|
||||
query = query.Where(l => l.IncludeInDashboard);
|
||||
}
|
||||
|
||||
if (context.HasFlag(QueryContext.Recommended))
|
||||
{
|
||||
query = query.Where(l => l.IncludeInRecommended);
|
||||
}
|
||||
|
||||
if (context.HasFlag(QueryContext.Search))
|
||||
{
|
||||
query = query.Where(l => l.IncludeInSearch);
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all libraries for a given user
|
||||
/// </summary>
|
||||
/// <param name="library"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="queryContext"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<int> GetUserLibraries(this IQueryable<Library> library, int userId, QueryContext queryContext = QueryContext.None)
|
||||
{
|
||||
return library
|
||||
.Include(l => l.AppUsers)
|
||||
.Where(lib => lib.AppUsers.Any(user => user.Id == userId))
|
||||
.IsRestricted(queryContext)
|
||||
.AsNoTracking()
|
||||
.AsSplitQuery()
|
||||
.Select(lib => lib.Id);
|
||||
}
|
||||
|
||||
public static IEnumerable<DateTime> Range(this DateTime startDate, int numberOfDays) =>
|
||||
Enumerable.Range(0, numberOfDays).Select(e => startDate.AddDays(e));
|
||||
|
||||
public static IQueryable<T> WhereIf<T>(this IQueryable<T> queryable, bool condition,
|
||||
Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
return condition ? queryable.Where(predicate) : queryable;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue