2
0
Эх сурвалжийг харах

Refactored api call logic handling.

ArabCoders 1 жил өмнө
parent
commit
2a25c5a2e3

+ 37 - 0
Emby.Server.Implementations/Library/UserDataManager.cs

@@ -6,6 +6,7 @@ using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Globalization;
+using System.Reflection;
 using System.Threading;
 using Jellyfin.Data.Entities;
 using MediaBrowser.Controller.Configuration;
@@ -81,6 +82,42 @@ namespace Emby.Server.Implementations.Library
             });
         }
 
+        public void SaveUserData(User user, BaseItem item, UserDataDto userDataDto, UserDataSaveReason reason)
+        {
+            ArgumentNullException.ThrowIfNull(user);
+            ArgumentNullException.ThrowIfNull(item);
+            ArgumentNullException.ThrowIfNull(reason);
+            ArgumentNullException.ThrowIfNull(userDataDto);
+
+            var userData = GetUserData(user, item);
+
+            var parentProperties = userDataDto.GetType().GetProperties();
+            var childProperties = userData.GetType().GetProperties();
+
+            foreach (var parentProperty in parentProperties)
+            {
+                foreach (var childProperty in childProperties)
+                {
+                    if (parentProperty.Name != childProperty.Name)
+                    {
+                        continue;
+                    }
+
+                    var value = parentProperty.GetValue(userDataDto, null);
+
+                    if (value is null)
+                    {
+                        continue;
+                    }
+
+                    childProperty.SetValue(userData, value, null);
+                    break;
+                }
+            }
+
+            SaveUserData(user, item, userData, reason, CancellationToken.None);
+        }
+
         /// <summary>
         /// Save the provided user data for the given user.  Batch operation. Does not fire any events or update the cache.
         /// </summary>

+ 8 - 52
Jellyfin.Api/Controllers/ItemsController.cs

@@ -913,13 +913,7 @@ public class ItemsController : BaseJellyfinApiController
     /// </summary>
     /// <param name="userId">The user id.</param>
     /// <param name="itemId">The item id.</param>
-    /// <param name="played">Optional. Whether to mark the item as played.</param>
-    /// <param name="favorite">Optional. Whether to mark the item as favorite.</param>
-    /// <param name="likes">Optional. Whether to mark the item as liked.</param>
-    /// <param name="rating">Optional. User item rating.</param>
-    /// <param name="playbackPositionTicks">Optional. Item playback position ticks. 1 tick = 10000 ms.</param>
-    /// <param name="playCount">Optional. How many times the user played the item.</param>
-    /// <param name="lastPlayedDate">Optional. The date the item was played.</param>
+    /// <param name="userDataDto">New user data object.</param>
     /// <response code="200">return updated user item data.</response>
     /// <response code="404">Item is not found.</response>
     /// <returns>Return <see cref="UserItemDataDto"/>.</returns>
@@ -929,14 +923,13 @@ public class ItemsController : BaseJellyfinApiController
     public ActionResult<UserItemDataDto> UpdateItemUserData(
         [FromRoute, Required] Guid userId,
         [FromRoute, Required] Guid itemId,
-        [FromQuery] bool? played,
-        [FromQuery] bool? favorite,
-        [FromQuery] bool? likes,
-        [FromQuery] double? rating,
-        [FromQuery] long? playbackPositionTicks,
-        [FromQuery] int? playCount,
-        [FromQuery, ModelBinder(typeof(LegacyDateTimeModelBinder))] DateTime? lastPlayedDate)
+        [FromBody, Required] UserDataDto userDataDto)
     {
+        if (!RequestHelpers.AssertCanUpdateUser(_userManager, User, userId, true))
+        {
+            return StatusCode(StatusCodes.Status403Forbidden, "User is not allowed to update this item user data.");
+        }
+
         var user = _userManager.GetUserById(userId) ?? throw new ResourceNotFoundException();
         var item = _libraryManager.GetItemById(itemId);
         if (item == null)
@@ -944,44 +937,7 @@ public class ItemsController : BaseJellyfinApiController
             return NotFound();
         }
 
-        var userData = _userDataRepository.GetUserData(user, item);
-
-        if (played.HasValue)
-        {
-            userData.Played = played.Value;
-        }
-
-        if (favorite.HasValue)
-        {
-            userData.IsFavorite = favorite.Value;
-        }
-
-        if (likes.HasValue)
-        {
-            userData.Likes = likes.Value;
-        }
-
-        if (rating.HasValue)
-        {
-            userData.Rating = rating.Value;
-        }
-
-        if (playbackPositionTicks.HasValue)
-        {
-            userData.PlaybackPositionTicks = playbackPositionTicks.Value;
-        }
-
-        if (playCount.HasValue)
-        {
-            userData.PlayCount = playCount.Value;
-        }
-
-        if (lastPlayedDate.HasValue)
-        {
-            userData.LastPlayedDate = lastPlayedDate.Value;
-        }
-
-        _userDataRepository.SaveUserData(user.Id, item, userData, UserDataSaveReason.UpdateUserData, CancellationToken.None);
+        _userDataRepository.SaveUserData(user, item, userDataDto, UserDataSaveReason.UpdateUserData);
 
         return _userDataRepository.GetUserDataDto(item, user);
     }

+ 9 - 0
MediaBrowser.Controller/Library/IUserDataManager.cs

@@ -35,6 +35,15 @@ namespace MediaBrowser.Controller.Library
 
         void SaveUserData(User user, BaseItem item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken);
 
+        /// <summary>
+        /// Save the provided user data for the given user.
+        /// </summary>
+        /// <param name="user">The user.</param>
+        /// <param name="item">The item.</param>
+        /// <param name="userDataDto">The reason for updating the user data.</param>
+        /// <param name="reason">The reason.</param>
+        void SaveUserData(User user, BaseItem item, UserDataDto userDataDto, UserDataSaveReason reason);
+
         UserItemData GetUserData(User user, BaseItem item);
 
         UserItemData GetUserData(Guid userId, BaseItem item);

+ 43 - 0
MediaBrowser.Model/Dto/UserDataDto.cs

@@ -0,0 +1,43 @@
+#nullable disable
+using System;
+
+namespace MediaBrowser.Model.Dto
+{
+    /// <summary>
+    /// Class UserDataDto extends UserItemDataDto to allow nullable members.
+    /// This change allow us to implement the new /Users/{UserId}/Items/{ItemId}/UserData endpoint.
+    /// This object allows the requestor to update all or specific user data fields without altering the non-nullable members state.
+    /// </summary>
+    public class UserDataDto : UserItemDataDto
+    {
+        /// <summary>
+        /// Gets or sets the playback position ticks.
+        /// </summary>
+        /// <value>The playback position ticks.</value>
+        public new long? PlaybackPositionTicks { get; set; }
+
+        /// <summary>
+        /// Gets or sets the play count.
+        /// </summary>
+        /// <value>The play count.</value>
+        public new int? PlayCount { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this instance is favorite.
+        /// </summary>
+        /// <value><c>true</c> if this instance is favorite; otherwise, <c>false</c>.</value>
+        public new bool? IsFavorite { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this <see cref="UserItemDataDto" /> is likes.
+        /// </summary>
+        /// <value><c>null</c> if [likes] contains no value, <c>true</c> if [likes]; otherwise, <c>false</c>.</value>
+        public new bool? Likes { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value indicating whether this <see cref="UserItemDataDto" /> is played.
+        /// </summary>
+        /// <value><c>true</c> if played; otherwise, <c>false</c>.</value>
+        public new bool? Played { get; set; }
+    }
+}