aboutsummaryrefslogtreecommitdiff
path: root/Jellyfin.Data/UserEntityExtensions.cs
blob: 8d84a6b6e190e27a48e034c88517854d82b02154 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
using System;
using System.ComponentModel;
using System.Linq;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using Jellyfin.Data.Interfaces;

namespace Jellyfin.Data;

/// <summary>
/// Contains extension methods for manipulation of <see cref="User"/> entities.
/// </summary>
public static class UserEntityExtensions
{
    /// <summary>
    /// The values being delimited here are Guids, so commas work as they do not appear in Guids.
    /// </summary>
    private const char Delimiter = ',';

    /// <summary>
    /// Checks whether the user has the specified permission.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    /// <param name="kind">The permission kind.</param>
    /// <returns><c>True</c> if the user has the specified permission.</returns>
    public static bool HasPermission(this IHasPermissions entity, PermissionKind kind)
    {
        return entity.Permissions.FirstOrDefault(p => p.Kind == kind)?.Value ?? false;
    }

    /// <summary>
    /// Sets the given permission kind to the provided value.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    /// <param name="kind">The permission kind.</param>
    /// <param name="value">The value to set.</param>
    public static void SetPermission(this IHasPermissions entity, PermissionKind kind, bool value)
    {
        var currentPermission = entity.Permissions.FirstOrDefault(p => p.Kind == kind);
        if (currentPermission is null)
        {
            entity.Permissions.Add(new Permission(kind, value));
        }
        else
        {
            currentPermission.Value = value;
        }
    }

    /// <summary>
    /// Gets the user's preferences for the given preference kind.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    /// <param name="preference">The preference kind.</param>
    /// <returns>A string array containing the user's preferences.</returns>
    public static string[] GetPreference(this User entity, PreferenceKind preference)
    {
        var val = entity.Preferences.FirstOrDefault(p => p.Kind == preference)?.Value;

        return string.IsNullOrEmpty(val) ? Array.Empty<string>() : val.Split(Delimiter);
    }

    /// <summary>
    /// Gets the user's preferences for the given preference kind.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    /// <param name="preference">The preference kind.</param>
    /// <typeparam name="T">Type of preference.</typeparam>
    /// <returns>A {T} array containing the user's preference.</returns>
    public static T[] GetPreferenceValues<T>(this User entity, PreferenceKind preference)
    {
        var val = entity.Preferences.FirstOrDefault(p => p.Kind == preference)?.Value;
        if (string.IsNullOrEmpty(val))
        {
            return Array.Empty<T>();
        }

        // Convert array of {string} to array of {T}
        var converter = TypeDescriptor.GetConverter(typeof(T));
        var stringValues = val.Split(Delimiter);
        var convertedCount = 0;
        var parsedValues = new T[stringValues.Length];
        for (var i = 0; i < stringValues.Length; i++)
        {
            try
            {
                var parsedValue = converter.ConvertFromString(stringValues[i].Trim());
                if (parsedValue is not null)
                {
                    parsedValues[convertedCount++] = (T)parsedValue;
                }
            }
            catch (FormatException)
            {
                // Unable to convert value
            }
        }

        return parsedValues[..convertedCount];
    }

    /// <summary>
    /// Sets the specified preference to the given value.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    /// <param name="preference">The preference kind.</param>
    /// <param name="values">The values.</param>
    public static void SetPreference(this User entity, PreferenceKind preference, string[] values)
    {
        var value = string.Join(Delimiter, values);
        var currentPreference = entity.Preferences.FirstOrDefault(p => p.Kind == preference);
        if (currentPreference is null)
        {
            entity.Preferences.Add(new Preference(preference, value));
        }
        else
        {
            currentPreference.Value = value;
        }
    }

    /// <summary>
    /// Sets the specified preference to the given value.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    /// <param name="preference">The preference kind.</param>
    /// <param name="values">The values.</param>
    /// <typeparam name="T">The type of value.</typeparam>
    public static void SetPreference<T>(this User entity, PreferenceKind preference, T[] values)
    {
        var value = string.Join(Delimiter, values);
        var currentPreference = entity.Preferences.FirstOrDefault(p => p.Kind == preference);
        if (currentPreference is null)
        {
            entity.Preferences.Add(new Preference(preference, value));
        }
        else
        {
            currentPreference.Value = value;
        }
    }

    /// <summary>
    /// Checks whether this user is currently allowed to use the server.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    /// <returns><c>True</c> if the current time is within an access schedule, or there are no access schedules.</returns>
    public static bool IsParentalScheduleAllowed(this User entity)
    {
        return entity.AccessSchedules.Count == 0
               || entity.AccessSchedules.Any(i => IsParentalScheduleAllowed(i, DateTime.UtcNow));
    }

    /// <summary>
    /// Checks whether the provided folder is in this user's grouped folders.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    /// <param name="id">The Guid of the folder.</param>
    /// <returns><c>True</c> if the folder is in the user's grouped folders.</returns>
    public static bool IsFolderGrouped(this User entity, Guid id)
    {
        return Array.IndexOf(GetPreferenceValues<Guid>(entity, PreferenceKind.GroupedFolders), id) != -1;
    }

    /// <summary>
    /// Initializes the default permissions for a user. Should only be called on user creation.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    // TODO: make these user configurable?
    public static void AddDefaultPermissions(this User entity)
    {
        entity.Permissions.Add(new Permission(PermissionKind.IsAdministrator, false));
        entity.Permissions.Add(new Permission(PermissionKind.IsDisabled, false));
        entity.Permissions.Add(new Permission(PermissionKind.IsHidden, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableAllChannels, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableAllDevices, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableAllFolders, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableContentDeletion, false));
        entity.Permissions.Add(new Permission(PermissionKind.EnableContentDownloading, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableMediaConversion, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableMediaPlayback, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnablePlaybackRemuxing, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnablePublicSharing, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableRemoteAccess, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableSyncTranscoding, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableAudioPlaybackTranscoding, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableLiveTvAccess, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableLiveTvManagement, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableSharedDeviceControl, true));
        entity.Permissions.Add(new Permission(PermissionKind.EnableVideoPlaybackTranscoding, true));
        entity.Permissions.Add(new Permission(PermissionKind.ForceRemoteSourceTranscoding, false));
        entity.Permissions.Add(new Permission(PermissionKind.EnableRemoteControlOfOtherUsers, false));
        entity.Permissions.Add(new Permission(PermissionKind.EnableCollectionManagement, false));
        entity.Permissions.Add(new Permission(PermissionKind.EnableSubtitleManagement, false));
        entity.Permissions.Add(new Permission(PermissionKind.EnableLyricManagement, false));
    }

    /// <summary>
    /// Initializes the default preferences. Should only be called on user creation.
    /// </summary>
    /// <param name="entity">The entity to update.</param>
    public static void AddDefaultPreferences(this User entity)
    {
        foreach (var val in Enum.GetValues<PreferenceKind>())
        {
            entity.Preferences.Add(new Preference(val, string.Empty));
        }
    }

    private static bool IsParentalScheduleAllowed(AccessSchedule schedule, DateTime date)
    {
        var localTime = date.ToLocalTime();
        var hour = localTime.TimeOfDay.TotalHours;
        var currentDayOfWeek = localTime.DayOfWeek;

        return schedule.DayOfWeek.Contains(currentDayOfWeek)
               && hour >= schedule.StartHour
               && hour <= schedule.EndHour;
    }
}