Merge branch 'develop' into feature/oidc
This commit is contained in:
commit
465723fedf
358 changed files with 34968 additions and 5203 deletions
|
@ -54,6 +54,8 @@ public static class ApplicationServiceExtensions
|
|||
services.AddScoped<IStreamService, StreamService>();
|
||||
services.AddScoped<IRatingService, RatingService>();
|
||||
services.AddScoped<IPersonService, PersonService>();
|
||||
services.AddScoped<IReadingProfileService, ReadingProfileService>();
|
||||
services.AddScoped<IKoreaderService, KoreaderService>();
|
||||
|
||||
services.AddScoped<IScannerService, ScannerService>();
|
||||
services.AddScoped<IProcessSeries, ProcessSeries>();
|
||||
|
@ -74,6 +76,7 @@ public static class ApplicationServiceExtensions
|
|||
services.AddScoped<ISettingsService, SettingsService>();
|
||||
|
||||
|
||||
services.AddScoped<IKavitaPlusApiService, KavitaPlusApiService>();
|
||||
services.AddScoped<IScrobblingService, ScrobblingService>();
|
||||
services.AddScoped<ILicenseService, LicenseService>();
|
||||
services.AddScoped<IExternalMetadataService, ExternalMetadataService>();
|
||||
|
|
|
@ -3,7 +3,9 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using API.Data.Misc;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
|
||||
namespace API.Extensions;
|
||||
#nullable enable
|
||||
|
@ -42,4 +44,28 @@ public static class EnumerableExtensions
|
|||
|
||||
return q;
|
||||
}
|
||||
|
||||
public static IEnumerable<SeriesMetadata> RestrictAgainstAgeRestriction(this IEnumerable<SeriesMetadata> items, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return items;
|
||||
var q = items.Where(s => s.AgeRating <= restriction.AgeRating);
|
||||
if (!restriction.IncludeUnknowns)
|
||||
{
|
||||
return q.Where(s => s.AgeRating != AgeRating.Unknown);
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
public static IEnumerable<Chapter> RestrictAgainstAgeRestriction(this IEnumerable<Chapter> items, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return items;
|
||||
var q = items.Where(s => s.AgeRating <= restriction.AgeRating);
|
||||
if (!restriction.IncludeUnknowns)
|
||||
{
|
||||
return q.Where(s => s.AgeRating != AgeRating.Unknown);
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
|
21
API/Extensions/IHasKPlusMetadataExtensions.cs
Normal file
21
API/Extensions/IHasKPlusMetadataExtensions.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using API.Entities.Interfaces;
|
||||
using API.Entities.MetadataMatching;
|
||||
|
||||
namespace API.Extensions;
|
||||
|
||||
public static class IHasKPlusMetadataExtensions
|
||||
{
|
||||
|
||||
public static bool HasSetKPlusMetadata(this IHasKPlusMetadata hasKPlusMetadata, MetadataSettingField field)
|
||||
{
|
||||
return hasKPlusMetadata.KPlusOverrides.Contains(field);
|
||||
}
|
||||
|
||||
public static void AddKPlusOverride(this IHasKPlusMetadata hasKPlusMetadata, MetadataSettingField field)
|
||||
{
|
||||
if (hasKPlusMetadata.KPlusOverrides.Contains(field)) return;
|
||||
|
||||
hasKPlusMetadata.KPlusOverrides.Add(field);
|
||||
}
|
||||
|
||||
}
|
136
API/Extensions/QueryExtensions/Filtering/PersonFilter.cs
Normal file
136
API/Extensions/QueryExtensions/Filtering/PersonFilter.cs
Normal file
|
@ -0,0 +1,136 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using API.DTOs.Filtering.v2;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Person;
|
||||
using Kavita.Common;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Extensions.QueryExtensions.Filtering;
|
||||
|
||||
public static class PersonFilter
|
||||
{
|
||||
public static IQueryable<Person> HasPersonName(this IQueryable<Person> queryable, bool condition,
|
||||
FilterComparison comparison, string queryString)
|
||||
{
|
||||
if (string.IsNullOrEmpty(queryString) || !condition) return queryable;
|
||||
|
||||
return comparison switch
|
||||
{
|
||||
FilterComparison.Equal => queryable.Where(p => p.Name.Equals(queryString)),
|
||||
FilterComparison.BeginsWith => queryable.Where(p => EF.Functions.Like(p.Name, $"{queryString}%")),
|
||||
FilterComparison.EndsWith => queryable.Where(p => EF.Functions.Like(p.Name, $"%{queryString}")),
|
||||
FilterComparison.Matches => queryable.Where(p => EF.Functions.Like(p.Name, $"%{queryString}%")),
|
||||
FilterComparison.NotEqual => queryable.Where(p => p.Name != queryString),
|
||||
FilterComparison.NotContains or FilterComparison.GreaterThan or FilterComparison.GreaterThanEqual
|
||||
or FilterComparison.LessThan or FilterComparison.LessThanEqual or FilterComparison.Contains
|
||||
or FilterComparison.IsBefore or FilterComparison.IsAfter or FilterComparison.IsInLast
|
||||
or FilterComparison.IsNotInLast or FilterComparison.MustContains
|
||||
or FilterComparison.IsEmpty =>
|
||||
throw new KavitaException($"{comparison} not applicable for Person.Name"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(comparison), comparison,
|
||||
"Filter Comparison is not supported")
|
||||
};
|
||||
}
|
||||
public static IQueryable<Person> HasPersonRole(this IQueryable<Person> queryable, bool condition,
|
||||
FilterComparison comparison, IList<PersonRole> roles)
|
||||
{
|
||||
if (roles == null || roles.Count == 0 || !condition) return queryable;
|
||||
|
||||
return comparison switch
|
||||
{
|
||||
FilterComparison.Contains or FilterComparison.MustContains => queryable.Where(p =>
|
||||
p.SeriesMetadataPeople.Any(smp => roles.Contains(smp.Role)) ||
|
||||
p.ChapterPeople.Any(cmp => roles.Contains(cmp.Role))),
|
||||
FilterComparison.NotContains => queryable.Where(p =>
|
||||
!p.SeriesMetadataPeople.Any(smp => roles.Contains(smp.Role)) &&
|
||||
!p.ChapterPeople.Any(cmp => roles.Contains(cmp.Role))),
|
||||
FilterComparison.Equal or FilterComparison.NotEqual or FilterComparison.BeginsWith
|
||||
or FilterComparison.EndsWith or FilterComparison.Matches or FilterComparison.GreaterThan
|
||||
or FilterComparison.GreaterThanEqual or FilterComparison.LessThan or FilterComparison.LessThanEqual
|
||||
or FilterComparison.IsBefore or FilterComparison.IsAfter or FilterComparison.IsInLast
|
||||
or FilterComparison.IsNotInLast
|
||||
or FilterComparison.IsEmpty =>
|
||||
throw new KavitaException($"{comparison} not applicable for Person.Role"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(comparison), comparison,
|
||||
"Filter Comparison is not supported")
|
||||
};
|
||||
}
|
||||
|
||||
public static IQueryable<Person> HasPersonSeriesCount(this IQueryable<Person> queryable, bool condition,
|
||||
FilterComparison comparison, int count)
|
||||
{
|
||||
if (!condition) return queryable;
|
||||
|
||||
return comparison switch
|
||||
{
|
||||
FilterComparison.Equal => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() == count),
|
||||
FilterComparison.GreaterThan => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() > count),
|
||||
FilterComparison.GreaterThanEqual => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() >= count),
|
||||
FilterComparison.LessThan => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() < count),
|
||||
FilterComparison.LessThanEqual => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() <= count),
|
||||
FilterComparison.NotEqual => queryable.Where(p => p.SeriesMetadataPeople
|
||||
.Select(smp => smp.SeriesMetadata.SeriesId)
|
||||
.Distinct()
|
||||
.Count() != count),
|
||||
FilterComparison.BeginsWith or FilterComparison.EndsWith or FilterComparison.Matches
|
||||
or FilterComparison.Contains or FilterComparison.NotContains or FilterComparison.IsBefore
|
||||
or FilterComparison.IsAfter or FilterComparison.IsInLast or FilterComparison.IsNotInLast
|
||||
or FilterComparison.MustContains
|
||||
or FilterComparison.IsEmpty => throw new KavitaException(
|
||||
$"{comparison} not applicable for Person.SeriesCount"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(comparison), comparison, "Filter Comparison is not supported")
|
||||
};
|
||||
}
|
||||
|
||||
public static IQueryable<Person> HasPersonChapterCount(this IQueryable<Person> queryable, bool condition,
|
||||
FilterComparison comparison, int count)
|
||||
{
|
||||
if (!condition) return queryable;
|
||||
|
||||
return comparison switch
|
||||
{
|
||||
FilterComparison.Equal => queryable.Where(p =>
|
||||
p.ChapterPeople.Select(cp => cp.Chapter.Id).Distinct().Count() == count),
|
||||
FilterComparison.GreaterThan => queryable.Where(p => p.ChapterPeople
|
||||
.Select(cp => cp.Chapter.Id)
|
||||
.Distinct()
|
||||
.Count() > count),
|
||||
FilterComparison.GreaterThanEqual => queryable.Where(p => p.ChapterPeople
|
||||
.Select(cp => cp.Chapter.Id)
|
||||
.Distinct()
|
||||
.Count() >= count),
|
||||
FilterComparison.LessThan => queryable.Where(p =>
|
||||
p.ChapterPeople.Select(cp => cp.Chapter.Id).Distinct().Count() < count),
|
||||
FilterComparison.LessThanEqual => queryable.Where(p => p.ChapterPeople
|
||||
.Select(cp => cp.Chapter.Id)
|
||||
.Distinct()
|
||||
.Count() <= count),
|
||||
FilterComparison.NotEqual => queryable.Where(p =>
|
||||
p.ChapterPeople.Select(cp => cp.Chapter.Id).Distinct().Count() != count),
|
||||
FilterComparison.BeginsWith or FilterComparison.EndsWith or FilterComparison.Matches
|
||||
or FilterComparison.Contains or FilterComparison.NotContains or FilterComparison.IsBefore
|
||||
or FilterComparison.IsAfter or FilterComparison.IsInLast or FilterComparison.IsNotInLast
|
||||
or FilterComparison.MustContains
|
||||
or FilterComparison.IsEmpty => throw new KavitaException(
|
||||
$"{comparison} not applicable for Person.ChapterCount"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(comparison), comparison, "Filter Comparison is not supported")
|
||||
};
|
||||
}
|
||||
}
|
|
@ -5,10 +5,13 @@ using System.Linq.Expressions;
|
|||
using System.Threading.Tasks;
|
||||
using API.Data.Misc;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs;
|
||||
using API.DTOs.Filtering;
|
||||
using API.DTOs.KavitaPlus.Manage;
|
||||
using API.DTOs.Metadata.Browse;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Person;
|
||||
using API.Entities.Scrobble;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
@ -273,6 +276,27 @@ public static class QueryableExtensions
|
|||
};
|
||||
}
|
||||
|
||||
public static IQueryable<Person> SortBy(this IQueryable<Person> query, PersonSortOptions? sort)
|
||||
{
|
||||
if (sort == null)
|
||||
{
|
||||
return query.OrderBy(p => p.Name);
|
||||
}
|
||||
|
||||
return sort.SortField switch
|
||||
{
|
||||
PersonSortField.Name when sort.IsAscending => query.OrderBy(p => p.Name),
|
||||
PersonSortField.Name => query.OrderByDescending(p => p.Name),
|
||||
PersonSortField.SeriesCount when sort.IsAscending => query.OrderBy(p => p.SeriesMetadataPeople.Count),
|
||||
PersonSortField.SeriesCount => query.OrderByDescending(p => p.SeriesMetadataPeople.Count),
|
||||
PersonSortField.ChapterCount when sort.IsAscending => query.OrderBy(p => p.ChapterPeople.Count),
|
||||
PersonSortField.ChapterCount => query.OrderByDescending(p => p.ChapterPeople.Count),
|
||||
_ => query.OrderBy(p => p.Name)
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs either OrderBy or OrderByDescending on the given query based on the value of SortOptions.IsAscending.
|
||||
/// </summary>
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Linq;
|
|||
using API.Data.Misc;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Entities.Person;
|
||||
|
||||
namespace API.Extensions.QueryExtensions;
|
||||
|
@ -26,6 +27,20 @@ public static class RestrictByAgeExtensions
|
|||
return q;
|
||||
}
|
||||
|
||||
public static IQueryable<SeriesMetadataPeople> RestrictAgainstAgeRestriction(this IQueryable<SeriesMetadataPeople> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
var q = queryable.Where(s => s.SeriesMetadata.AgeRating <= restriction.AgeRating);
|
||||
|
||||
if (!restriction.IncludeUnknowns)
|
||||
{
|
||||
return q.Where(s => s.SeriesMetadata.AgeRating != AgeRating.Unknown);
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
public static IQueryable<Chapter> RestrictAgainstAgeRestriction(this IQueryable<Chapter> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
@ -39,21 +54,20 @@ public static class RestrictByAgeExtensions
|
|||
return q;
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public static IQueryable<CollectionTag> RestrictAgainstAgeRestriction(this IQueryable<CollectionTag> queryable, AgeRestriction restriction)
|
||||
public static IQueryable<ChapterPeople> RestrictAgainstAgeRestriction(this IQueryable<ChapterPeople> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
var q = queryable.Where(cp => cp.Chapter.Volume.Series.Metadata.AgeRating <= restriction.AgeRating);
|
||||
|
||||
if (restriction.IncludeUnknowns)
|
||||
if (!restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
return q.Where(cp => cp.Chapter.Volume.Series.Metadata.AgeRating != AgeRating.Unknown);
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
public static IQueryable<AppUserCollection> RestrictAgainstAgeRestriction(this IQueryable<AppUserCollection> queryable, AgeRestriction restriction)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
|
@ -68,18 +82,27 @@ public static class RestrictByAgeExtensions
|
|||
sm.Metadata.AgeRating <= restriction.AgeRating && sm.Metadata.AgeRating > AgeRating.Unknown));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all Genres where any of the linked Series/Chapters are less than or equal to restriction age rating
|
||||
/// </summary>
|
||||
/// <param name="queryable"></param>
|
||||
/// <param name="restriction"></param>
|
||||
/// <returns></returns>
|
||||
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.Any(sm => sm.AgeRating <= restriction.AgeRating) ||
|
||||
c.Chapters.Any(cp => cp.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
return queryable.Where(c =>
|
||||
c.SeriesMetadatas.Any(sm => sm.AgeRating <= restriction.AgeRating && sm.AgeRating != AgeRating.Unknown) ||
|
||||
c.Chapters.Any(cp => cp.AgeRating <= restriction.AgeRating && cp.AgeRating != AgeRating.Unknown)
|
||||
);
|
||||
}
|
||||
|
||||
public static IQueryable<Tag> RestrictAgainstAgeRestriction(this IQueryable<Tag> queryable, AgeRestriction restriction)
|
||||
|
@ -88,12 +111,15 @@ public static class RestrictByAgeExtensions
|
|||
|
||||
if (restriction.IncludeUnknowns)
|
||||
{
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating));
|
||||
return queryable.Where(c =>
|
||||
c.SeriesMetadatas.Any(sm => sm.AgeRating <= restriction.AgeRating) ||
|
||||
c.Chapters.Any(cp => cp.AgeRating <= restriction.AgeRating));
|
||||
}
|
||||
|
||||
return queryable.Where(c => c.SeriesMetadatas.All(sm =>
|
||||
sm.AgeRating <= restriction.AgeRating && sm.AgeRating > AgeRating.Unknown));
|
||||
return queryable.Where(c =>
|
||||
c.SeriesMetadatas.Any(sm => sm.AgeRating <= restriction.AgeRating && sm.AgeRating != AgeRating.Unknown) ||
|
||||
c.Chapters.Any(cp => cp.AgeRating <= restriction.AgeRating && cp.AgeRating != AgeRating.Unknown)
|
||||
);
|
||||
}
|
||||
|
||||
public static IQueryable<Person> RestrictAgainstAgeRestriction(this IQueryable<Person> queryable, AgeRestriction restriction)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
using System.Linq;
|
||||
using API.Entities;
|
||||
using API.Entities.Person;
|
||||
|
||||
namespace API.Extensions.QueryExtensions;
|
||||
|
||||
public static class RestrictByLibraryExtensions
|
||||
{
|
||||
|
||||
public static IQueryable<Person> RestrictByLibrary(this IQueryable<Person> query, IQueryable<int> userLibs)
|
||||
{
|
||||
return query.Where(p =>
|
||||
p.ChapterPeople.Any(cp => userLibs.Contains(cp.Chapter.Volume.Series.LibraryId)) ||
|
||||
p.SeriesMetadataPeople.Any(sm => userLibs.Contains(sm.SeriesMetadata.Series.LibraryId)));
|
||||
}
|
||||
|
||||
public static IQueryable<Chapter> RestrictByLibrary(this IQueryable<Chapter> query, IQueryable<int> userLibs)
|
||||
{
|
||||
return query.Where(cp => userLibs.Contains(cp.Volume.Series.LibraryId));
|
||||
}
|
||||
|
||||
public static IQueryable<SeriesMetadataPeople> RestrictByLibrary(this IQueryable<SeriesMetadataPeople> query, IQueryable<int> userLibs)
|
||||
{
|
||||
return query.Where(sm => userLibs.Contains(sm.SeriesMetadata.Series.LibraryId));
|
||||
}
|
||||
|
||||
public static IQueryable<ChapterPeople> RestrictByLibrary(this IQueryable<ChapterPeople> query, IQueryable<int> userLibs)
|
||||
{
|
||||
return query.Where(cp => userLibs.Contains(cp.Chapter.Volume.Series.LibraryId));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue