diff options
| author | Patrick Barron <barronpm@gmail.com> | 2020-05-15 17:24:01 -0400 |
|---|---|---|
| committer | Patrick Barron <barronpm@gmail.com> | 2020-05-20 10:04:00 -0400 |
| commit | 3eeb6576d8425c8d2917f861b466dfa36e3994df (patch) | |
| tree | b725c19d776a1ee11f3cc7686a01069c9d443e48 /Jellyfin.Data | |
| parent | aca7e221d811040bdb14da6390bbd16c5f7db785 (diff) | |
Migrate User DB to EF Core
Diffstat (limited to 'Jellyfin.Data')
| -rw-r--r-- | Jellyfin.Data/Entities/AccessSchedule.cs | 18 | ||||
| -rw-r--r-- | Jellyfin.Data/Entities/Group.cs | 41 | ||||
| -rw-r--r-- | Jellyfin.Data/Entities/Permission.cs | 53 | ||||
| -rw-r--r-- | Jellyfin.Data/Entities/Preference.cs | 81 | ||||
| -rw-r--r-- | Jellyfin.Data/Entities/User.cs | 141 | ||||
| -rw-r--r-- | Jellyfin.Data/IHasPermissions.cs | 10 |
6 files changed, 167 insertions, 177 deletions
diff --git a/Jellyfin.Data/Entities/AccessSchedule.cs b/Jellyfin.Data/Entities/AccessSchedule.cs index 7966cdb50..711e94dd1 100644 --- a/Jellyfin.Data/Entities/AccessSchedule.cs +++ b/Jellyfin.Data/Entities/AccessSchedule.cs @@ -1,5 +1,7 @@ -using System.ComponentModel.DataAnnotations; +using System; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using System.Text.Json.Serialization; using Jellyfin.Data.Enums; namespace Jellyfin.Data.Entities @@ -20,8 +22,9 @@ namespace Jellyfin.Data.Entities /// <param name="dayOfWeek">The day of the week.</param> /// <param name="startHour">The start hour.</param> /// <param name="endHour">The end hour.</param> - public AccessSchedule(DynamicDayOfWeek dayOfWeek, double startHour, double endHour) + public AccessSchedule(DynamicDayOfWeek dayOfWeek, double startHour, double endHour, Guid userId) { + UserId = userId; DayOfWeek = dayOfWeek; StartHour = startHour; EndHour = endHour; @@ -34,15 +37,20 @@ namespace Jellyfin.Data.Entities /// <param name="startHour">The start hour.</param> /// <param name="endHour">The end hour.</param> /// <returns>The newly created instance.</returns> - public static AccessSchedule CreateInstance(DynamicDayOfWeek dayOfWeek, double startHour, double endHour) + public static AccessSchedule CreateInstance(DynamicDayOfWeek dayOfWeek, double startHour, double endHour, Guid userId) { - return new AccessSchedule(dayOfWeek, startHour, endHour); + return new AccessSchedule(dayOfWeek, startHour, endHour, userId); } + [JsonIgnore] [Key] [Required] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; protected set; } + public int Id { get; set; } + + [Required] + [ForeignKey("Id")] + public Guid UserId { get; set; } /// <summary> /// Gets or sets the day of week. diff --git a/Jellyfin.Data/Entities/Group.cs b/Jellyfin.Data/Entities/Group.cs index 54f9f4905..017fb2234 100644 --- a/Jellyfin.Data/Entities/Group.cs +++ b/Jellyfin.Data/Entities/Group.cs @@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema; namespace Jellyfin.Data.Entities { - public partial class Group + public partial class Group : IHasPermissions, ISavingChanges { partial void Init(); @@ -14,7 +14,7 @@ namespace Jellyfin.Data.Entities /// </summary> protected Group() { - GroupPermissions = new HashSet<Permission>(); + Permissions = new HashSet<Permission>(); ProviderMappings = new HashSet<ProviderMapping>(); Preferences = new HashSet<Preference>(); @@ -22,27 +22,21 @@ namespace Jellyfin.Data.Entities } /// <summary> - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// </summary> - public static Group CreateGroupUnsafe() - { - return new Group(); - } - - /// <summary> /// Public constructor with required data /// </summary> /// <param name="name"></param> - /// <param name="_user0"></param> - public Group(string name, User _user0) + /// <param name="user"></param> + public Group(string name, User user) { - if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name)); - this.Name = name; + if (string.IsNullOrEmpty(name)) + { + throw new ArgumentNullException(nameof(name)); + } - if (_user0 == null) throw new ArgumentNullException(nameof(_user0)); - _user0.Groups.Add(this); + this.Name = name; + user.Groups.Add(this); - this.GroupPermissions = new HashSet<Permission>(); + this.Permissions = new HashSet<Permission>(); this.ProviderMappings = new HashSet<ProviderMapping>(); this.Preferences = new HashSet<Preference>(); @@ -54,9 +48,9 @@ namespace Jellyfin.Data.Entities /// </summary> /// <param name="name"></param> /// <param name="_user0"></param> - public static Group Create(string name, User _user0) + public static Group Create(string name, User user) { - return new Group(name, _user0); + return new Group(name, user); } /************************************************************************* @@ -68,8 +62,7 @@ namespace Jellyfin.Data.Entities /// </summary> [Key] [Required] - [DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public int Id { get; protected set; } + public Guid Id { get; protected set; } /// <summary> /// Required, Max length = 255 @@ -96,13 +89,13 @@ namespace Jellyfin.Data.Entities *************************************************************************/ [ForeignKey("Permission_GroupPermissions_Id")] - public virtual ICollection<Permission> GroupPermissions { get; protected set; } + public ICollection<Permission> Permissions { get; protected set; } [ForeignKey("ProviderMapping_ProviderMappings_Id")] - public virtual ICollection<ProviderMapping> ProviderMappings { get; protected set; } + public ICollection<ProviderMapping> ProviderMappings { get; protected set; } [ForeignKey("Preference_Preferences_Id")] - public virtual ICollection<Preference> Preferences { get; protected set; } + public ICollection<Preference> Preferences { get; protected set; } } } diff --git a/Jellyfin.Data/Entities/Permission.cs b/Jellyfin.Data/Entities/Permission.cs index 0b5b52cbd..136e7abd3 100644 --- a/Jellyfin.Data/Entities/Permission.cs +++ b/Jellyfin.Data/Entities/Permission.cs @@ -3,10 +3,11 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Runtime.CompilerServices; +using Jellyfin.Data.Enums; namespace Jellyfin.Data.Entities { - public partial class Permission + public partial class Permission : ISavingChanges { partial void Init(); @@ -19,32 +20,15 @@ namespace Jellyfin.Data.Entities } /// <summary> - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. - /// </summary> - public static Permission CreatePermissionUnsafe() - { - return new Permission(); - } - - /// <summary> /// Public constructor with required data /// </summary> /// <param name="kind"></param> /// <param name="value"></param> - /// <param name="_user0"></param> - /// <param name="_group1"></param> - public Permission(Enums.PermissionKind kind, bool value, User _user0, Group _group1) + /// <param name="holderId"></param> + public Permission(PermissionKind kind, bool value) { - this.Kind = kind; - - this.Value = value; - - if (_user0 == null) throw new ArgumentNullException(nameof(_user0)); - _user0.Permissions.Add(this); - - if (_group1 == null) throw new ArgumentNullException(nameof(_group1)); - _group1.GroupPermissions.Add(this); - + Kind = kind; + Value = value; Init(); } @@ -54,11 +38,10 @@ namespace Jellyfin.Data.Entities /// </summary> /// <param name="kind"></param> /// <param name="value"></param> - /// <param name="_user0"></param> - /// <param name="_group1"></param> - public static Permission Create(Enums.PermissionKind kind, bool value, User _user0, Group _group1) + /// <param name="holderId"></param> + public static Permission Create(PermissionKind kind, bool value) { - return new Permission(kind, value, _user0, _group1); + return new Permission(kind, value); } /************************************************************************* @@ -76,31 +59,32 @@ namespace Jellyfin.Data.Entities /// <summary> /// Backing field for Kind /// </summary> - protected Enums.PermissionKind _Kind; + protected PermissionKind _Kind; /// <summary> /// When provided in a partial class, allows value of Kind to be changed before setting. /// </summary> - partial void SetKind(Enums.PermissionKind oldValue, ref Enums.PermissionKind newValue); + partial void SetKind(PermissionKind oldValue, ref PermissionKind newValue); /// <summary> /// When provided in a partial class, allows value of Kind to be changed before returning. /// </summary> - partial void GetKind(ref Enums.PermissionKind result); + partial void GetKind(ref PermissionKind result); /// <summary> /// Required /// </summary> [Required] - public Enums.PermissionKind Kind + public PermissionKind Kind { get { - Enums.PermissionKind value = _Kind; + PermissionKind value = _Kind; GetKind(ref value); - return (_Kind = value); + return _Kind = value; } + set { - Enums.PermissionKind oldValue = _Kind; + PermissionKind oldValue = _Kind; SetKind(oldValue, ref value); if (oldValue != value) { @@ -117,7 +101,7 @@ namespace Jellyfin.Data.Entities public bool Value { get; set; } /// <summary> - /// Required, ConcurrenyToken + /// Required, ConcurrencyToken. /// </summary> [ConcurrencyCheck] [Required] @@ -138,7 +122,6 @@ namespace Jellyfin.Data.Entities { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } - } } diff --git a/Jellyfin.Data/Entities/Preference.cs b/Jellyfin.Data/Entities/Preference.cs index 505f52e6b..56a07d440 100644 --- a/Jellyfin.Data/Entities/Preference.cs +++ b/Jellyfin.Data/Entities/Preference.cs @@ -1,63 +1,33 @@ using System; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using Jellyfin.Data.Enums; namespace Jellyfin.Data.Entities { - public partial class Preference + /// <summary> + /// An entity representing a preference attached to a user or group. + /// </summary> + public class Preference : ISavingChanges { - partial void Init(); - - /// <summary> - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// </summary> - protected Preference() - { - Init(); - } - /// <summary> - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. + /// Initializes a new instance of the <see cref="Preference"/> class. + /// Public constructor with required data. /// </summary> - public static Preference CreatePreferenceUnsafe() + /// <param name="kind">The preference kind.</param> + /// <param name="value">The value.</param> + public Preference(PreferenceKind kind, string value) { - return new Preference(); + Kind = kind; + Value = value ?? throw new ArgumentNullException(nameof(value)); } /// <summary> - /// Public constructor with required data - /// </summary> - /// <param name="kind"></param> - /// <param name="value"></param> - /// <param name="_user0"></param> - /// <param name="_group1"></param> - public Preference(Enums.PreferenceKind kind, string value, User _user0, Group _group1) - { - this.Kind = kind; - - if (string.IsNullOrEmpty(value)) throw new ArgumentNullException(nameof(value)); - this.Value = value; - - if (_user0 == null) throw new ArgumentNullException(nameof(_user0)); - _user0.Preferences.Add(this); - - if (_group1 == null) throw new ArgumentNullException(nameof(_group1)); - _group1.Preferences.Add(this); - - - Init(); - } - - /// <summary> - /// Static create function (for use in LINQ queries, etc.) + /// Initializes a new instance of the <see cref="Preference"/> class. + /// Default constructor. Protected due to required properties, but present because EF needs it. /// </summary> - /// <param name="kind"></param> - /// <param name="value"></param> - /// <param name="_user0"></param> - /// <param name="_group1"></param> - public static Preference Create(Enums.PreferenceKind kind, string value, User _user0, Group _group1) + protected Preference() { - return new Preference(kind, value, _user0, _group1); } /************************************************************************* @@ -76,7 +46,7 @@ namespace Jellyfin.Data.Entities /// Required /// </summary> [Required] - public Enums.PreferenceKind Kind { get; set; } + public PreferenceKind Kind { get; set; } /// <summary> /// Required, Max length = 65535 @@ -87,21 +57,28 @@ namespace Jellyfin.Data.Entities public string Value { get; set; } /// <summary> - /// Required, ConcurrenyToken + /// Required, ConcurrencyToken. /// </summary> [ConcurrencyCheck] [Required] public uint RowVersion { get; set; } + /// <summary> + /// Static create function (for use in LINQ queries, etc.) + /// </summary> + /// <param name="kind">The preference kind.</param> + /// <param name="value">The value.</param> + /// <returns>The new instance.</returns> + public static Preference Create(PreferenceKind kind, string value) + { + return new Preference(kind, value); + } + + /// <inheritdoc/> public void OnSavingChanges() { RowVersion++; } - - /************************************************************************* - * Navigation properties - *************************************************************************/ - } } diff --git a/Jellyfin.Data/Entities/User.cs b/Jellyfin.Data/Entities/User.cs index 17913959e..7252ef230 100644 --- a/Jellyfin.Data/Entities/User.cs +++ b/Jellyfin.Data/Entities/User.cs @@ -9,45 +9,23 @@ using Jellyfin.Data.Enums; namespace Jellyfin.Data.Entities { - public partial class User + /// <summary> + /// An entity representing a user. + /// </summary> + public partial class User : IHasPermissions, ISavingChanges { /// <summary> /// The values being delimited here are Guids, so commas work as they do not appear in Guids. /// </summary> private const char Delimiter = ','; - partial void Init(); - - /// <summary> - /// Default constructor. Protected due to required properties, but present because EF needs it. - /// </summary> - protected User() - { - Groups = new HashSet<Group>(); - Permissions = new HashSet<Permission>(); - ProviderMappings = new HashSet<ProviderMapping>(); - Preferences = new HashSet<Preference>(); - AccessSchedules = new HashSet<AccessSchedule>(); - - Init(); - } - /// <summary> - /// Public constructor with required data + /// Initializes a new instance of the <see cref="User"/> class. + /// Public constructor with required data. /// </summary> - /// <param name="username"></param> - /// <param name="mustUpdatePassword"></param> - /// <param name="authenticationProviderId"></param> - /// <param name="invalidLoginAttemptCount"></param> - /// <param name="subtitleMode"></param> - /// <param name="playDefaultAudioTrack"></param> - public User( - string username, - bool mustUpdatePassword, - string authenticationProviderId, - int invalidLoginAttemptCount, - SubtitlePlaybackMode subtitleMode, - bool playDefaultAudioTrack) + /// <param name="username">The username for the new user.</param> + /// <param name="authenticationProviderId">The authentication provider's Id</param> + public User(string username, string authenticationProviderId) { if (string.IsNullOrEmpty(username)) { @@ -60,11 +38,7 @@ namespace Jellyfin.Data.Entities } Username = username; - MustUpdatePassword = mustUpdatePassword; AuthenticationProviderId = authenticationProviderId; - InvalidLoginAttemptCount = invalidLoginAttemptCount; - SubtitleMode = subtitleMode; - PlayDefaultAudioTrack = playDefaultAudioTrack; Groups = new HashSet<Group>(); Permissions = new HashSet<Permission>(); @@ -74,6 +48,8 @@ namespace Jellyfin.Data.Entities // Set default values Id = Guid.NewGuid(); + InvalidLoginAttemptCount = 0; + MustUpdatePassword = false; DisplayMissingEpisodes = false; DisplayCollectionsView = false; HidePlayedInLatest = true; @@ -81,36 +57,40 @@ namespace Jellyfin.Data.Entities RememberSubtitleSelections = true; EnableNextEpisodeAutoPlay = true; EnableAutoLogin = false; + PlayDefaultAudioTrack = true; + SubtitleMode = SubtitlePlaybackMode.Default; + AddDefaultPermissions(); + AddDefaultPreferences(); Init(); } /// <summary> - /// Replaces default constructor, since it's protected. Caller assumes responsibility for setting all required values before saving. + /// Initializes a new instance of the <see cref="User"/> class. + /// Default constructor. Protected due to required properties, but present because EF needs it. /// </summary> - public static User CreateUserUnsafe() + protected User() { - return new User(); + Groups = new HashSet<Group>(); + Permissions = new HashSet<Permission>(); + ProviderMappings = new HashSet<ProviderMapping>(); + Preferences = new HashSet<Preference>(); + AccessSchedules = new HashSet<AccessSchedule>(); + + AddDefaultPermissions(); + AddDefaultPreferences(); + Init(); } /// <summary> /// Static create function (for use in LINQ queries, etc.) /// </summary> - /// <param name="username"></param> - /// <param name="mustUpdatePassword"></param> - /// <param name="authenticationProviderId"></param> - /// <param name="invalidLoginAttemptCount"></param> - /// <param name="subtitleMode"></param> - /// <param name="playDefaultAudioTrack"></param> - public static User Create( - string username, - bool mustUpdatePassword, - string authenticationProviderId, - int invalidLoginAttemptCount, - SubtitlePlaybackMode subtitleMode, - bool playDefaultAudioTrack) + /// <param name="username">The username for the created user.</param> + /// <param name="authenticationProviderId">The Id of the user's authentication provider.</param> + /// <returns>The created instance.</returns> + public static User Create(string username, string authenticationProviderId) { - return new User(username, mustUpdatePassword, authenticationProviderId, invalidLoginAttemptCount, subtitleMode, playDefaultAudioTrack); + return new User(username, authenticationProviderId); } /************************************************************************* @@ -131,7 +111,6 @@ namespace Jellyfin.Data.Entities [Required] [MaxLength(255)] [StringLength(255)] - [JsonPropertyName("Name")] public string Username { get; set; } /// <summary> @@ -199,6 +178,7 @@ namespace Jellyfin.Data.Entities public bool PlayDefaultAudioTrack { get; set; } /// <summary> + /// Gets or sets the subtitle language preference. /// Max length = 255 /// </summary> [MaxLength(255)] @@ -237,6 +217,7 @@ namespace Jellyfin.Data.Entities public int? RemoteClientBitrateLimit { get; set; } /// <summary> + /// Gets or sets the internal id. /// This is a temporary stopgap for until the library db is migrated. /// This corresponds to the value of the index of this user in the library db. /// </summary> @@ -246,7 +227,8 @@ namespace Jellyfin.Data.Entities public ImageInfo ProfileImage { get; set; } /// <summary> - /// Required, ConcurrenyToken + /// Gets or sets the row version. + /// Required, ConcurrenyToken. /// </summary> [ConcurrencyCheck] [Required] @@ -260,23 +242,25 @@ namespace Jellyfin.Data.Entities /************************************************************************* * Navigation properties *************************************************************************/ - [ForeignKey("Group_Groups_Id")] + [ForeignKey("Group_Groups_Guid")] public ICollection<Group> Groups { get; protected set; } - [ForeignKey("Permission_Permissions_Id")] + [ForeignKey("Permission_Permissions_Guid")] public ICollection<Permission> Permissions { get; protected set; } [ForeignKey("ProviderMapping_ProviderMappings_Id")] public ICollection<ProviderMapping> ProviderMappings { get; protected set; } - [ForeignKey("Preference_Preferences_Id")] + [ForeignKey("Preference_Preferences_Guid")] public ICollection<Preference> Preferences { get; protected set; } public ICollection<AccessSchedule> AccessSchedules { get; protected set; } + partial void Init(); + public bool HasPermission(PermissionKind permission) { - return Permissions.Select(p => p.Kind).Contains(permission); + return Permissions.First(p => p.Kind == permission).Value; } public void SetPermission(PermissionKind kind, bool value) @@ -287,11 +271,12 @@ namespace Jellyfin.Data.Entities public string[] GetPreference(PreferenceKind preference) { - return Preferences + var val = Preferences .Where(p => p.Kind == preference) .Select(p => p.Value) - .First() - .Split(Delimiter); + .First(); + + return Equals(val, string.Empty) ? Array.Empty<string>() : val.Split(Delimiter); } public void SetPreference(PreferenceKind preference, string[] values) @@ -332,5 +317,39 @@ namespace Jellyfin.Data.Entities return hour >= schedule.StartHour && hour <= schedule.EndHour; } + + // TODO: make these user configurable? + private void AddDefaultPermissions() + { + Permissions.Add(new Permission(PermissionKind.IsAdministrator, false)); + Permissions.Add(new Permission(PermissionKind.IsDisabled, false)); + Permissions.Add(new Permission(PermissionKind.IsHidden, false)); + Permissions.Add(new Permission(PermissionKind.EnableAllChannels, false)); + Permissions.Add(new Permission(PermissionKind.EnableAllDevices, true)); + Permissions.Add(new Permission(PermissionKind.EnableAllFolders, false)); + Permissions.Add(new Permission(PermissionKind.EnableContentDeletion, false)); + Permissions.Add(new Permission(PermissionKind.EnableContentDownloading, true)); + Permissions.Add(new Permission(PermissionKind.EnableMediaConversion, true)); + Permissions.Add(new Permission(PermissionKind.EnableMediaPlayback, true)); + Permissions.Add(new Permission(PermissionKind.EnablePlaybackRemuxing, true)); + Permissions.Add(new Permission(PermissionKind.EnablePublicSharing, true)); + Permissions.Add(new Permission(PermissionKind.EnableRemoteAccess, true)); + Permissions.Add(new Permission(PermissionKind.EnableSyncTranscoding, true)); + Permissions.Add(new Permission(PermissionKind.EnableAudioPlaybackTranscoding, true)); + Permissions.Add(new Permission(PermissionKind.EnableLiveTvAccess, true)); + Permissions.Add(new Permission(PermissionKind.EnableLiveTvManagement, true)); + Permissions.Add(new Permission(PermissionKind.EnableSharedDeviceControl, true)); + Permissions.Add(new Permission(PermissionKind.EnableVideoPlaybackTranscoding, true)); + Permissions.Add(new Permission(PermissionKind.ForceRemoteSourceTranscoding, false)); + Permissions.Add(new Permission(PermissionKind.EnableRemoteControlOfOtherUsers, false)); + } + + private void AddDefaultPreferences() + { + foreach (var val in Enum.GetValues(typeof(PreferenceKind)).Cast<PreferenceKind>()) + { + Preferences.Add(new Preference(val, string.Empty)); + } + } } } diff --git a/Jellyfin.Data/IHasPermissions.cs b/Jellyfin.Data/IHasPermissions.cs new file mode 100644 index 000000000..a77e51e1e --- /dev/null +++ b/Jellyfin.Data/IHasPermissions.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using Jellyfin.Data.Entities; + +namespace Jellyfin.Data +{ + public interface IHasPermissions + { + ICollection<Permission> Permissions { get; } + } +} |
