diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs new file mode 100644 index 000000000..6742bffc6 --- /dev/null +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -0,0 +1,139 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Net; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Api.Controllers +{ + /// + /// Image controller. + /// + public class ImageController : BaseJellyfinApiController + { + private readonly IUserManager _userManager; + private readonly ILibraryManager _libraryManager; + private readonly IProviderManager _providerManager; + private readonly IImageProcessor _imageProcessor; + private readonly IFileSystem _fileSystem; + private readonly IAuthorizationContext _authContext; + private readonly ILogger _logger; + private readonly IServerConfigurationManager _serverConfigurationManager; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public ImageController( + IUserManager userManager, + ILibraryManager libraryManager, + IProviderManager providerManager, + IImageProcessor imageProcessor, + IFileSystem fileSystem, + IAuthorizationContext authContext, + ILogger logger, + IServerConfigurationManager serverConfigurationManager) + { + _userManager = userManager; + _libraryManager = libraryManager; + _providerManager = providerManager; + _imageProcessor = imageProcessor; + _fileSystem = fileSystem; + _authContext = authContext; + _logger = logger; + _serverConfigurationManager = serverConfigurationManager; + } + + /// + /// Sets the user image. + /// + /// User Id. + /// (Unused) Image type. + /// (Unused) Image index. + /// Image updated. + /// A . + [HttpPost("/Users/{userId}/Images/{imageType}")] + [HttpPost("/Users/{userId}/Images/{imageType}/{index}")] + public async Task PostUserImage( + [FromRoute] Guid userId, + [FromRoute] ImageType imageType, + [FromRoute] int? index) + { + // TODO AssertCanUpdateUser(_authContext, _userManager, id, true); + + var user = _userManager.GetUserById(userId); + await using var memoryStream = await GetMemoryStream(Request.Body).ConfigureAwait(false); + + // Handle image/png; charset=utf-8 + var mimeType = Request.ContentType.Split(';').FirstOrDefault(); + var userDataPath = Path.Combine(_serverConfigurationManager.ApplicationPaths.UserConfigurationDirectoryPath, user.Username); + user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType))); + + await _providerManager + .SaveImage(user, memoryStream, mimeType, user.ProfileImage.Path) + .ConfigureAwait(false); + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + + return NoContent(); + } + + /// + /// Delete the user's image. + /// + /// User Id. + /// (Unused) Image type. + /// (Unused) Image index. + /// Image deleted. + /// A . + [HttpDelete("/Users/{userId}/Images/{itemType}")] + [HttpDelete("/Users/{userId}/Images/{itemType}/{index}")] + public ActionResult DeleteUserImage( + [FromRoute] Guid userId, + [FromRoute] ImageType imageType, + [FromRoute] int? index) + { + // TODO AssertCanUpdateUser(_authContext, _userManager, userId, true); + + var user = _userManager.GetUserById(userId); + try + { + System.IO.File.Delete(user.ProfileImage.Path); + } + catch (IOException e) + { + _logger.LogError(e, "Error deleting user profile image:"); + } + + _userManager.ClearProfileImage(user); + return NoContent(); + } + + private static async Task GetMemoryStream(Stream inputStream) + { + using var reader = new StreamReader(inputStream); + var text = await reader.ReadToEndAsync().ConfigureAwait(false); + + var bytes = Convert.FromBase64String(text); + return new MemoryStream(bytes) + { + Position = 0 + }; + } + } +} diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 0b8ddeacd..48c879bb7 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -163,44 +163,6 @@ namespace MediaBrowser.Api.Images public string Id { get; set; } } - /// - /// Class DeleteUserImage - /// - [Route("/Users/{Id}/Images/{Type}", "DELETE")] - [Route("/Users/{Id}/Images/{Type}/{Index}", "DELETE")] - [Authenticated] - public class DeleteUserImage : DeleteImageRequest, IReturnVoid - { - /// - /// Gets or sets the id. - /// - /// The id. - [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public Guid Id { get; set; } - } - - /// - /// Class PostUserImage - /// - [Route("/Users/{Id}/Images/{Type}", "POST")] - [Route("/Users/{Id}/Images/{Type}/{Index}", "POST")] - [Authenticated] - public class PostUserImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid - { - /// - /// Gets or sets the id. - /// - /// The id. - [ApiMember(Name = "Id", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string Id { get; set; } - - /// - /// The raw Http Request Input Stream - /// - /// The request stream. - public Stream RequestStream { get; set; } - } - /// /// Class PostItemImage /// @@ -438,23 +400,6 @@ namespace MediaBrowser.Api.Images return GetImage(request, item.Id, item, true); } - /// - /// Posts the specified request. - /// - /// The request. - public Task Post(PostUserImage request) - { - var id = Guid.Parse(GetPathValue(1)); - - AssertCanUpdateUser(_authContext, _userManager, id, true); - - request.Type = Enum.Parse(GetPathValue(3).ToString(), true); - - var user = _userManager.GetUserById(id); - - return PostImage(user, request.RequestStream, Request.ContentType); - } - /// /// Posts the specified request. /// @@ -470,28 +415,6 @@ namespace MediaBrowser.Api.Images return PostImage(item, request.RequestStream, request.Type, Request.ContentType); } - /// - /// Deletes the specified request. - /// - /// The request. - public void Delete(DeleteUserImage request) - { - var userId = request.Id; - AssertCanUpdateUser(_authContext, _userManager, userId, true); - - var user = _userManager.GetUserById(userId); - try - { - File.Delete(user.ProfileImage.Path); - } - catch (IOException e) - { - Logger.LogError(e, "Error deleting user profile image:"); - } - - _userManager.ClearProfileImage(user); - } - /// /// Deletes the specified request. ///