Move audit log endpoints to their respective silos and clean up (#16170)
* Move audit log endpoints to their respective silos and clean up * Fix failing integration tests --------- Co-authored-by: Mads Rasmussen <madsr@hey.com>
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.AuditLog;
|
||||
|
||||
[VersionedApiBackOfficeRoute("audit-log")]
|
||||
[ApiExplorerSettings(GroupName = "Audit Log")]
|
||||
public class AuditLogControllerBase : ManagementApiControllerBase
|
||||
{
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.AuditLogs;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.AuditLog;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessContentOrMedia)]
|
||||
public class ByKeyAuditLogController : AuditLogControllerBase
|
||||
{
|
||||
private readonly IAuditService _auditService;
|
||||
private readonly IAuditLogPresentationFactory _auditLogPresentationFactory;
|
||||
|
||||
public ByKeyAuditLogController(IAuditService auditService, IAuditLogPresentationFactory auditLogPresentationFactory)
|
||||
{
|
||||
_auditService = auditService;
|
||||
_auditLogPresentationFactory = auditLogPresentationFactory;
|
||||
}
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<AuditLogResponseModel>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> ByKey(CancellationToken cancellationToken, Guid id, Direction orderDirection = Direction.Descending, DateTime? sinceDate = null, int skip = 0, int take = 100)
|
||||
{
|
||||
PagedModel<IAuditItem> result = await _auditService.GetItemsByKeyAsync(id, skip, take, orderDirection, sinceDate);
|
||||
IEnumerable<AuditLogResponseModel> mapped = _auditLogPresentationFactory.CreateAuditLogViewModel(result.Items);
|
||||
var viewModel = new PagedViewModel<AuditLogResponseModel>
|
||||
{
|
||||
Total = result.Total,
|
||||
Items = mapped,
|
||||
};
|
||||
|
||||
return Ok(viewModel);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.AuditLogs;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.AuditLog;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class ByTypeAuditLogController : AuditLogControllerBase
|
||||
{
|
||||
private readonly IAuditService _auditService;
|
||||
private readonly IAuditLogPresentationFactory _auditLogPresentationFactory;
|
||||
|
||||
public ByTypeAuditLogController(IAuditService auditService, IAuditLogPresentationFactory auditLogPresentationFactory)
|
||||
{
|
||||
_auditService = auditService;
|
||||
_auditLogPresentationFactory = auditLogPresentationFactory;
|
||||
}
|
||||
|
||||
[HttpGet("type/{logType}")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<AuditLogResponseModel>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> ByType(CancellationToken cancellationToken, AuditType logType, DateTime? sinceDate = null, int skip = 0, int take = 100)
|
||||
{
|
||||
IAuditItem[] result = _auditService.GetLogs(logType, sinceDate).ToArray();
|
||||
IEnumerable<AuditLogResponseModel> mapped = _auditLogPresentationFactory.CreateAuditLogViewModel(result.Skip(skip).Take(take));
|
||||
var viewModel = new PagedViewModel<AuditLogResponseModel>
|
||||
{
|
||||
Total = result.Length,
|
||||
Items = mapped,
|
||||
};
|
||||
|
||||
return await Task.FromResult(Ok(viewModel));
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.AuditLogs;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.AuditLog;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class CurrentUserAuditLogController : AuditLogControllerBase
|
||||
{
|
||||
private readonly IAuditService _auditService;
|
||||
private readonly IAuditLogPresentationFactory _auditLogPresentationFactory;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
|
||||
public CurrentUserAuditLogController(
|
||||
IAuditService auditService,
|
||||
IAuditLogPresentationFactory auditLogPresentationFactory,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
{
|
||||
_auditService = auditService;
|
||||
_auditLogPresentationFactory = auditLogPresentationFactory;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<AuditLogWithUsernameResponseModel>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> CurrentUser(CancellationToken cancellationToken, Direction orderDirection = Direction.Descending, DateTime? sinceDate = null, int skip = 0, int take = 100)
|
||||
{
|
||||
IUser user = CurrentUser(_backOfficeSecurityAccessor);
|
||||
PagedModel<IAuditItem> result = await _auditService.GetPagedItemsByUserAsync(
|
||||
user.Key,
|
||||
skip,
|
||||
take,
|
||||
orderDirection,
|
||||
null,
|
||||
sinceDate);
|
||||
|
||||
IEnumerable<AuditLogWithUsernameResponseModel> mapped = _auditLogPresentationFactory.CreateAuditLogWithUsernameViewModels(result.Items);
|
||||
var viewModel = new PagedViewModel<AuditLogWithUsernameResponseModel>
|
||||
{
|
||||
Total = result.Total,
|
||||
Items = mapped,
|
||||
};
|
||||
|
||||
return Ok(viewModel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.AuditLog;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Actions;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Security.Authorization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Document;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class GetAuditLogDocumentController : DocumentControllerBase
|
||||
{
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IAuditService _auditService;
|
||||
private readonly IAuditLogPresentationFactory _auditLogPresentationFactory;
|
||||
|
||||
public GetAuditLogDocumentController(
|
||||
IAuthorizationService authorizationService,
|
||||
IAuditService auditService,
|
||||
IAuditLogPresentationFactory auditLogPresentationFactory)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_auditService = auditService;
|
||||
_auditLogPresentationFactory = auditLogPresentationFactory;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[HttpGet("{id:guid}/audit-log")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<AuditLogResponseModel>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetAuditLog(CancellationToken cancellationToken, Guid id, Direction orderDirection = Direction.Descending, DateTime? sinceDate = null, int skip = 0, int take = 100)
|
||||
{
|
||||
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
|
||||
User,
|
||||
ContentPermissionResource.WithKeys(ActionProtect.ActionLetter, id),
|
||||
AuthorizationPolicies.ContentPermissionByResource);
|
||||
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbidden();
|
||||
}
|
||||
|
||||
PagedModel<IAuditItem> result = await _auditService.GetItemsByKeyAsync(id, UmbracoObjectTypes.Document, skip, take, orderDirection, sinceDate);
|
||||
IEnumerable<AuditLogResponseModel> mapped = _auditLogPresentationFactory.CreateAuditLogViewModel(result.Items);
|
||||
var viewModel = new PagedViewModel<AuditLogResponseModel>
|
||||
{
|
||||
Total = result.Total,
|
||||
Items = mapped,
|
||||
};
|
||||
|
||||
return Ok(viewModel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Common.ViewModels.Pagination;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.AuditLog;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Security.Authorization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.Common.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Media;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class GetAuditLogMediaController : MediaControllerBase
|
||||
{
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly IAuditService _auditService;
|
||||
private readonly IAuditLogPresentationFactory _auditLogPresentationFactory;
|
||||
|
||||
public GetAuditLogMediaController(
|
||||
IAuthorizationService authorizationService,
|
||||
IAuditService auditService,
|
||||
IAuditLogPresentationFactory auditLogPresentationFactory)
|
||||
{
|
||||
_authorizationService = authorizationService;
|
||||
_auditService = auditService;
|
||||
_auditLogPresentationFactory = auditLogPresentationFactory;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[HttpGet("{id:guid}/audit-log")]
|
||||
[ProducesResponseType(typeof(PagedViewModel<AuditLogResponseModel>), StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetAuditLog(CancellationToken cancellationToken, Guid id, Direction orderDirection = Direction.Descending, DateTime? sinceDate = null, int skip = 0, int take = 100)
|
||||
{
|
||||
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
|
||||
User,
|
||||
MediaPermissionResource.WithKeys(id),
|
||||
AuthorizationPolicies.MediaPermissionByResource);
|
||||
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbidden();
|
||||
}
|
||||
|
||||
PagedModel<IAuditItem> result = await _auditService.GetItemsByKeyAsync(id, UmbracoObjectTypes.Media, skip, take, orderDirection, sinceDate);
|
||||
IEnumerable<AuditLogResponseModel> mapped = _auditLogPresentationFactory.CreateAuditLogViewModel(result.Items);
|
||||
var viewModel = new PagedViewModel<AuditLogResponseModel>
|
||||
{
|
||||
Total = result.Total,
|
||||
Items = mapped,
|
||||
};
|
||||
|
||||
return Ok(viewModel);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.AuditLogs;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Media;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.AuditLog;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -13,57 +9,25 @@ namespace Umbraco.Cms.Api.Management.Factories;
|
||||
public class AuditLogPresentationFactory : IAuditLogPresentationFactory
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
private readonly AppCaches _appCaches;
|
||||
private readonly MediaFileManager _mediaFileManager;
|
||||
private readonly IImageUrlGenerator _imageUrlGenerator;
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IUserIdKeyResolver _userIdKeyResolver;
|
||||
|
||||
public AuditLogPresentationFactory(IUserService userService, AppCaches appCaches, MediaFileManager mediaFileManager, IImageUrlGenerator imageUrlGenerator, IEntityService entityService, IUserIdKeyResolver userIdKeyResolver)
|
||||
public AuditLogPresentationFactory(IUserService userService, IUserIdKeyResolver userIdKeyResolver)
|
||||
{
|
||||
_userService = userService;
|
||||
_appCaches = appCaches;
|
||||
_mediaFileManager = mediaFileManager;
|
||||
_imageUrlGenerator = imageUrlGenerator;
|
||||
_entityService = entityService;
|
||||
_userIdKeyResolver = userIdKeyResolver;
|
||||
}
|
||||
|
||||
public IEnumerable<AuditLogResponseModel> CreateAuditLogViewModel(IEnumerable<IAuditItem> auditItems) => auditItems.Select(CreateAuditLogViewModel);
|
||||
|
||||
public IEnumerable<AuditLogWithUsernameResponseModel> CreateAuditLogWithUsernameViewModels(IEnumerable<IAuditItem> auditItems) => auditItems.Select(CreateAuditLogWithUsernameViewModel);
|
||||
|
||||
private AuditLogWithUsernameResponseModel CreateAuditLogWithUsernameViewModel(IAuditItem auditItem)
|
||||
{
|
||||
AuditLogWithUsernameResponseModel target = CreateResponseModel<AuditLogWithUsernameResponseModel>(auditItem, out IUser user);
|
||||
|
||||
target.UserAvatars = user.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator);
|
||||
target.UserName = user.Name;
|
||||
return target;
|
||||
}
|
||||
|
||||
private AuditLogResponseModel CreateAuditLogViewModel(IAuditItem auditItem)
|
||||
=> CreateResponseModel<AuditLogResponseModel>(auditItem, out _);
|
||||
|
||||
private T CreateResponseModel<T>(IAuditItem auditItem, out IUser user)
|
||||
where T : AuditLogBaseModel, new()
|
||||
{
|
||||
Guid userKey = _userIdKeyResolver.GetAsync(auditItem.UserId).GetAwaiter().GetResult();
|
||||
user = _userService.GetAsync(userKey).GetAwaiter().GetResult()
|
||||
?? throw new ArgumentException($"Could not find user with id {auditItem.UserId}");
|
||||
IUser user = _userService.GetAsync(userKey).GetAwaiter().GetResult()
|
||||
?? throw new ArgumentException($"Could not find user with id {auditItem.UserId}");
|
||||
|
||||
IEntitySlim? entitySlim = _entityService.Get(auditItem.Id);
|
||||
|
||||
return new T
|
||||
return new AuditLogResponseModel
|
||||
{
|
||||
Comment = auditItem.Comment,
|
||||
Entity = auditItem.EntityType is not null || entitySlim is not null
|
||||
? new AuditLogEntity
|
||||
{
|
||||
Id = entitySlim?.Key,
|
||||
Type = auditItem.EntityType
|
||||
}
|
||||
: null,
|
||||
LogType = auditItem.AuditType,
|
||||
Parameters = auditItem.Parameters,
|
||||
Timestamp = auditItem.CreateDate,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.AuditLogs;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.AuditLog;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
@@ -6,6 +6,4 @@ namespace Umbraco.Cms.Api.Management.Factories;
|
||||
public interface IAuditLogPresentationFactory
|
||||
{
|
||||
IEnumerable<AuditLogResponseModel> CreateAuditLogViewModel(IEnumerable<IAuditItem> auditItems);
|
||||
|
||||
IEnumerable<AuditLogWithUsernameResponseModel> CreateAuditLogWithUsernameViewModels(IEnumerable<IAuditItem> auditItems);
|
||||
}
|
||||
|
||||
@@ -6,220 +6,6 @@
|
||||
"version": "Latest"
|
||||
},
|
||||
"paths": {
|
||||
"/umbraco/management/api/v1/audit-log": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Audit Log"
|
||||
],
|
||||
"operationId": "GetAuditLog",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "orderDirection",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/DirectionModel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sinceDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PagedAuditLogWithUsernameResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Backoffice User": [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/audit-log/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Audit Log"
|
||||
],
|
||||
"operationId": "GetAuditLogById",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "orderDirection",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/DirectionModel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sinceDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PagedAuditLogResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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/audit-log/type/{logType}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Audit Log"
|
||||
],
|
||||
"operationId": "GetAuditLogTypeByLogType",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "logType",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/AuditTypeModel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sinceDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PagedAuditLogResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Backoffice User": [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/culture": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -7340,6 +7126,85 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/document/{id}/audit-log": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Document"
|
||||
],
|
||||
"operationId": "GetDocumentByIdAuditLog",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "orderDirection",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/DirectionModel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sinceDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PagedAuditLogResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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/document/{id}/copy": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@@ -15276,6 +15141,85 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/media/{id}/audit-log": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Media"
|
||||
],
|
||||
"operationId": "GetMediaByIdAuditLog",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "orderDirection",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/DirectionModel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sinceDate",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "skip",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "take",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/PagedAuditLogResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"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/media/{id}/move": {
|
||||
"put": {
|
||||
"tags": [
|
||||
@@ -32466,21 +32410,6 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"AuditLogEntityModel": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"nullable": true
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"AuditLogResponseModel": {
|
||||
"required": [
|
||||
"logType",
|
||||
@@ -32496,14 +32425,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"entity": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AuditLogEntityModel"
|
||||
}
|
||||
],
|
||||
"nullable": true
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
@@ -32522,58 +32443,6 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"AuditLogWithUsernameResponseModel": {
|
||||
"required": [
|
||||
"logType",
|
||||
"timestamp",
|
||||
"user",
|
||||
"userAvatars"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"user": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ReferenceByIdModel"
|
||||
}
|
||||
]
|
||||
},
|
||||
"entity": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AuditLogEntityModel"
|
||||
}
|
||||
],
|
||||
"nullable": true
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"logType": {
|
||||
"$ref": "#/components/schemas/AuditTypeModel"
|
||||
},
|
||||
"comment": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"parameters": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"userName": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"userAvatars": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"AuditTypeModel": {
|
||||
"enum": [
|
||||
"New",
|
||||
@@ -39067,30 +38936,6 @@
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedAuditLogWithUsernameResponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
"total"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/AuditLogWithUsernameResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"PagedCultureReponseModel": {
|
||||
"required": [
|
||||
"items",
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.AuditLogs;
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.AuditLog;
|
||||
|
||||
public class AuditLogBaseModel
|
||||
public class AuditLogResponseModel
|
||||
{
|
||||
public ReferenceByIdModel User { get; set; } = new();
|
||||
|
||||
public AuditLogEntity? Entity { get; set; }
|
||||
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
|
||||
public AuditType LogType { get; set; }
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.AuditLogs;
|
||||
|
||||
public class AuditLogEntity
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
public string? Type { get; set; }
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.AuditLogs;
|
||||
|
||||
/// <inheritdoc />
|
||||
public class AuditLogResponseModel : AuditLogBaseModel
|
||||
{
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.AuditLogs;
|
||||
|
||||
public class AuditLogWithUsernameResponseModel : AuditLogBaseModel
|
||||
{
|
||||
public string? UserName { get; set; }
|
||||
|
||||
public string[] UserAvatars { get; set; } = Array.Empty<string>();
|
||||
}
|
||||
@@ -2,16 +2,11 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Exceptions;
|
||||
using Umbraco.Cms.Core.Extensions;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Persistence.Querying;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Implement;
|
||||
|
||||
@@ -19,10 +14,11 @@ public sealed class AuditService : RepositoryService, IAuditService
|
||||
{
|
||||
private readonly IAuditEntryRepository _auditEntryRepository;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IEntityRepository _entityRepository;
|
||||
private readonly IAuditRepository _auditRepository;
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly Lazy<bool> _isAvailable;
|
||||
|
||||
[Obsolete("Use the non-obsolete constructor. Will be removed in V15.")]
|
||||
public AuditService(
|
||||
ICoreScopeProvider provider,
|
||||
ILoggerFactory loggerFactory,
|
||||
@@ -31,12 +27,54 @@ public sealed class AuditService : RepositoryService, IAuditService
|
||||
IAuditEntryRepository auditEntryRepository,
|
||||
IUserService userService,
|
||||
IEntityRepository entityRepository)
|
||||
: this(
|
||||
provider,
|
||||
loggerFactory,
|
||||
eventMessagesFactory,
|
||||
auditRepository,
|
||||
auditEntryRepository,
|
||||
userService,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IEntityService>()
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use the non-obsolete constructor. Will be removed in V15.")]
|
||||
public AuditService(
|
||||
ICoreScopeProvider provider,
|
||||
ILoggerFactory loggerFactory,
|
||||
IEventMessagesFactory eventMessagesFactory,
|
||||
IAuditRepository auditRepository,
|
||||
IAuditEntryRepository auditEntryRepository,
|
||||
IUserService userService,
|
||||
IEntityRepository entityRepository,
|
||||
IEntityService entityService)
|
||||
: this(
|
||||
provider,
|
||||
loggerFactory,
|
||||
eventMessagesFactory,
|
||||
auditRepository,
|
||||
auditEntryRepository,
|
||||
userService,
|
||||
entityService
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
public AuditService(
|
||||
ICoreScopeProvider provider,
|
||||
ILoggerFactory loggerFactory,
|
||||
IEventMessagesFactory eventMessagesFactory,
|
||||
IAuditRepository auditRepository,
|
||||
IAuditEntryRepository auditEntryRepository,
|
||||
IUserService userService,
|
||||
IEntityService entityService)
|
||||
: base(provider, loggerFactory, eventMessagesFactory)
|
||||
{
|
||||
_auditRepository = auditRepository;
|
||||
_auditEntryRepository = auditEntryRepository;
|
||||
_userService = userService;
|
||||
_entityRepository = entityRepository;
|
||||
_entityService = entityService;
|
||||
_isAvailable = new Lazy<bool>(DetermineIsAvailable);
|
||||
}
|
||||
|
||||
@@ -200,6 +238,7 @@ public sealed class AuditService : RepositoryService, IAuditService
|
||||
|
||||
public async Task<PagedModel<IAuditItem>> GetItemsByKeyAsync(
|
||||
Guid entityKey,
|
||||
UmbracoObjectTypes entityType,
|
||||
int skip,
|
||||
int take,
|
||||
Direction orderDirection = Direction.Descending,
|
||||
@@ -216,16 +255,20 @@ public sealed class AuditService : RepositoryService, IAuditService
|
||||
throw new ArgumentOutOfRangeException(nameof(take));
|
||||
}
|
||||
|
||||
Attempt<int> keyToIdAttempt = _entityService.GetId(entityKey, entityType);
|
||||
if (keyToIdAttempt.Success is false)
|
||||
{
|
||||
return await Task.FromResult(new PagedModel<IAuditItem> { Items = Enumerable.Empty<IAuditItem>(), Total = 0 });
|
||||
}
|
||||
|
||||
using (ScopeProvider.CreateCoreScope(autoComplete: true))
|
||||
{
|
||||
IUser user = await _userService.GetRequiredUserAsync(entityKey);
|
||||
|
||||
IQuery<IAuditItem> query = Query<IAuditItem>().Where(x => x.UserId == user.Id);
|
||||
IQuery<IAuditItem> query = Query<IAuditItem>().Where(x => x.Id == keyToIdAttempt.Result);
|
||||
IQuery<IAuditItem>? customFilter = sinceDate.HasValue ? Query<IAuditItem>().Where(x => x.CreateDate >= sinceDate) : null;
|
||||
PaginationHelper.ConvertSkipTakeToPaging(skip, take, out var pageNumber, out var pageSize);
|
||||
|
||||
IEnumerable<IAuditItem> auditItems = _auditRepository.GetPagedResultsByQuery(query, pageNumber, pageSize, out var totalRecords, orderDirection, auditTypeFilter, customFilter);
|
||||
return await Task.FromResult(new PagedModel<IAuditItem> { Items = auditItems, Total = totalRecords });
|
||||
return new PagedModel<IAuditItem> { Items = auditItems, Total = totalRecords };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Persistence.Querying;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
@@ -76,12 +75,12 @@ public interface IAuditService : IService
|
||||
IQuery<IAuditItem>? customFilter = null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns paged items in the audit trail for a given user
|
||||
/// Returns paged items in the audit trail for a given entity
|
||||
/// </summary>
|
||||
/// <param name="entityKey">The key of the user</param>
|
||||
/// <param name="skip">The amount of entries to skip</param>
|
||||
/// <param name="take">The amount of entiries to take</param>
|
||||
/// <param name="totalRecords">The total amount of entires</param>
|
||||
/// <param name="entityKey">The key of the entity</param>
|
||||
/// <param name="entityType">The entity type</param>
|
||||
/// <param name="skip">The amount of audit trail entries to skip</param>
|
||||
/// <param name="take">The amount of audit trail entries to take</param>
|
||||
/// <param name="orderDirection">
|
||||
/// By default this will always be ordered descending (newest first)
|
||||
/// </param>
|
||||
@@ -96,6 +95,7 @@ public interface IAuditService : IService
|
||||
/// <returns></returns>
|
||||
Task<PagedModel<IAuditItem>> GetItemsByKeyAsync(
|
||||
Guid entityKey,
|
||||
UmbracoObjectTypes entityType,
|
||||
int skip,
|
||||
int take,
|
||||
Direction orderDirection = Direction.Descending,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Controllers.AuditLog;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Api.Management.Controllers.Culture;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Policies;
|
||||
|
||||
@@ -11,10 +9,10 @@ namespace Umbraco.Cms.Tests.Integration.ManagementApi.Policies;
|
||||
///
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ByKeyAuditLogControllerTests : ManagementApiTest<ByKeyAuditLogController>
|
||||
public class AllCultureControllerTests : ManagementApiTest<AllCultureController>
|
||||
{
|
||||
protected override Expression<Func<ByKeyAuditLogController, object>> MethodSelector =>
|
||||
x => x.ByKey(CancellationToken.None, Constants.Security.SuperUserKey, Direction.Ascending, null, 0, 100);
|
||||
protected override Expression<Func<AllCultureController, object>> MethodSelector =>
|
||||
x => x.GetAll(CancellationToken.None, 0, 100);
|
||||
|
||||
[Test]
|
||||
public virtual async Task As_Admin_I_Have_Access()
|
||||
Reference in New Issue
Block a user