From 1180b9746fe7c4a6562baff77910819a6706510b Mon Sep 17 00:00:00 2001 From: ZadenRB Date: Wed, 15 Apr 2020 00:01:31 -0600 Subject: [PATCH] Migrates the notifications service to use ASP.NET MVC framework --- .../Api/NotificationsService.cs | 189 ------------------ .../Controllers/NotificationsController.cs | 138 +++++++++++++ .../NotificationDtos/NotificationDto.cs | 51 +++++ .../NotificationsSummaryDto.cs | 20 ++ .../ApiServiceCollectionExtensions.cs | 1 + 5 files changed, 210 insertions(+), 189 deletions(-) delete mode 100644 Emby.Notifications/Api/NotificationsService.cs create mode 100644 Jellyfin.Api/Controllers/NotificationsController.cs create mode 100644 Jellyfin.Api/Models/NotificationDtos/NotificationDto.cs create mode 100644 Jellyfin.Api/Models/NotificationDtos/NotificationsSummaryDto.cs diff --git a/Emby.Notifications/Api/NotificationsService.cs b/Emby.Notifications/Api/NotificationsService.cs deleted file mode 100644 index 788750796..000000000 --- a/Emby.Notifications/Api/NotificationsService.cs +++ /dev/null @@ -1,189 +0,0 @@ -#pragma warning disable CS1591 -#pragma warning disable SA1402 -#pragma warning disable SA1649 - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Notifications; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Notifications; -using MediaBrowser.Model.Services; - -namespace Emby.Notifications.Api -{ - [Route("/Notifications/{UserId}", "GET", Summary = "Gets notifications")] - public class GetNotifications : IReturn - { - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string UserId { get; set; } = string.Empty; - - [ApiMember(Name = "IsRead", Description = "An optional filter by IsRead", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] - public bool? IsRead { get; set; } - - [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] - public int? StartIndex { get; set; } - - [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] - public int? Limit { get; set; } - } - - public class Notification - { - public string Id { get; set; } = string.Empty; - - public string UserId { get; set; } = string.Empty; - - public DateTime Date { get; set; } - - public bool IsRead { get; set; } - - public string Name { get; set; } = string.Empty; - - public string Description { get; set; } = string.Empty; - - public string Url { get; set; } = string.Empty; - - public NotificationLevel Level { get; set; } - } - - public class NotificationResult - { - public IReadOnlyList Notifications { get; set; } = Array.Empty(); - - public int TotalRecordCount { get; set; } - } - - public class NotificationsSummary - { - public int UnreadCount { get; set; } - - public NotificationLevel MaxUnreadNotificationLevel { get; set; } - } - - [Route("/Notifications/{UserId}/Summary", "GET", Summary = "Gets a notification summary for a user")] - public class GetNotificationsSummary : IReturn - { - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string UserId { get; set; } = string.Empty; - } - - [Route("/Notifications/Types", "GET", Summary = "Gets notification types")] - public class GetNotificationTypes : IReturn> - { - } - - [Route("/Notifications/Services", "GET", Summary = "Gets notification types")] - public class GetNotificationServices : IReturn> - { - } - - [Route("/Notifications/Admin", "POST", Summary = "Sends a notification to all admin users")] - public class AddAdminNotification : IReturnVoid - { - [ApiMember(Name = "Name", Description = "The notification's name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string Name { get; set; } = string.Empty; - - [ApiMember(Name = "Description", Description = "The notification's description", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string Description { get; set; } = string.Empty; - - [ApiMember(Name = "ImageUrl", Description = "The notification's image url", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] - public string? ImageUrl { get; set; } - - [ApiMember(Name = "Url", Description = "The notification's info url", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] - public string? Url { get; set; } - - [ApiMember(Name = "Level", Description = "The notification level", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] - public NotificationLevel Level { get; set; } - } - - [Route("/Notifications/{UserId}/Read", "POST", Summary = "Marks notifications as read")] - public class MarkRead : IReturnVoid - { - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string UserId { get; set; } = string.Empty; - - [ApiMember(Name = "Ids", Description = "A list of notification ids, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)] - public string Ids { get; set; } = string.Empty; - } - - [Route("/Notifications/{UserId}/Unread", "POST", Summary = "Marks notifications as unread")] - public class MarkUnread : IReturnVoid - { - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string UserId { get; set; } = string.Empty; - - [ApiMember(Name = "Ids", Description = "A list of notification ids, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)] - public string Ids { get; set; } = string.Empty; - } - - [Authenticated] - public class NotificationsService : IService - { - private readonly INotificationManager _notificationManager; - private readonly IUserManager _userManager; - - public NotificationsService(INotificationManager notificationManager, IUserManager userManager) - { - _notificationManager = notificationManager; - _userManager = userManager; - } - - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")] - public object Get(GetNotificationTypes request) - { - return _notificationManager.GetNotificationTypes(); - } - - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")] - public object Get(GetNotificationServices request) - { - return _notificationManager.GetNotificationServices().ToList(); - } - - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")] - public object Get(GetNotificationsSummary request) - { - return new NotificationsSummary - { - }; - } - - public Task Post(AddAdminNotification request) - { - // This endpoint really just exists as post of a real with sickbeard - var notification = new NotificationRequest - { - Date = DateTime.UtcNow, - Description = request.Description, - Level = request.Level, - Name = request.Name, - Url = request.Url, - UserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id).ToArray() - }; - - return _notificationManager.SendNotification(notification, CancellationToken.None); - } - - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")] - public void Post(MarkRead request) - { - } - - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")] - public void Post(MarkUnread request) - { - } - - [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")] - public object Get(GetNotifications request) - { - return new NotificationResult(); - } - } -} diff --git a/Jellyfin.Api/Controllers/NotificationsController.cs b/Jellyfin.Api/Controllers/NotificationsController.cs new file mode 100644 index 000000000..6602fca9c --- /dev/null +++ b/Jellyfin.Api/Controllers/NotificationsController.cs @@ -0,0 +1,138 @@ +#nullable enable +#pragma warning disable CA1801 +#pragma warning disable SA1313 + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Jellyfin.Api.Models.NotificationDtos; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Notifications; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Notifications; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Controllers +{ + /// + /// The notification controller. + /// + public class NotificationsController : BaseJellyfinApiController + { + private readonly INotificationManager _notificationManager; + private readonly IUserManager _userManager; + + /// + /// Initializes a new instance of the class. + /// + /// The notification manager. + /// The user manager. + public NotificationsController(INotificationManager notificationManager, IUserManager userManager) + { + _notificationManager = notificationManager; + _userManager = userManager; + } + + /// + /// Endpoint for getting a user's notifications. + /// + /// The UserID. + /// An optional filter by IsRead. + /// The optional index to start at. All notifications with a lower index will be dropped from the results. + /// An optional limit on the number of notifications returned. + /// A read-only list of all of the user's notifications. + [HttpGet("{UserID}")] + public IReadOnlyList GetNotifications( + [FromRoute] string UserID, + [FromQuery] bool? IsRead, + [FromQuery] int? StartIndex, + [FromQuery] int? Limit) + { + return new List(); + } + + /// + /// Endpoint for getting a user's notification summary. + /// + /// The UserID. + /// Notifications summary for the user. + [HttpGet("{UserId}/Summary")] + public NotificationsSummaryDto GetNotificationsSummary( + [FromRoute] string UserID) + { + return new NotificationsSummaryDto(); + } + + /// + /// Endpoint for getting notification types. + /// + /// All notification types. + [HttpGet("Types")] + public IEnumerable GetNotificationTypes() + { + return _notificationManager.GetNotificationTypes(); + } + + /// + /// Endpoint for getting notification services. + /// + /// All notification services. + [HttpGet("Services")] + public IEnumerable GetNotificationServices() + { + return _notificationManager.GetNotificationServices(); + } + + /// + /// Endpoint to send a notification to all admins. + /// + /// The name of the notification. + /// The description of the notification. + /// The URL of the notification. + /// The level of the notification. + [HttpPost("Admin")] + public void CreateAdminNotification( + [FromForm] string Name, + [FromForm] string Description, + [FromForm] string? URL, + [FromForm] NotificationLevel Level) + { + var notification = new NotificationRequest + { + Name = Name, + Description = Description, + Url = URL, + Level = Level, + UserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id).ToArray(), + Date = DateTime.UtcNow, + }; + + _notificationManager.SendNotification(notification, CancellationToken.None); + } + + /// + /// Endpoint to set notifications as read. + /// + /// The UserID. + /// The IDs of notifications which should be set as read. + [HttpPost("{UserID}/Read")] + public void SetRead( + [FromRoute] string UserID, + [FromForm] List IDs) + { + } + + /// + /// Endpoint to set notifications as unread. + /// + /// The UserID. + /// The IDs of notifications which should be set as unread. + [HttpPost("{UserID}/Unread")] + public void SetUnread( + [FromRoute] string UserID, + [FromForm] List IDs) + { + } + } +} diff --git a/Jellyfin.Api/Models/NotificationDtos/NotificationDto.cs b/Jellyfin.Api/Models/NotificationDtos/NotificationDto.cs new file mode 100644 index 000000000..7ecd2a49d --- /dev/null +++ b/Jellyfin.Api/Models/NotificationDtos/NotificationDto.cs @@ -0,0 +1,51 @@ +using System; +using MediaBrowser.Model.Notifications; + +namespace Jellyfin.Api.Models.NotificationDtos +{ + /// + /// The notification DTO. + /// + public class NotificationDto + { + /// + /// Gets or sets the notification ID. Defaults to an empty string. + /// + public string Id { get; set; } = string.Empty; + + /// + /// Gets or sets the notification's user ID. Defaults to an empty string. + /// + public string UserId { get; set; } = string.Empty; + + /// + /// Gets or sets the notification date. + /// + public DateTime Date { get; set; } + + /// + /// Gets or sets a value indicating whether the notification has been read. + /// + public bool IsRead { get; set; } + + /// + /// Gets or sets the notification's name. + /// + public string Name { get; set; } = string.Empty; + + /// + /// Gets or sets the notification's description. + /// + public string Description { get; set; } = string.Empty; + + /// + /// Gets or sets the notification's URL. + /// + public string Url { get; set; } = string.Empty; + + /// + /// Gets or sets the notification level. + /// + public NotificationLevel Level { get; set; } + } +} diff --git a/Jellyfin.Api/Models/NotificationDtos/NotificationsSummaryDto.cs b/Jellyfin.Api/Models/NotificationDtos/NotificationsSummaryDto.cs new file mode 100644 index 000000000..c18ab545d --- /dev/null +++ b/Jellyfin.Api/Models/NotificationDtos/NotificationsSummaryDto.cs @@ -0,0 +1,20 @@ +using MediaBrowser.Model.Notifications; + +namespace Jellyfin.Api.Models.NotificationDtos +{ + /// + /// The notification summary DTO. + /// + public class NotificationsSummaryDto + { + /// + /// Gets or sets the number of unread notifications. + /// + public int UnreadCount { get; set; } + + /// + /// Gets or sets the maximum unread notification level. + /// + public NotificationLevel MaxUnreadNotificationLevel { get; set; } + } +} diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index dd4f9cd23..b3164e068 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -71,6 +71,7 @@ namespace Jellyfin.Server.Extensions // Clear app parts to avoid other assemblies being picked up .ConfigureApplicationPartManager(a => a.ApplicationParts.Clear()) .AddApplicationPart(typeof(StartupController).Assembly) + .AddApplicationPart(typeof(NotificationsController).Assembly) .AddControllersAsServices(); }