From 0b3d6676d1dc78f38cd17c04ecafe2196a291199 Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Mon, 8 Dec 2025 21:01:32 -0700 Subject: Add ability to sort and filter activity log entries (#15583) --- Jellyfin.Api/Controllers/ActivityLogController.cs | 76 ++++++++++++++++++++--- 1 file changed, 67 insertions(+), 9 deletions(-) (limited to 'Jellyfin.Api/Controllers/ActivityLogController.cs') diff --git a/Jellyfin.Api/Controllers/ActivityLogController.cs b/Jellyfin.Api/Controllers/ActivityLogController.cs index a19a203b5..d5f262773 100644 --- a/Jellyfin.Api/Controllers/ActivityLogController.cs +++ b/Jellyfin.Api/Controllers/ActivityLogController.cs @@ -1,13 +1,16 @@ using System; +using System.Collections.Generic; using System.Threading.Tasks; -using Jellyfin.Api.Constants; +using Jellyfin.Data.Enums; using Jellyfin.Data.Queries; +using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Common.Api; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Querying; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; namespace Jellyfin.Api.Controllers; @@ -32,10 +35,19 @@ public class ActivityLogController : BaseJellyfinApiController /// /// Gets activity log entries. /// - /// Optional. The record index to start at. All items with a lower index will be dropped from the results. - /// Optional. The maximum number of records to return. - /// Optional. The minimum date. Format = ISO. - /// Optional. Filter log entries if it has user id, or not. + /// The record index to start at. All items with a lower index will be dropped from the results. + /// The maximum number of records to return. + /// The minimum date. + /// Filter log entries if it has user id, or not. + /// Filter by name. + /// Filter by overview. + /// Filter by short overview. + /// Filter by type. + /// Filter by item id. + /// Filter by username. + /// Filter by log severity. + /// Specify one or more sort orders. Format: SortBy=Name,Type. + /// Sort Order.. /// Activity log returned. /// A containing the log entries. [HttpGet("Entries")] @@ -44,14 +56,60 @@ public class ActivityLogController : BaseJellyfinApiController [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] DateTime? minDate, - [FromQuery] bool? hasUserId) + [FromQuery] bool? hasUserId, + [FromQuery] string? name, + [FromQuery] string? overview, + [FromQuery] string? shortOverview, + [FromQuery] string? type, + [FromQuery] Guid? itemId, + [FromQuery] string? username, + [FromQuery] LogLevel? severity, + [FromQuery] ActivityLogSortBy[]? sortBy, + [FromQuery] SortOrder[]? sortOrder) { - return await _activityManager.GetPagedResultAsync(new ActivityLogQuery + var query = new ActivityLogQuery { Skip = startIndex, Limit = limit, MinDate = minDate, - HasUserId = hasUserId - }).ConfigureAwait(false); + HasUserId = hasUserId, + Name = name, + Overview = overview, + ShortOverview = shortOverview, + Type = type, + ItemId = itemId, + Username = username, + Severity = severity, + OrderBy = GetOrderBy(sortBy ?? [], sortOrder ?? []), + }; + + return await _activityManager.GetPagedResultAsync(query).ConfigureAwait(false); + } + + private static (ActivityLogSortBy SortBy, SortOrder SortOrder)[] GetOrderBy( + IReadOnlyList sortBy, + IReadOnlyList requestedSortOrder) + { + if (sortBy.Count == 0) + { + return []; + } + + var result = new (ActivityLogSortBy, SortOrder)[sortBy.Count]; + var i = 0; + for (; i < requestedSortOrder.Count; i++) + { + result[i] = (sortBy[i], requestedSortOrder[i]); + } + + // Add remaining elements with the first specified SortOrder + // or the default one if no SortOrders are specified + var order = requestedSortOrder.Count > 0 ? requestedSortOrder[0] : SortOrder.Ascending; + for (; i < sortBy.Count; i++) + { + result[i] = (sortBy[i], order); + } + + return result; } } -- cgit v1.2.3 From 84f66dd54e74621e4d81cd57648c4d27411d82d9 Mon Sep 17 00:00:00 2001 From: Björn Tenje Persson Date: Sat, 20 Dec 2025 04:36:38 +0100 Subject: Fixed Multi Sort in New ActivityManager (#15820) --- CONTRIBUTORS.md | 1 + Jellyfin.Api/Controllers/ActivityLogController.cs | 3 +++ Jellyfin.Data/Queries/ActivityLogQuery.cs | 5 +++++ .../Activity/ActivityManager.cs | 21 ++++++++++++++++++--- 4 files changed, 27 insertions(+), 3 deletions(-) (limited to 'Jellyfin.Api/Controllers/ActivityLogController.cs') diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 0a4114478..4406413da 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -205,6 +205,7 @@ - [theshoeshiner](https://github.com/theshoeshiner) - [TokerX](https://github.com/TokerX) - [GeneMarks](https://github.com/GeneMarks) + - [bjorntp](https://github.com/bjorntp) # Emby Contributors diff --git a/Jellyfin.Api/Controllers/ActivityLogController.cs b/Jellyfin.Api/Controllers/ActivityLogController.cs index d5f262773..47d3f4b7f 100644 --- a/Jellyfin.Api/Controllers/ActivityLogController.cs +++ b/Jellyfin.Api/Controllers/ActivityLogController.cs @@ -38,6 +38,7 @@ public class ActivityLogController : BaseJellyfinApiController /// The record index to start at. All items with a lower index will be dropped from the results. /// The maximum number of records to return. /// The minimum date. + /// The maximum date. /// Filter log entries if it has user id, or not. /// Filter by name. /// Filter by overview. @@ -56,6 +57,7 @@ public class ActivityLogController : BaseJellyfinApiController [FromQuery] int? startIndex, [FromQuery] int? limit, [FromQuery] DateTime? minDate, + [FromQuery] DateTime? maxDate, [FromQuery] bool? hasUserId, [FromQuery] string? name, [FromQuery] string? overview, @@ -72,6 +74,7 @@ public class ActivityLogController : BaseJellyfinApiController Skip = startIndex, Limit = limit, MinDate = minDate, + MaxDate = maxDate, HasUserId = hasUserId, Name = name, Overview = overview, diff --git a/Jellyfin.Data/Queries/ActivityLogQuery.cs b/Jellyfin.Data/Queries/ActivityLogQuery.cs index 95c52f870..6de6c4c21 100644 --- a/Jellyfin.Data/Queries/ActivityLogQuery.cs +++ b/Jellyfin.Data/Queries/ActivityLogQuery.cs @@ -21,6 +21,11 @@ public class ActivityLogQuery : PaginatedQuery /// public DateTime? MinDate { get; set; } + /// + /// Gets or sets the maximum date to query for. + /// + public DateTime? MaxDate { get; set; } + /// /// Gets or sets the name filter. /// diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs index 7ee573f53..fe987b9d8 100644 --- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs +++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs @@ -72,6 +72,11 @@ public class ActivityManager : IActivityManager entries = entries.Where(e => e.ActivityLog.DateCreated >= query.MinDate.Value); } + if (query.MaxDate is not null) + { + entries = entries.Where(e => e.ActivityLog.DateCreated <= query.MaxDate.Value); + } + if (!string.IsNullOrEmpty(query.Name)) { entries = entries.Where(e => EF.Functions.Like(e.ActivityLog.Name, $"%{query.Name}%")); @@ -166,9 +171,19 @@ public class ActivityManager : IActivityManager foreach (var (sortBy, sortOrder) in sorting) { var orderBy = MapOrderBy(sortBy); - ordered = sortOrder == SortOrder.Ascending - ? (ordered ?? query).OrderBy(orderBy) - : (ordered ?? query).OrderByDescending(orderBy); + + if (ordered == null) + { + ordered = sortOrder == SortOrder.Ascending + ? query.OrderBy(orderBy) + : query.OrderByDescending(orderBy); + } + else + { + ordered = sortOrder == SortOrder.Ascending + ? ordered.ThenBy(orderBy) + : ordered.ThenByDescending(orderBy); + } } return ordered; -- cgit v1.2.3