Add endpoint for calculating effective user start nodes (#16609)

* Add endpoint for calculating effective user start nodes

* Fix OpenAPI
This commit is contained in:
Kenn Jacobsen
2024-06-25 10:34:16 +02:00
committed by GitHub
parent 215fc4378e
commit 76bb2b0847
5 changed files with 197 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
using Asp.Versioning;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Api.Management.Factories;
using Umbraco.Cms.Api.Management.ViewModels.User;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Security.Authorization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Web.Common.Authorization;
using Umbraco.Extensions;
namespace Umbraco.Cms.Api.Management.Controllers.User;
[ApiVersion("1.0")]
public class CalculatedStartNodesUserController : UserControllerBase
{
private readonly IAuthorizationService _authorizationService;
private readonly IUserService _userService;
private readonly IUserPresentationFactory _userPresentationFactory;
public CalculatedStartNodesUserController(
IAuthorizationService authorizationService,
IUserService userService,
IUserPresentationFactory userPresentationFactory)
{
_authorizationService = authorizationService;
_userService = userService;
_userPresentationFactory = userPresentationFactory;
}
[HttpGet("{id:guid}/calculate-start-nodes")]
[MapToApiVersion("1.0")]
[ProducesResponseType(typeof(CalculatedUserStartNodesResponseModel), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
public async Task<IActionResult> CalculatedStartNodes(CancellationToken cancellationToken, Guid id)
{
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
User,
UserPermissionResource.WithKeys(id),
AuthorizationPolicies.UserPermissionByResource);
if (!authorizationResult.Succeeded)
{
return Forbidden();
}
IUser? user = await _userService.GetAsync(id);
if (user is null)
{
return UserOperationStatusResult(UserOperationStatus.UserNotFound);
}
CalculatedUserStartNodesResponseModel responseModel = await _userPresentationFactory.CreateCalculatedUserStartNodesResponseModelAsync(user);
return Ok(responseModel);
}
}

View File

@@ -25,4 +25,6 @@ public interface IUserPresentationFactory
Task<CurrenUserConfigurationResponseModel> CreateCurrentUserConfigurationModelAsync();
UserItemResponseModel CreateItemResponseModel(IUser user);
Task<CalculatedUserStartNodesResponseModel> CreateCalculatedUserStartNodesResponseModelAsync(IUser user);
}

View File

@@ -212,6 +212,23 @@ public class UserPresentationFactory : IUserPresentationFactory
});
}
public async Task<CalculatedUserStartNodesResponseModel> CreateCalculatedUserStartNodesResponseModelAsync(IUser user)
{
var mediaStartNodeIds = user.CalculateMediaStartNodeIds(_entityService, _appCaches);
ISet<ReferenceByIdModel> mediaStartNodeKeys = GetKeysFromIds(mediaStartNodeIds, UmbracoObjectTypes.Media);
var contentStartNodeIds = user.CalculateContentStartNodeIds(_entityService, _appCaches);
ISet<ReferenceByIdModel> documentStartNodeKeys = GetKeysFromIds(contentStartNodeIds, UmbracoObjectTypes.Document);
return await Task.FromResult(new CalculatedUserStartNodesResponseModel()
{
Id = user.Key,
MediaStartNodeIds = mediaStartNodeKeys,
HasMediaRootAccess = HasRootAccess(mediaStartNodeIds),
DocumentStartNodeIds = documentStartNodeKeys,
HasDocumentRootAccess = HasRootAccess(contentStartNodeIds),
});
}
private ISet<ReferenceByIdModel> GetKeysFromIds(IEnumerable<int>? ids, UmbracoObjectTypes type)
{
IEnumerable<ReferenceByIdModel>? models = ids?

View File

@@ -30298,6 +30298,66 @@
]
}
},
"/umbraco/management/api/v1/user/{id}/calculate-start-nodes": {
"get": {
"tags": [
"User"
],
"operationId": "GetUserByIdCalculateStartNodes",
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "uuid"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/CalculatedUserStartNodesResponseModel"
}
]
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"oneOf": [
{
"$ref": "#/components/schemas/ProblemDetails"
}
]
}
}
}
},
"401": {
"description": "The resource is protected and requires an authentication token"
},
"403": {
"description": "The authenticated user do not have access to this resource"
}
},
"security": [
{
"Backoffice User": [ ]
}
]
}
},
"/umbraco/management/api/v1/user/{id}/change-password": {
"post": {
"tags": [
@@ -33447,6 +33507,51 @@
},
"additionalProperties": false
},
"CalculatedUserStartNodesResponseModel": {
"required": [
"documentStartNodeIds",
"hasDocumentRootAccess",
"hasMediaRootAccess",
"id",
"mediaStartNodeIds"
],
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"documentStartNodeIds": {
"uniqueItems": true,
"type": "array",
"items": {
"oneOf": [
{
"$ref": "#/components/schemas/ReferenceByIdModel"
}
]
}
},
"hasDocumentRootAccess": {
"type": "boolean"
},
"mediaStartNodeIds": {
"uniqueItems": true,
"type": "array",
"items": {
"oneOf": [
{
"$ref": "#/components/schemas/ReferenceByIdModel"
}
]
}
},
"hasMediaRootAccess": {
"type": "boolean"
}
},
"additionalProperties": false
},
"ChangePasswordCurrentUserRequestModel": {
"required": [
"newPassword"

View File

@@ -0,0 +1,14 @@
namespace Umbraco.Cms.Api.Management.ViewModels.User;
public class CalculatedUserStartNodesResponseModel
{
public required Guid Id { get; init; }
public ISet<ReferenceByIdModel> DocumentStartNodeIds { get; set; } = new HashSet<ReferenceByIdModel>();
public bool HasDocumentRootAccess { get; set; }
public ISet<ReferenceByIdModel> MediaStartNodeIds { get; set; } = new HashSet<ReferenceByIdModel>();
public bool HasMediaRootAccess { get; set; }
}