aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Lavado <anthony@lavado.ca>2020-10-09 20:12:26 -0400
committerGitHub <noreply@github.com>2020-10-09 20:12:26 -0400
commitecabcff8f0fd9e8d9a59a91b11b2ab14a64be74a (patch)
tree45442b377575345a527dac8aeffc09b301225dee
parentea5c78ee2111ee334920c2f52326efc7d0a8086b (diff)
parentd4a492ef93f6b663fd4a4f7710613f06863f401f (diff)
Merge pull request #4274 from barronpm/activitylog-query
Rewrite Activity Log Backend
-rw-r--r--Jellyfin.Api/Controllers/ActivityLogController.cs20
-rw-r--r--Jellyfin.Data/Queries/ActivityLogQuery.cs30
-rw-r--r--Jellyfin.Server.Implementations/Activity/ActivityManager.cs40
-rw-r--r--Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj1
-rw-r--r--Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs1
-rw-r--r--Jellyfin.Server.Implementations/Users/UserManager.cs11
-rw-r--r--MediaBrowser.Model/Activity/IActivityManager.cs9
7 files changed, 69 insertions, 43 deletions
diff --git a/Jellyfin.Api/Controllers/ActivityLogController.cs b/Jellyfin.Api/Controllers/ActivityLogController.cs
index a07cea9c0..b429cebec 100644
--- a/Jellyfin.Api/Controllers/ActivityLogController.cs
+++ b/Jellyfin.Api/Controllers/ActivityLogController.cs
@@ -1,7 +1,7 @@
using System;
-using System.Linq;
+using System.Threading.Tasks;
using Jellyfin.Api.Constants;
-using Jellyfin.Data.Entities;
+using Jellyfin.Data.Queries;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Querying;
using Microsoft.AspNetCore.Authorization;
@@ -39,19 +39,19 @@ namespace Jellyfin.Api.Controllers
/// <returns>A <see cref="QueryResult{ActivityLogEntry}"/> containing the log entries.</returns>
[HttpGet("Entries")]
[ProducesResponseType(StatusCodes.Status200OK)]
- public ActionResult<QueryResult<ActivityLogEntry>> GetLogEntries(
+ public async Task<ActionResult<QueryResult<ActivityLogEntry>>> GetLogEntries(
[FromQuery] int? startIndex,
[FromQuery] int? limit,
[FromQuery] DateTime? minDate,
[FromQuery] bool? hasUserId)
{
- var filterFunc = new Func<IQueryable<ActivityLog>, IQueryable<ActivityLog>>(
- entries => entries.Where(entry => entry.DateCreated >= minDate
- && (!hasUserId.HasValue || (hasUserId.Value
- ? entry.UserId != Guid.Empty
- : entry.UserId == Guid.Empty))));
-
- return _activityManager.GetPagedResult(filterFunc, startIndex, limit);
+ return await _activityManager.GetPagedResultAsync(new ActivityLogQuery
+ {
+ StartIndex = startIndex,
+ Limit = limit,
+ MinDate = minDate,
+ HasUserId = hasUserId
+ }).ConfigureAwait(false);
}
}
}
diff --git a/Jellyfin.Data/Queries/ActivityLogQuery.cs b/Jellyfin.Data/Queries/ActivityLogQuery.cs
new file mode 100644
index 000000000..92919d3a5
--- /dev/null
+++ b/Jellyfin.Data/Queries/ActivityLogQuery.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace Jellyfin.Data.Queries
+{
+ /// <summary>
+ /// A class representing a query to the activity logs.
+ /// </summary>
+ public class ActivityLogQuery
+ {
+ /// <summary>
+ /// Gets or sets the index to start at.
+ /// </summary>
+ public int? StartIndex { get; set; }
+
+ /// <summary>
+ /// Gets or sets the maximum number of items to include.
+ /// </summary>
+ public int? Limit { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to take entries with a user id.
+ /// </summary>
+ public bool? HasUserId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the minimum date to query for.
+ /// </summary>
+ public DateTime? MinDate { get; set; }
+ }
+}
diff --git a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
index abdd290d4..5926abfe0 100644
--- a/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
+++ b/Jellyfin.Server.Implementations/Activity/ActivityManager.cs
@@ -3,8 +3,10 @@ using System.Linq;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Events;
+using Jellyfin.Data.Queries;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Querying;
+using Microsoft.EntityFrameworkCore;
namespace Jellyfin.Server.Implementations.Activity
{
@@ -39,41 +41,37 @@ namespace Jellyfin.Server.Implementations.Activity
}
/// <inheritdoc/>
- public QueryResult<ActivityLogEntry> GetPagedResult(
- Func<IQueryable<ActivityLog>, IQueryable<ActivityLog>> func,
- int? startIndex,
- int? limit)
+ public async Task<QueryResult<ActivityLogEntry>> GetPagedResultAsync(ActivityLogQuery query)
{
- using var dbContext = _provider.CreateContext();
+ await using var dbContext = _provider.CreateContext();
- var query = func(dbContext.ActivityLogs.OrderByDescending(entry => entry.DateCreated));
+ IQueryable<ActivityLog> entries = dbContext.ActivityLogs
+ .AsQueryable()
+ .OrderByDescending(entry => entry.DateCreated);
- if (startIndex.HasValue)
+ if (query.MinDate.HasValue)
{
- query = query.Skip(startIndex.Value);
+ entries = entries.Where(entry => entry.DateCreated >= query.MinDate);
}
- if (limit.HasValue)
+ if (query.HasUserId.HasValue)
{
- query = query.Take(limit.Value);
+ entries = entries.Where(entry => entry.UserId != Guid.Empty == query.HasUserId.Value );
}
- // This converts the objects from the new database model to the old for compatibility with the existing API.
- var list = query.Select(ConvertToOldModel).ToList();
-
return new QueryResult<ActivityLogEntry>
{
- Items = list,
- TotalRecordCount = func(dbContext.ActivityLogs).Count()
+ Items = await entries
+ .Skip(query.StartIndex ?? 0)
+ .Take(query.Limit ?? 100)
+ .AsAsyncEnumerable()
+ .Select(ConvertToOldModel)
+ .ToListAsync()
+ .ConfigureAwait(false),
+ TotalRecordCount = await entries.CountAsync().ConfigureAwait(false)
};
}
- /// <inheritdoc/>
- public QueryResult<ActivityLogEntry> GetPagedResult(int? startIndex, int? limit)
- {
- return GetPagedResult(logs => logs, startIndex, limit);
- }
-
private static ActivityLogEntry ConvertToOldModel(ActivityLog entry)
{
return new ActivityLogEntry
diff --git a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
index 4e79dd8d6..17ba09258 100644
--- a/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
+++ b/Jellyfin.Server.Implementations/Jellyfin.Server.Implementations.csproj
@@ -24,6 +24,7 @@
</ItemGroup>
<ItemGroup>
+ <PackageReference Include="System.Linq.Async" Version="4.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
diff --git a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
index 46f1c618f..76f943385 100644
--- a/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
+++ b/Jellyfin.Server.Implementations/Users/DisplayPreferencesManager.cs
@@ -61,6 +61,7 @@ namespace Jellyfin.Server.Implementations.Users
public IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client)
{
return _dbContext.ItemDisplayPreferences
+ .AsQueryable()
.Where(prefs => prefs.UserId == userId && prefs.ItemId != Guid.Empty && string.Equals(prefs.Client, client))
.ToList();
}
diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs
index c6cc639fa..437833aa3 100644
--- a/Jellyfin.Server.Implementations/Users/UserManager.cs
+++ b/Jellyfin.Server.Implementations/Users/UserManager.cs
@@ -108,6 +108,7 @@ namespace Jellyfin.Server.Implementations.Users
{
using var dbContext = _dbProvider.CreateContext();
return dbContext.Users
+ .AsQueryable()
.Select(user => user.Id)
.ToList();
}
@@ -200,8 +201,8 @@ namespace Jellyfin.Server.Implementations.Users
internal async Task<User> CreateUserInternalAsync(string name, JellyfinDb dbContext)
{
// TODO: Remove after user item data is migrated.
- var max = await dbContext.Users.AnyAsync().ConfigureAwait(false)
- ? await dbContext.Users.Select(u => u.InternalId).MaxAsync().ConfigureAwait(false)
+ var max = await dbContext.Users.AsQueryable().AnyAsync().ConfigureAwait(false)
+ ? await dbContext.Users.AsQueryable().Select(u => u.InternalId).MaxAsync().ConfigureAwait(false)
: 0;
return new User(
@@ -221,7 +222,7 @@ namespace Jellyfin.Server.Implementations.Users
throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)");
}
- using var dbContext = _dbProvider.CreateContext();
+ await using var dbContext = _dbProvider.CreateContext();
var newUser = await CreateUserInternalAsync(name, dbContext).ConfigureAwait(false);
@@ -588,9 +589,9 @@ namespace Jellyfin.Server.Implementations.Users
public async Task InitializeAsync()
{
// TODO: Refactor the startup wizard so that it doesn't require a user to already exist.
- using var dbContext = _dbProvider.CreateContext();
+ await using var dbContext = _dbProvider.CreateContext();
- if (await dbContext.Users.AnyAsync().ConfigureAwait(false))
+ if (await dbContext.Users.AsQueryable().AnyAsync().ConfigureAwait(false))
{
return;
}
diff --git a/MediaBrowser.Model/Activity/IActivityManager.cs b/MediaBrowser.Model/Activity/IActivityManager.cs
index d5344494e..3e4ea208e 100644
--- a/MediaBrowser.Model/Activity/IActivityManager.cs
+++ b/MediaBrowser.Model/Activity/IActivityManager.cs
@@ -1,10 +1,10 @@
#pragma warning disable CS1591
using System;
-using System.Linq;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Events;
+using Jellyfin.Data.Queries;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Model.Activity
@@ -15,11 +15,6 @@ namespace MediaBrowser.Model.Activity
Task CreateAsync(ActivityLog entry);
- QueryResult<ActivityLogEntry> GetPagedResult(int? startIndex, int? limit);
-
- QueryResult<ActivityLogEntry> GetPagedResult(
- Func<IQueryable<ActivityLog>, IQueryable<ActivityLog>> func,
- int? startIndex,
- int? limit);
+ Task<QueryResult<ActivityLogEntry>> GetPagedResultAsync(ActivityLogQuery query);
}
}