diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/NotificationsController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/NotificationsController.cs new file mode 100644 index 0000000000..e5917d0a07 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/NotificationsController.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.Factories; +using Umbraco.Cms.Api.Management.ViewModels.Document; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Controllers.Document; + +public class NotificationsController : DocumentControllerBase +{ + private readonly IContentEditingService _contentEditingService; + private readonly IDocumentNotificationPresentationFactory _documentNotificationPresentationFactory; + + public NotificationsController(IContentEditingService contentEditingService, IDocumentNotificationPresentationFactory documentNotificationPresentationFactory) + { + _contentEditingService = contentEditingService; + _documentNotificationPresentationFactory = documentNotificationPresentationFactory; + } + + [HttpGet("{key:guid}/notifications")] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task Notifications(Guid key) + { + IContent? content = await _contentEditingService.GetAsync(key); + return content != null + ? Ok(await _documentNotificationPresentationFactory.CreateNotificationModelsAsync(content)) + : DocumentNotFound(); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/UpdateNotificationsController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/UpdateNotificationsController.cs new file mode 100644 index 0000000000..1fc558e369 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/UpdateNotificationsController.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.ViewModels.Document; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Security; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Controllers.Document; + +public class UpdateNotificationsController : DocumentControllerBase +{ + private readonly IContentEditingService _contentEditingService; + private readonly INotificationService _notificationService; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; + + public UpdateNotificationsController(IContentEditingService contentEditingService, INotificationService notificationService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor) + { + _contentEditingService = contentEditingService; + _notificationService = notificationService; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; + } + + [HttpPut("{key:guid}/notifications")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task UpdateNotifications(Guid key, UpdateDocumentNotificationsRequestModel updateModel) + { + IContent? content = await _contentEditingService.GetAsync(key); + if (content == null) + { + return DocumentNotFound(); + } + + _notificationService.SetNotifications(_backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, content, updateModel.SubscribedActionIds); + return await Task.FromResult(Ok()); + } +} diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/DocumentBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/DocumentBuilderExtensions.cs index 604626cfc9..9b16d23022 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/DocumentBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/DocumentBuilderExtensions.cs @@ -11,6 +11,7 @@ internal static class DocumentBuilderExtensions internal static IUmbracoBuilder AddDocuments(this IUmbracoBuilder builder) { builder.Services.AddTransient(); + builder.Services.AddTransient(); builder.Services.AddTransient(); builder.Services.AddTransient(); diff --git a/src/Umbraco.Cms.Api.Management/Factories/DocumentNotificationPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/DocumentNotificationPresentationFactory.cs new file mode 100644 index 0000000000..549163df91 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Factories/DocumentNotificationPresentationFactory.cs @@ -0,0 +1,39 @@ +using Umbraco.Cms.Api.Management.ViewModels.Document; +using Umbraco.Cms.Core.Actions; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Security; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Api.Management.Factories; + +internal sealed class DocumentNotificationPresentationFactory : IDocumentNotificationPresentationFactory +{ + private readonly ActionCollection _actionCollection; + private readonly INotificationService _notificationService; + private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; + + public DocumentNotificationPresentationFactory(ActionCollection actionCollection, INotificationService notificationService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor) + { + _actionCollection = actionCollection; + _notificationService = notificationService; + _backOfficeSecurityAccessor = backOfficeSecurityAccessor; + } + + public async Task> CreateNotificationModelsAsync(IContent content) + { + var subscribedActionIds = _notificationService + .GetUserNotifications(_backOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, content.Path)? + .Select(n => n.Action) + .ToArray() + ?? Array.Empty(); + + var availableActionIds = _actionCollection.Where(a => a.ShowInNotifier).Select(a => a.Letter.ToString()).ToArray(); + + return await Task.FromResult( + availableActionIds.Select(actionId => new DocumentNotificationResponseModel + { + ActionId = actionId, + Subscribed = subscribedActionIds.Contains(actionId) + }).ToArray()); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Factories/IDocumentNotificationPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/IDocumentNotificationPresentationFactory.cs new file mode 100644 index 0000000000..ee0325eff5 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Factories/IDocumentNotificationPresentationFactory.cs @@ -0,0 +1,9 @@ +using Umbraco.Cms.Api.Management.ViewModels.Document; +using Umbraco.Cms.Core.Models; + +namespace Umbraco.Cms.Api.Management.Factories; + +public interface IDocumentNotificationPresentationFactory +{ + Task> CreateNotificationModelsAsync(IContent content); +} diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index 310a5654fd..e3d66d1a94 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -1767,6 +1767,85 @@ } } }, + "/umbraco/management/api/v1/document/{key}/notifications": { + "get": { + "tags": [ + "Document" + ], + "operationId": "GetDocumentByKeyNotifications", + "parameters": [ + { + "name": "key", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentNotificationResponseModel" + } + ] + } + } + } + } + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "tags": [ + "Document" + ], + "operationId": "PutDocumentByKeyNotifications", + "parameters": [ + { + "name": "key", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/UpdateDocumentNotificationsRequestModel" + } + ] + } + } + } + }, + "responses": { + "200": { + "description": "Success" + }, + "404": { + "description": "Not Found" + } + } + } + }, "/umbraco/management/api/v1/recycle-bin/document/children": { "get": { "tags": [ @@ -7745,6 +7824,18 @@ } } }, + "DocumentNotificationResponseModel": { + "type": "object", + "properties": { + "actionId": { + "type": "string" + }, + "subscribed": { + "type": "boolean" + } + }, + "additionalProperties": false + }, "DocumentResponseModel": { "type": "object", "allOf": [ @@ -10511,6 +10602,18 @@ ], "additionalProperties": false }, + "UpdateDocumentNotificationsRequestModel": { + "type": "object", + "properties": { + "subscribedActionIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, "UpdateDocumentRequestModel": { "type": "object", "allOf": [ diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Document/DocumentNotificationsResponseModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Document/DocumentNotificationsResponseModel.cs new file mode 100644 index 0000000000..b3ae3b8f6e --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Document/DocumentNotificationsResponseModel.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.Document; + +public class DocumentNotificationResponseModel +{ + public required string ActionId { get; set; } + + public required bool Subscribed { get; set; } +} diff --git a/src/Umbraco.Cms.Api.Management/ViewModels/Document/UpdateDocumentNotificationsRequestModel.cs b/src/Umbraco.Cms.Api.Management/ViewModels/Document/UpdateDocumentNotificationsRequestModel.cs new file mode 100644 index 0000000000..35b9938fc3 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/ViewModels/Document/UpdateDocumentNotificationsRequestModel.cs @@ -0,0 +1,6 @@ +namespace Umbraco.Cms.Api.Management.ViewModels.Document; + +public class UpdateDocumentNotificationsRequestModel +{ + public required string[] SubscribedActionIds { get; set; } +}