using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Jellyfin.Data; using Jellyfin.Data.Enums; using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Enums; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Users; using Moq; namespace Jellyfin.Plugin.WatchedTogether.Tests; /// /// Sets up the members whose signatures differ between Jellyfin 10.11 /// and 12, so the suites read the same whichever generation they are compiled against. /// internal static class UserManagerMockExtensions { /// /// Routes ChangePassword to with the user the real server /// would act on: the instance handed in on 10.11, the stored row looked up by id on 12. /// /// The user manager mock. /// The users the mock knows about, used to resolve ids on 12. /// The behaviour to run for the change. public static void SetupChangePassword( this Mock mock, List users, Func onChange) { #if JELLYFIN_12 mock.Setup(m => m.ChangePassword(It.IsAny(), It.IsAny())) .Returns((Guid id, string password) => { var user = users.Find(u => u.Id == id) ?? throw new KeyNotFoundException($"No user with id {id}"); return onChange(user, password); }); #else mock.Setup(m => m.ChangePassword(It.IsAny(), It.IsAny())) .Returns((User user, string password) => onChange(user, password)); #endif } /// /// Models the policy round trip the way Jellyfin's UserManager does it: GetUserDto /// projects the user's live fields into a , and /// UpdatePolicyAsync writes a policy back onto the user entity, so code that reads the /// user afterwards sees what was written. /// /// The user manager mock. /// The users the mock knows about. public static void SetupPolicyRoundTrip(this Mock mock, List users) { mock.Setup(m => m.GetUserDto(It.IsAny(), It.IsAny())) .Returns((User user, string? _) => new UserDto { Id = user.Id, Name = user.Username, Policy = new UserPolicy { IsAdministrator = user.HasPermission(PermissionKind.IsAdministrator), EnableAllFolders = user.HasPermission(PermissionKind.EnableAllFolders), EnabledFolders = user.GetPreferenceValues(PreferenceKind.EnabledFolders), MaxParentalRating = user.MaxParentalRatingScore, MaxParentalSubRating = user.MaxParentalRatingSubScore, BlockUnratedItems = user.GetPreferenceValues(PreferenceKind.BlockUnratedItems), BlockedTags = user.GetPreference(PreferenceKind.BlockedTags), AllowedTags = user.GetPreference(PreferenceKind.AllowedTags), } }); mock.Setup(m => m.UpdatePolicyAsync(It.IsAny(), It.IsAny())) .Returns((Guid id, UserPolicy policy) => { var user = users.Find(u => u.Id == id) ?? throw new KeyNotFoundException($"No user with id {id}"); user.SetPermission(PermissionKind.IsAdministrator, policy.IsAdministrator); user.SetPermission(PermissionKind.EnableAllFolders, policy.EnableAllFolders); user.SetPreference(PreferenceKind.EnabledFolders, policy.EnabledFolders ?? []); user.MaxParentalRatingScore = policy.MaxParentalRating; user.MaxParentalRatingSubScore = policy.MaxParentalSubRating; user.SetPreference(PreferenceKind.BlockUnratedItems, policy.BlockUnratedItems ?? []); user.SetPreference(PreferenceKind.BlockedTags, policy.BlockedTags ?? []); user.SetPreference(PreferenceKind.AllowedTags, policy.AllowedTags ?? []); return Task.CompletedTask; }); } /// /// Sets a user's content restrictions directly, the way the user editor would. /// /// The user to restrict. /// The rating cap, or null for none. /// The sub-score cap at the rating cap. /// The unrated kinds to block. /// The tags that hide an item. /// The whitelist, or none for no whitelist. /// The same user, for chaining. public static User Restrict( this User user, int? maxRating = null, int? maxSubRating = null, IEnumerable? blockUnrated = null, IEnumerable? blockedTags = null, IEnumerable? allowedTags = null) { user.MaxParentalRatingScore = maxRating; user.MaxParentalRatingSubScore = maxSubRating; user.SetPreference(PreferenceKind.BlockUnratedItems, (blockUnrated ?? []).ToArray()); user.SetPreference(PreferenceKind.BlockedTags, (blockedTags ?? []).ToArray()); user.SetPreference(PreferenceKind.AllowedTags, (allowedTags ?? []).ToArray()); return user; } }