mirror of
https://github.com/Kareadita/Kavita.git
synced 2026-05-13 11:02:18 -04:00
Progress Overhaul + Profile Page and a LOT more! (#4262)
Co-authored-by: Amelia <77553571+Fesaa@users.noreply.github.com> Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using API.Entities.User;
|
||||
|
||||
namespace API.Extensions.QueryExtensions;
|
||||
|
||||
public static class AuthKeyQueryExtensions
|
||||
{
|
||||
public static IQueryable<AppUserAuthKey> HasNotExpired(this IQueryable<AppUserAuthKey> queryable)
|
||||
{
|
||||
return queryable.Where(k => k.ExpiresAtUtc == null || k.ExpiresAtUtc > DateTime.UtcNow);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System.Linq;
|
||||
using API.DTOs.Statistics;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Enums.UserPreferences;
|
||||
using API.Entities.Progress;
|
||||
using API.Entities.User;
|
||||
|
||||
namespace API.Extensions.QueryExtensions.Filtering;
|
||||
|
||||
public static class ActivityFilter
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Filter AppUserReadingSessionActivityData for the given filter, viewer, and owner
|
||||
/// </summary>
|
||||
/// <param name="queryable">source</param>
|
||||
/// <param name="filter">stats filter from the UI</param>
|
||||
/// <param name="userId">user id of the user <b>owing</b> the data</param>
|
||||
/// <param name="socialPreferences">social preferences of the user <b>owing</b> the data</param>
|
||||
/// <param name="requestingUser">the user <b>requesting</b> the data</param>
|
||||
/// <param name="onlyCompleted">return only data for fully read chapters</param>
|
||||
/// <param name="isAggregate">If this is aggregate data (counts, etc), the filter will opt-out of restricting based on Social Libraries/Age Rating</param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<AppUserReadingSessionActivityData> ApplyStatsFilter(
|
||||
this IQueryable<AppUserReadingSessionActivityData> queryable,
|
||||
StatsFilterDto filter,
|
||||
int userId,
|
||||
AppUserSocialPreferences socialPreferences,
|
||||
AppUser requestingUser,
|
||||
bool onlyCompleted = true,
|
||||
bool isAggregate = false
|
||||
)
|
||||
{
|
||||
var startTime = filter.StartDate?.ToUniversalTime();
|
||||
var endTime = filter.EndDate?.ToUniversalTime();
|
||||
var isOwnRequest = userId == requestingUser.Id;
|
||||
|
||||
var shouldLimitOnSocialLibraries = !isOwnRequest && socialPreferences.SocialLibraries.Count > 0;
|
||||
var shouldLimitOnSocialAgeRating =
|
||||
!isOwnRequest && socialPreferences.SocialMaxAgeRating != AgeRating.NotApplicable;
|
||||
var shouldLimitOnAgeRating = !isOwnRequest && requestingUser.AgeRestriction != AgeRating.NotApplicable;
|
||||
|
||||
queryable = queryable
|
||||
.Where(d => filter.Libraries.Contains(d.LibraryId) && d.ReadingSession.AppUserId == userId)
|
||||
.WhereIf(onlyCompleted, d => d.EndPage >= d.Chapter.Pages)
|
||||
.WhereIf(startTime != null, d => d.StartTime >= startTime)
|
||||
.WhereIf(endTime != null, d => d.EndTime <= endTime);
|
||||
|
||||
if (isAggregate)
|
||||
{
|
||||
return queryable;
|
||||
}
|
||||
|
||||
return queryable
|
||||
.WhereIf(shouldLimitOnSocialLibraries, d => socialPreferences.SocialLibraries.Contains(d.LibraryId))
|
||||
.WhereIf(shouldLimitOnSocialAgeRating, d =>
|
||||
(socialPreferences.SocialMaxAgeRating >= d.Chapter.Volume.Series.Metadata.AgeRating && d.Chapter.Volume.Series.Metadata.AgeRating != AgeRating.Unknown)
|
||||
|| (socialPreferences.SocialIncludeUnknowns && d.Chapter.Volume.Series.Metadata.AgeRating == AgeRating.Unknown )
|
||||
)
|
||||
.WhereIf(shouldLimitOnAgeRating, d =>
|
||||
(requestingUser.AgeRestriction >= d.Chapter.Volume.Series.Metadata.AgeRating && d.Chapter.Volume.Series.Metadata.AgeRating != AgeRating.Unknown)
|
||||
|| (requestingUser.AgeRestrictionIncludeUnknowns && d.Chapter.Volume.Series.Metadata.AgeRating == AgeRating.Unknown )
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.DTOs.Filtering.v2;
|
||||
using API.DTOs.Reader;
|
||||
using API.Entities;
|
||||
using Kavita.Common;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@@ -129,4 +127,61 @@ public static class AnnotationFilter
|
||||
};
|
||||
}
|
||||
|
||||
public static IQueryable<AppUserAnnotation> HasLikes(this IQueryable<AppUserAnnotation> queryable, bool condition,
|
||||
FilterComparison comparison, int value)
|
||||
{
|
||||
if (!condition) return queryable;
|
||||
|
||||
return comparison switch
|
||||
{
|
||||
FilterComparison.Equal => queryable.Where(a => a.Likes.Count == value),
|
||||
FilterComparison.NotEqual => queryable.Where(a => a.Likes.Count != value),
|
||||
FilterComparison.GreaterThan => queryable.Where(a => a.Likes.Count > value),
|
||||
FilterComparison.GreaterThanEqual => queryable.Where(a => a.Likes.Count >= value),
|
||||
FilterComparison.LessThan => queryable.Where(a => a.Likes.Count < value),
|
||||
FilterComparison.LessThanEqual => queryable.Where(a => a.Likes.Count <= value),
|
||||
FilterComparison.BeginsWith or
|
||||
FilterComparison.EndsWith or
|
||||
FilterComparison.Matches or
|
||||
FilterComparison.Contains or
|
||||
FilterComparison.MustContains or
|
||||
FilterComparison.NotContains or
|
||||
FilterComparison.IsBefore or
|
||||
FilterComparison.IsAfter or
|
||||
FilterComparison.IsInLast or
|
||||
FilterComparison.IsNotInLast or
|
||||
FilterComparison.IsEmpty => throw new KavitaException($"{comparison} is not applicable for Annotation.Likes"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(comparison), comparison, null),
|
||||
};
|
||||
}
|
||||
|
||||
public static IQueryable<AppUserAnnotation> IsLikedBy(this IQueryable<AppUserAnnotation> queryable, bool condition,
|
||||
FilterComparison comparison, IList<int> value)
|
||||
{
|
||||
if (value.Count == 0 || !condition) return queryable;
|
||||
|
||||
return comparison switch
|
||||
{
|
||||
FilterComparison.Equal => queryable.Where(a => a.Likes.Contains(value[0])),
|
||||
FilterComparison.NotEqual => queryable.Where(a => a!.Likes.Contains(value[0])),
|
||||
FilterComparison.Contains => queryable.Where(a => a.Likes.Any(value.Contains)),
|
||||
FilterComparison.NotContains => queryable.Where(a => !a.Likes.Any(value.Contains)),
|
||||
FilterComparison.GreaterThan or
|
||||
FilterComparison.GreaterThanEqual or
|
||||
FilterComparison.LessThan or
|
||||
FilterComparison.LessThanEqual or
|
||||
FilterComparison.BeginsWith or
|
||||
FilterComparison.EndsWith or
|
||||
FilterComparison.Matches or
|
||||
FilterComparison.MustContains or
|
||||
FilterComparison.IsBefore or
|
||||
FilterComparison.IsAfter or
|
||||
FilterComparison.IsInLast or
|
||||
FilterComparison.IsNotInLast or
|
||||
FilterComparison.IsEmpty => throw new KavitaException($"{comparison} is not applicable for Annotation.Likes"),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(comparison), comparison, null),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using API.Data.Misc;
|
||||
using API.Data.Repositories;
|
||||
|
||||
@@ -271,6 +271,11 @@ public static class IncludesExtensions
|
||||
query = query.Include(u => u.ChapterRatings);
|
||||
}
|
||||
|
||||
if (includeFlags.HasFlag(AppUserIncludes.AuthKeys))
|
||||
{
|
||||
query = query.Include(u => u.AuthKeys);
|
||||
}
|
||||
|
||||
return query.AsSplitQuery();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,16 +5,13 @@ using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data.Misc;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs;
|
||||
using API.DTOs.Annotations;
|
||||
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 AutoMapper.QueryableExtensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace API.Extensions.QueryExtensions;
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using API.Data.Misc;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Entities.Person;
|
||||
using API.Entities.User;
|
||||
|
||||
namespace API.Extensions.QueryExtensions;
|
||||
#nullable enable
|
||||
@@ -153,7 +152,7 @@ public static class RestrictByAgeExtensions
|
||||
return q;
|
||||
}
|
||||
|
||||
private static IQueryable<AppUserRating> RestrictAgainstAgeRestriction(this IQueryable<AppUserRating> queryable, AgeRestriction restriction, int userId)
|
||||
public static IQueryable<AppUserRating> RestrictAgainstAgeRestriction(this IQueryable<AppUserRating> queryable, AgeRestriction restriction, int userId)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
var q = queryable.Where(r => r.Series.Metadata.AgeRating <= restriction.AgeRating || r.AppUserId == userId);
|
||||
@@ -166,7 +165,7 @@ public static class RestrictByAgeExtensions
|
||||
return q;
|
||||
}
|
||||
|
||||
private static IQueryable<AppUserChapterRating> RestrictAgainstAgeRestriction(this IQueryable<AppUserChapterRating> queryable, AgeRestriction restriction, int userId)
|
||||
public static IQueryable<AppUserChapterRating> RestrictAgainstAgeRestriction(this IQueryable<AppUserChapterRating> queryable, AgeRestriction restriction, int userId)
|
||||
{
|
||||
if (restriction.AgeRating == AgeRating.NotApplicable) return queryable;
|
||||
var q = queryable.Where(r => r.Series.Metadata.AgeRating <= restriction.AgeRating || r.AppUserId == userId);
|
||||
|
||||
Reference in New Issue
Block a user