From c1ac80653b4ea0c751515c8ee768957e6ce351e0 Mon Sep 17 00:00:00 2001 From: Laura Neto <12862535+lauraneto@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:52:17 +0200 Subject: [PATCH] Use audit service instead of repository directly in services (#19357) * Introduce new AuditEntryService - Moved logic related to the IAuditEntryRepository from the AuditService to the new service - Introduced new Async methods - Using ids (for easier transition from the previous Write method) - Using keys - Moved and updated integration tests related to the audit entries to a new test class `AuditEntryServiceTests` - Added unit tests class `AuditEntryServiceTests` and added a few unit tests - Added migration to add columns for `performingUserKey` and `affectedUserKey` and convert existing user ids - Adjusted usages of the old AuditService.Write method to use the new one (mostly notification handlers) * Audit service rework - Added new async and paged methods - Marked (now) redundant methods as obsolete - Updated all of the usages to use the non-obsolete methods - Added unit tests class `AuditServiceTests` and some unit tests - Updated existing integration test * Use the audit service instead of the repository directly in services * Apply suggestions from code review * Small improvement * Update src/Umbraco.Core/Services/AuditService.cs * Some minor adjustments following the merge * Delete unnecessary file * Small cleanup on the tests * Remove changing user id to 0 (on audit) if user id is admin in media bulk save * Remove reference to unused IUserIdKeyResolver in TemplateService * Remove references to unused IShortStringHelper and GlobalSettings in FileService --- src/Umbraco.Core/Services/AuditService.cs | 40 ++---- .../ContentBlueprintContainerService.cs | 4 +- src/Umbraco.Core/Services/ContentService.cs | 49 +++++--- .../Services/ContentTypeContainerService.cs | 4 +- .../Services/ContentTypeService.cs | 63 +++++++++- ...peServiceBaseOfTRepositoryTItemTService.cs | 47 +++++++- .../Services/ContentVersionService.cs | 21 ++-- .../Services/DataTypeContainerService.cs | 4 +- src/Umbraco.Core/Services/DataTypeService.cs | 114 ++++++++++++------ .../Services/DictionaryItemService.cs | 24 ++-- .../Services/EntityTypeContainerService.cs | 20 +-- src/Umbraco.Core/Services/FileService.cs | 94 +++++++++++++-- .../Services/FileServiceOperationBase.cs | 42 +++++-- src/Umbraco.Core/Services/LanguageService.cs | 21 ++-- .../Services/LocalizationService.cs | 5 - src/Umbraco.Core/Services/MediaService.cs | 78 +++++++++++- .../Services/MediaTypeContainerService.cs | 4 +- src/Umbraco.Core/Services/MediaTypeService.cs | 67 +++++++++- src/Umbraco.Core/Services/MemberService.cs | 81 ++++++++++++- .../Services/MemberTypeService.cs | 63 +++++++++- .../Services/PartialViewService.cs | 51 +++++++- src/Umbraco.Core/Services/RelationService.cs | 77 ++++++++++-- src/Umbraco.Core/Services/ScriptService.cs | 47 +++++++- .../Services/StylesheetService.cs | 47 +++++++- src/Umbraco.Core/Services/TemplateService.cs | 74 +++++++++--- .../Services/AuditServiceTests.cs | 14 +-- 26 files changed, 942 insertions(+), 213 deletions(-) diff --git a/src/Umbraco.Core/Services/AuditService.cs b/src/Umbraco.Core/Services/AuditService.cs index 342e62a004..33893dfd5d 100644 --- a/src/Umbraco.Core/Services/AuditService.cs +++ b/src/Umbraco.Core/Services/AuditService.cs @@ -16,9 +16,9 @@ namespace Umbraco.Cms.Core.Services.Implement; /// public sealed class AuditService : RepositoryService, IAuditService { + private readonly IUserIdKeyResolver _userIdKeyResolver; private readonly IAuditRepository _auditRepository; private readonly IEntityService _entityService; - private readonly IUserService _userService; /// /// Initializes a new instance of the class. @@ -28,37 +28,15 @@ public sealed class AuditService : RepositoryService, IAuditService ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IAuditRepository auditRepository, - IUserService userService, + IUserIdKeyResolver userIdKeyResolver, IEntityService entityService) : base(provider, loggerFactory, eventMessagesFactory) { _auditRepository = auditRepository; - _userService = userService; + _userIdKeyResolver = userIdKeyResolver; _entityService = entityService; } - /// - /// Initializes a new instance of the class. - /// - [Obsolete("Use the non-obsolete constructor. Scheduled for removal in Umbraco 19.")] - public AuditService( - ICoreScopeProvider provider, - ILoggerFactory loggerFactory, - IEventMessagesFactory eventMessagesFactory, - IAuditRepository auditRepository, - IAuditEntryRepository auditEntryRepository, - IUserService userService, - IEntityService entityService) - : this( - provider, - loggerFactory, - eventMessagesFactory, - auditRepository, - userService, - entityService) - { - } - /// public async Task> AddAsync( AuditType type, @@ -68,7 +46,9 @@ public sealed class AuditService : RepositoryService, IAuditService string? comment = null, string? parameters = null) { - var userId = (await _userService.GetAsync(userKey))?.Id; + int? userId = await _userIdKeyResolver.TryGetAsync(userKey) is { Success: true } userIdAttempt + ? userIdAttempt.Result + : null; if (userId is null) { return Attempt.Fail(AuditLogOperationStatus.UserNotFound); @@ -245,8 +225,7 @@ public sealed class AuditService : RepositoryService, IAuditService ArgumentOutOfRangeException.ThrowIfNegative(skip); ArgumentOutOfRangeException.ThrowIfNegativeOrZero(take); - IUser? user = await _userService.GetAsync(userKey); - if (user is null) + if (await _userIdKeyResolver.TryGetAsync(userKey) is not { Success: true } userIdAttempt) { return new PagedModel(); } @@ -256,7 +235,7 @@ public sealed class AuditService : RepositoryService, IAuditService sinceDate.HasValue ? Query().Where(x => x.CreateDate >= sinceDate) : null; PagedModel result = GetItemsByUserInner( - user.Id, + userIdAttempt.Result, pageIndex, pageSize, orderDirection, @@ -418,7 +397,7 @@ public sealed class AuditService : RepositoryService, IAuditService AuditType[]? auditTypeFilter = null, IQuery? customFilter = null) { - if (userId is < Constants.Security.SuperUserId) + if (userId < Constants.Security.SuperUserId) { return new PagedModel { Items = [], Total = 0 }; } @@ -434,3 +413,4 @@ public sealed class AuditService : RepositoryService, IAuditService scope.Complete(); } } + diff --git a/src/Umbraco.Core/Services/ContentBlueprintContainerService.cs b/src/Umbraco.Core/Services/ContentBlueprintContainerService.cs index e8d742b70e..046c475632 100644 --- a/src/Umbraco.Core/Services/ContentBlueprintContainerService.cs +++ b/src/Umbraco.Core/Services/ContentBlueprintContainerService.cs @@ -13,10 +13,10 @@ internal sealed class ContentBlueprintContainerService : EntityTypeContainerServ ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDocumentBlueprintContainerRepository entityContainerRepository, - IAuditRepository auditRepository, + IAuditService auditService, IEntityRepository entityRepository, IUserIdKeyResolver userIdKeyResolver) - : base(provider, loggerFactory, eventMessagesFactory, entityContainerRepository, auditRepository, entityRepository, userIdKeyResolver) + : base(provider, loggerFactory, eventMessagesFactory, entityContainerRepository, auditService, entityRepository, userIdKeyResolver) { } diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 0c3b61a1c3..246682ec14 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -27,7 +27,7 @@ namespace Umbraco.Cms.Core.Services; /// public class ContentService : RepositoryService, IContentService { - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; private readonly IContentTypeRepository _contentTypeRepository; private readonly IDocumentBlueprintRepository _documentBlueprintRepository; private readonly IDocumentRepository _documentRepository; @@ -52,7 +52,7 @@ public class ContentService : RepositoryService, IContentService IEventMessagesFactory eventMessagesFactory, IDocumentRepository documentRepository, IEntityRepository entityRepository, - IAuditRepository auditRepository, + IAuditService auditService, IContentTypeRepository contentTypeRepository, IDocumentBlueprintRepository documentBlueprintRepository, ILanguageRepository languageRepository, @@ -68,7 +68,7 @@ public class ContentService : RepositoryService, IContentService { _documentRepository = documentRepository; _entityRepository = entityRepository; - _auditRepository = auditRepository; + _auditService = auditService; _contentTypeRepository = contentTypeRepository; _documentBlueprintRepository = documentBlueprintRepository; _languageRepository = languageRepository; @@ -87,8 +87,7 @@ public class ContentService : RepositoryService, IContentService _logger = loggerFactory.CreateLogger(); } - [Obsolete("Use non-obsolete constructor. Scheduled for removal in V17.")] - + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] public ContentService( ICoreScopeProvider provider, ILoggerFactory loggerFactory, @@ -104,14 +103,16 @@ public class ContentService : RepositoryService, IContentService ICultureImpactFactory cultureImpactFactory, IUserIdKeyResolver userIdKeyResolver, PropertyEditorCollection propertyEditorCollection, - IIdKeyMap idKeyMap) + IIdKeyMap idKeyMap, + IOptionsMonitor optionsMonitor, + IRelationService relationService) : this( provider, loggerFactory, eventMessagesFactory, documentRepository, entityRepository, - auditRepository, + StaticServiceProvider.Instance.GetRequiredService(), contentTypeRepository, documentBlueprintRepository, languageRepository, @@ -121,11 +122,12 @@ public class ContentService : RepositoryService, IContentService userIdKeyResolver, propertyEditorCollection, idKeyMap, - StaticServiceProvider.Instance.GetRequiredService>(), - StaticServiceProvider.Instance.GetRequiredService()) + optionsMonitor, + relationService) { } - [Obsolete("Use non-obsolete constructor. Scheduled for removal in V17.")] + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] public ContentService( ICoreScopeProvider provider, ILoggerFactory loggerFactory, @@ -133,6 +135,7 @@ public class ContentService : RepositoryService, IContentService IDocumentRepository documentRepository, IEntityRepository entityRepository, IAuditRepository auditRepository, + IAuditService auditService, IContentTypeRepository contentTypeRepository, IDocumentBlueprintRepository documentBlueprintRepository, ILanguageRepository languageRepository, @@ -140,14 +143,17 @@ public class ContentService : RepositoryService, IContentService IShortStringHelper shortStringHelper, ICultureImpactFactory cultureImpactFactory, IUserIdKeyResolver userIdKeyResolver, - PropertyEditorCollection propertyEditorCollection) + PropertyEditorCollection propertyEditorCollection, + IIdKeyMap idKeyMap, + IOptionsMonitor optionsMonitor, + IRelationService relationService) : this( provider, loggerFactory, eventMessagesFactory, documentRepository, entityRepository, - auditRepository, + auditService, contentTypeRepository, documentBlueprintRepository, languageRepository, @@ -156,7 +162,9 @@ public class ContentService : RepositoryService, IContentService cultureImpactFactory, userIdKeyResolver, propertyEditorCollection, - StaticServiceProvider.Instance.GetRequiredService()) + idKeyMap, + optionsMonitor, + relationService) { } @@ -3084,7 +3092,20 @@ public class ContentService : RepositoryService, IContentService #region Private Methods private void Audit(AuditType type, int userId, int objectId, string? message = null, string? parameters = null) => - _auditRepository.Save(new AuditItem(objectId, type, userId, UmbracoObjectTypes.Document.GetName(), message, parameters)); + AuditAsync(type, userId, objectId, message, parameters).GetAwaiter().GetResult(); + + private async Task AuditAsync(AuditType type, int userId, int objectId, string? message = null, string? parameters = null) + { + Guid userKey = await _userIdKeyResolver.GetAsync(userId); + + await _auditService.AddAsync( + type, + userKey, + objectId, + UmbracoObjectTypes.Document.GetName(), + message, + parameters); + } private string GetLanguageDetailsForAuditEntry(IEnumerable affectedCultures) => GetLanguageDetailsForAuditEntry(_languageRepository.GetMany(), affectedCultures); diff --git a/src/Umbraco.Core/Services/ContentTypeContainerService.cs b/src/Umbraco.Core/Services/ContentTypeContainerService.cs index a6ac5e811f..6258216c8e 100644 --- a/src/Umbraco.Core/Services/ContentTypeContainerService.cs +++ b/src/Umbraco.Core/Services/ContentTypeContainerService.cs @@ -14,10 +14,10 @@ internal sealed class ContentTypeContainerService : EntityTypeContainerService ContentService = contentService; + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public ContentTypeService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IContentService contentService, + IContentTypeRepository repository, + IAuditRepository auditRepository, + IDocumentTypeContainerRepository entityContainerRepository, + IEntityRepository entityRepository, + IEventAggregator eventAggregator, + IUserIdKeyResolver userIdKeyResolver, + ContentTypeFilterCollection contentTypeFilters) + : this( + provider, + loggerFactory, + eventMessagesFactory, + contentService, + repository, + StaticServiceProvider.Instance.GetRequiredService(), + entityContainerRepository, + entityRepository, + eventAggregator, + userIdKeyResolver, + contentTypeFilters) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public ContentTypeService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IContentService contentService, + IContentTypeRepository repository, + IAuditRepository auditRepository, + IAuditService auditService, + IDocumentTypeContainerRepository entityContainerRepository, + IEntityRepository entityRepository, + IEventAggregator eventAggregator, + IUserIdKeyResolver userIdKeyResolver, + ContentTypeFilterCollection contentTypeFilters) + : this( + provider, + loggerFactory, + eventMessagesFactory, + contentService, + repository, + auditService, + entityContainerRepository, + entityRepository, + eventAggregator, + userIdKeyResolver, + contentTypeFilters) + { + } + protected override int[] ReadLockIds => ContentTypeLocks.ReadLockIds; protected override int[] WriteLockIds => ContentTypeLocks.WriteLockIds; diff --git a/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index cd72be54ab..58f3915d52 100644 --- a/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -1,6 +1,8 @@ using System.Globalization; using System.Runtime.InteropServices; +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.Models; @@ -20,7 +22,7 @@ public abstract class ContentTypeServiceBase : ContentTypeSe where TRepository : IContentTypeRepositoryBase where TItem : class, IContentTypeComposition { - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; private readonly IEntityContainerRepository _containerRepository; private readonly IEntityRepository _entityRepository; private readonly IEventAggregator _eventAggregator; @@ -32,7 +34,7 @@ public abstract class ContentTypeServiceBase : ContentTypeSe ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, TRepository repository, - IAuditRepository auditRepository, + IAuditService auditService, IEntityContainerRepository containerRepository, IEntityRepository entityRepository, IEventAggregator eventAggregator, @@ -41,7 +43,7 @@ public abstract class ContentTypeServiceBase : ContentTypeSe : base(provider, loggerFactory, eventMessagesFactory) { Repository = repository; - _auditRepository = auditRepository; + _auditService = auditService; _containerRepository = containerRepository; _entityRepository = entityRepository; _eventAggregator = eventAggregator; @@ -49,6 +51,32 @@ public abstract class ContentTypeServiceBase : ContentTypeSe _contentTypeFilters = contentTypeFilters; } + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + protected ContentTypeServiceBase( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + TRepository repository, + IAuditRepository auditRepository, + IEntityContainerRepository containerRepository, + IEntityRepository entityRepository, + IEventAggregator eventAggregator, + IUserIdKeyResolver userIdKeyResolver, + ContentTypeFilterCollection contentTypeFilters) + : this( + provider, + loggerFactory, + eventMessagesFactory, + repository, + StaticServiceProvider.Instance.GetRequiredService(), + containerRepository, + entityRepository, + eventAggregator, + userIdKeyResolver, + contentTypeFilters) + { + } + protected TRepository Repository { get; } protected abstract int[] WriteLockIds { get; } protected abstract int[] ReadLockIds { get; } @@ -1398,9 +1426,18 @@ public abstract class ContentTypeServiceBase : ContentTypeSe #region Audit - private void Audit(AuditType type, int userId, int objectId) + private void Audit(AuditType type, int userId, int objectId) => + AuditAsync(type, userId, objectId).GetAwaiter().GetResult(); + + private async Task AuditAsync(AuditType type, int userId, int objectId) { - _auditRepository.Save(new AuditItem(objectId, type, userId, ObjectTypes.GetUmbracoObjectType(ContainedObjectType).GetName())); + Guid userKey = await _userIdKeyResolver.GetAsync(userId); + + await _auditService.AddAsync( + type, + userKey, + objectId, + ObjectTypes.GetUmbracoObjectType(ContainedObjectType).GetName()); } #endregion diff --git a/src/Umbraco.Core/Services/ContentVersionService.cs b/src/Umbraco.Core/Services/ContentVersionService.cs index d6562351d7..5dddaad709 100644 --- a/src/Umbraco.Core/Services/ContentVersionService.cs +++ b/src/Umbraco.Core/Services/ContentVersionService.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Core.Services; internal sealed class ContentVersionService : IContentVersionService { - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; private readonly IContentVersionCleanupPolicy _contentVersionCleanupPolicy; private readonly IDocumentVersionRepository _documentVersionRepository; private readonly IEventMessagesFactory _eventMessagesFactory; @@ -32,7 +32,7 @@ internal sealed class ContentVersionService : IContentVersionService IContentVersionCleanupPolicy contentVersionCleanupPolicy, ICoreScopeProvider scopeProvider, IEventMessagesFactory eventMessagesFactory, - IAuditRepository auditRepository, + IAuditService auditService, ILanguageRepository languageRepository, IEntityService entityService, IContentService contentService, @@ -43,7 +43,7 @@ internal sealed class ContentVersionService : IContentVersionService _contentVersionCleanupPolicy = contentVersionCleanupPolicy; _scopeProvider = scopeProvider; _eventMessagesFactory = eventMessagesFactory; - _auditRepository = auditRepository; + _auditService = auditService; _languageRepository = languageRepository; _entityService = entityService; _contentService = contentService; @@ -299,16 +299,19 @@ internal sealed class ContentVersionService : IContentVersionService return versionsToDelete; } - private void Audit(AuditType type, int userId, int objectId, string? message = null, string? parameters = null) + private void Audit(AuditType type, int userId, int objectId, string? message = null, string? parameters = null) => + AuditAsync(type, userId, objectId, message, parameters).GetAwaiter().GetResult(); + + private async Task AuditAsync(AuditType type, int userId, int objectId, string? message = null, string? parameters = null) { - var entry = new AuditItem( - objectId, + Guid userKey = await _userIdKeyResolver.GetAsync(userId); + + await _auditService.AddAsync( type, - userId, + userKey, + objectId, UmbracoObjectTypes.Document.GetName(), message, parameters); - - _auditRepository.Save(entry); } } diff --git a/src/Umbraco.Core/Services/DataTypeContainerService.cs b/src/Umbraco.Core/Services/DataTypeContainerService.cs index 0e6292f7f1..8b892226ef 100644 --- a/src/Umbraco.Core/Services/DataTypeContainerService.cs +++ b/src/Umbraco.Core/Services/DataTypeContainerService.cs @@ -13,10 +13,10 @@ internal sealed class DataTypeContainerService : EntityTypeContainerService _idKeyMap; - [Obsolete("Please use the constructor taking all parameters. Scheduled for removal in Umbraco 17.")] public DataTypeService( ICoreScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDataTypeRepository dataTypeRepository, IDataValueEditorFactory dataValueEditorFactory, - IAuditRepository auditRepository, + IAuditService auditService, IContentTypeRepository contentTypeRepository, + IMediaTypeRepository mediaTypeRepository, + IMemberTypeRepository memberTypeRepository, IIOHelper ioHelper, Lazy idKeyMap) - : this( - provider, - loggerFactory, - eventMessagesFactory, - dataTypeRepository, - dataValueEditorFactory, - auditRepository, - contentTypeRepository, - StaticServiceProvider.Instance.GetRequiredService(), - StaticServiceProvider.Instance.GetRequiredService(), - ioHelper, - idKeyMap) + : base(provider, loggerFactory, eventMessagesFactory) { + _dataValueEditorFactory = dataValueEditorFactory; + _dataTypeRepository = dataTypeRepository; + _auditService = auditService; + _contentTypeRepository = contentTypeRepository; + _mediaTypeRepository = mediaTypeRepository; + _memberTypeRepository = memberTypeRepository; + _ioHelper = ioHelper; + _idKeyMap = idKeyMap; + + // resolve dependencies for obsolete methods through the static service provider, so they don't pollute the constructor signature + _dataTypeContainerService = StaticServiceProvider.Instance.GetRequiredService(); + _dataTypeContainerRepository = StaticServiceProvider.Instance.GetRequiredService(); + _userIdKeyResolver = StaticServiceProvider.Instance.GetRequiredService(); } + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] public DataTypeService( ICoreScopeProvider provider, ILoggerFactory loggerFactory, @@ -71,21 +75,48 @@ namespace Umbraco.Cms.Core.Services.Implement IMemberTypeRepository memberTypeRepository, IIOHelper ioHelper, Lazy idKeyMap) - : base(provider, loggerFactory, eventMessagesFactory) + : this( + provider, + loggerFactory, + eventMessagesFactory, + dataTypeRepository, + dataValueEditorFactory, + StaticServiceProvider.Instance.GetRequiredService(), + contentTypeRepository, + mediaTypeRepository, + memberTypeRepository, + ioHelper, + idKeyMap) { - _dataValueEditorFactory = dataValueEditorFactory; - _dataTypeRepository = dataTypeRepository; - _auditRepository = auditRepository; - _contentTypeRepository = contentTypeRepository; - _mediaTypeRepository = mediaTypeRepository; - _memberTypeRepository = memberTypeRepository; - _ioHelper = ioHelper; - _idKeyMap = idKeyMap; + } - // resolve dependencies for obsolete methods through the static service provider, so they don't pollute the constructor signature - _dataTypeContainerService = StaticServiceProvider.Instance.GetRequiredService(); - _dataTypeContainerRepository = StaticServiceProvider.Instance.GetRequiredService(); - _userIdKeyResolver = StaticServiceProvider.Instance.GetRequiredService(); + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public DataTypeService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IDataTypeRepository dataTypeRepository, + IDataValueEditorFactory dataValueEditorFactory, + IAuditRepository auditRepository, + IAuditService auditService, + IContentTypeRepository contentTypeRepository, + IMediaTypeRepository mediaTypeRepository, + IMemberTypeRepository memberTypeRepository, + IIOHelper ioHelper, + Lazy idKeyMap) + : this( + provider, + loggerFactory, + eventMessagesFactory, + dataTypeRepository, + dataValueEditorFactory, + auditService, + contentTypeRepository, + mediaTypeRepository, + memberTypeRepository, + ioHelper, + idKeyMap) + { } #region Containers @@ -474,8 +505,7 @@ namespace Umbraco.Cms.Core.Services.Implement scope.Notifications.Publish(new DataTypeMovedNotification(moveEventInfo, eventMessages).WithStateFrom(movingDataTypeNotification)); - var currentUserId = await _userIdKeyResolver.GetAsync(userKey); - Audit(AuditType.Move, currentUserId, toMove.Id); + await AuditAsync(AuditType.Move, userKey, toMove.Id); scope.Complete(); } @@ -597,7 +627,7 @@ namespace Umbraco.Cms.Core.Services.Implement : DataTypeOperationStatus.Success; }, userKey, - AuditType.New); + AuditType.Save); /// /// Saves a collection of @@ -705,8 +735,7 @@ namespace Umbraco.Cms.Core.Services.Implement scope.Notifications.Publish(new DataTypeDeletedNotification(dataType, eventMessages).WithStateFrom(deletingDataTypeNotification)); - var currentUserId = await _userIdKeyResolver.GetAsync(userKey); - Audit(AuditType.Delete, currentUserId, dataType.Id); + await AuditAsync(AuditType.Delete, userKey, dataType.Id); scope.Complete(); @@ -902,7 +931,7 @@ namespace Umbraco.Cms.Core.Services.Implement scope.Notifications.Publish(new DataTypeSavedNotification(dataType, eventMessages).WithStateFrom(savingDataTypeNotification)); - Audit(auditType, currentUserId, dataType.Id); + await AuditAsync(auditType, userKey, dataType.Id); scope.Complete(); return Attempt.SucceedWithStatus(DataTypeOperationStatus.Success, dataType); @@ -915,7 +944,20 @@ namespace Umbraco.Cms.Core.Services.Implement { Result: var intId } => _dataTypeRepository.Get(intId), }; - private void Audit(AuditType type, int userId, int objectId) - => _auditRepository.Save(new AuditItem(objectId, type, userId, ObjectTypes.GetName(UmbracoObjectTypes.DataType))); + private void Audit(AuditType type, int userId, int objectId) => + AuditAsync(type, userId, objectId).GetAwaiter().GetResult(); + + private async Task AuditAsync(AuditType type, int userId, int objectId) + { + Guid userKey = await _userIdKeyResolver.GetAsync(userId); + await AuditAsync(type, userKey, objectId); + } + + private async Task AuditAsync(AuditType type, Guid userKey, int objectId) => + await _auditService.AddAsync( + type, + userKey, + objectId, + UmbracoObjectTypes.DataType.GetName()); } } diff --git a/src/Umbraco.Core/Services/DictionaryItemService.cs b/src/Umbraco.Core/Services/DictionaryItemService.cs index 467f4ea26a..c8cb2605b5 100644 --- a/src/Umbraco.Core/Services/DictionaryItemService.cs +++ b/src/Umbraco.Core/Services/DictionaryItemService.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Core.Services; internal sealed class DictionaryItemService : RepositoryService, IDictionaryItemService { private readonly IDictionaryRepository _dictionaryRepository; - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; private readonly ILanguageService _languageService; private readonly IUserIdKeyResolver _userIdKeyResolver; @@ -21,13 +21,13 @@ internal sealed class DictionaryItemService : RepositoryService, IDictionaryItem ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDictionaryRepository dictionaryRepository, - IAuditRepository auditRepository, + IAuditService auditService, ILanguageService languageService, IUserIdKeyResolver userIdKeyResolver) : base(provider, loggerFactory, eventMessagesFactory) { _dictionaryRepository = dictionaryRepository; - _auditRepository = auditRepository; + _auditService = auditService; _languageService = languageService; _userIdKeyResolver = userIdKeyResolver; } @@ -199,8 +199,7 @@ internal sealed class DictionaryItemService : RepositoryService, IDictionaryItem new DictionaryItemDeletedNotification(dictionaryItem, eventMessages) .WithStateFrom(deletingNotification)); - var currentUserId = await _userIdKeyResolver.GetAsync(userKey); - Audit(AuditType.Delete, "Delete DictionaryItem", currentUserId, dictionaryItem.Id, nameof(DictionaryItem)); + await AuditAsync(AuditType.Delete, "Delete DictionaryItem", userKey, dictionaryItem.Id, nameof(DictionaryItem)); scope.Complete(); return Attempt.SucceedWithStatus(DictionaryItemOperationStatus.Success, dictionaryItem); @@ -261,8 +260,7 @@ internal sealed class DictionaryItemService : RepositoryService, IDictionaryItem scope.Notifications.Publish( new DictionaryItemMovedNotification(moveEventInfo, eventMessages).WithStateFrom(movingNotification)); - var currentUserId = await _userIdKeyResolver.GetAsync(userKey); - Audit(AuditType.Move, "Move DictionaryItem", currentUserId, dictionaryItem.Id, nameof(DictionaryItem)); + await AuditAsync(AuditType.Move, "Move DictionaryItem", userKey, dictionaryItem.Id, nameof(DictionaryItem)); scope.Complete(); return Attempt.SucceedWithStatus(DictionaryItemOperationStatus.Success, dictionaryItem); @@ -322,8 +320,7 @@ internal sealed class DictionaryItemService : RepositoryService, IDictionaryItem scope.Notifications.Publish( new DictionaryItemSavedNotification(dictionaryItem, eventMessages).WithStateFrom(savingNotification)); - var currentUserId = await _userIdKeyResolver.GetAsync(userKey); - Audit(auditType, auditMessage, currentUserId, dictionaryItem.Id, nameof(DictionaryItem)); + await AuditAsync(auditType, auditMessage, userKey, dictionaryItem.Id, nameof(DictionaryItem)); scope.Complete(); return Attempt.SucceedWithStatus(DictionaryItemOperationStatus.Success, dictionaryItem); @@ -339,8 +336,13 @@ internal sealed class DictionaryItemService : RepositoryService, IDictionaryItem } } - private void Audit(AuditType type, string message, int userId, int objectId, string? entityType) => - _auditRepository.Save(new AuditItem(objectId, type, userId, entityType, message)); + private async Task AuditAsync(AuditType type, string message, Guid userKey, int objectId, string? entityType) => + await _auditService.AddAsync( + type, + userKey, + objectId, + entityType, + message); private bool HasValidParent(IDictionaryItem dictionaryItem) => dictionaryItem.ParentId.HasValue == false || _dictionaryRepository.Get(dictionaryItem.ParentId.Value) != null; diff --git a/src/Umbraco.Core/Services/EntityTypeContainerService.cs b/src/Umbraco.Core/Services/EntityTypeContainerService.cs index 575ff11f2e..46532ad067 100644 --- a/src/Umbraco.Core/Services/EntityTypeContainerService.cs +++ b/src/Umbraco.Core/Services/EntityTypeContainerService.cs @@ -14,7 +14,7 @@ internal abstract class EntityTypeContainerService _auditRepository.Save(new AuditItem(objectId, type, userId, ContainerObjectType.GetName())); + private async Task AuditAsync(AuditType type, Guid userKey, int objectId) => + await _auditService.AddAsync( + type, + userKey, + objectId, + ContainerObjectType.GetName()); private void ReadLock(ICoreScope scope) { diff --git a/src/Umbraco.Core/Services/FileService.cs b/src/Umbraco.Core/Services/FileService.cs index eae1944b5d..cf0873c2e8 100644 --- a/src/Umbraco.Core/Services/FileService.cs +++ b/src/Umbraco.Core/Services/FileService.cs @@ -1,7 +1,9 @@ using System.Text.RegularExpressions; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Models; @@ -22,7 +24,7 @@ namespace Umbraco.Cms.Core.Services; public class FileService : RepositoryService, IFileService { private const string PartialViewHeader = "@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage"; - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; private readonly IHostingEnvironment _hostingEnvironment; private readonly IPartialViewRepository _partialViewRepository; private readonly IScriptRepository _scriptRepository; @@ -31,6 +33,31 @@ public class FileService : RepositoryService, IFileService private readonly ITemplateRepository _templateRepository; private readonly IUserIdKeyResolver _userIdKeyResolver; + public FileService( + ICoreScopeProvider uowProvider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IStylesheetRepository stylesheetRepository, + IScriptRepository scriptRepository, + IPartialViewRepository partialViewRepository, + IAuditService auditService, + IHostingEnvironment hostingEnvironment, + ITemplateService templateService, + ITemplateRepository templateRepository, + IUserIdKeyResolver userIdKeyResolver) + : base(uowProvider, loggerFactory, eventMessagesFactory) + { + _stylesheetRepository = stylesheetRepository; + _scriptRepository = scriptRepository; + _partialViewRepository = partialViewRepository; + _auditService = auditService; + _hostingEnvironment = hostingEnvironment; + _templateService = templateService; + _templateRepository = templateRepository; + _userIdKeyResolver = userIdKeyResolver; + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] public FileService( ICoreScopeProvider uowProvider, ILoggerFactory loggerFactory, @@ -45,16 +72,50 @@ public class FileService : RepositoryService, IFileService IUserIdKeyResolver userIdKeyResolver, IShortStringHelper shortStringHelper, IOptions globalSettings) - : base(uowProvider, loggerFactory, eventMessagesFactory) + : this( + uowProvider, + loggerFactory, + eventMessagesFactory, + stylesheetRepository, + scriptRepository, + partialViewRepository, + StaticServiceProvider.Instance.GetRequiredService(), + hostingEnvironment, + templateService, + templateRepository, + userIdKeyResolver) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public FileService( + ICoreScopeProvider uowProvider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IStylesheetRepository stylesheetRepository, + IScriptRepository scriptRepository, + IPartialViewRepository partialViewRepository, + IAuditService auditService, + IAuditRepository auditRepository, + IHostingEnvironment hostingEnvironment, + ITemplateService templateService, + ITemplateRepository templateRepository, + IUserIdKeyResolver userIdKeyResolver, + IShortStringHelper shortStringHelper, + IOptions globalSettings) + : this( + uowProvider, + loggerFactory, + eventMessagesFactory, + stylesheetRepository, + scriptRepository, + partialViewRepository, + auditService, + hostingEnvironment, + templateService, + templateRepository, + userIdKeyResolver) { - _stylesheetRepository = stylesheetRepository; - _scriptRepository = scriptRepository; - _partialViewRepository = partialViewRepository; - _auditRepository = auditRepository; - _hostingEnvironment = hostingEnvironment; - _templateService = templateService; - _templateRepository = templateRepository; - _userIdKeyResolver = userIdKeyResolver; } #region Stylesheets @@ -70,7 +131,18 @@ public class FileService : RepositoryService, IFileService } private void Audit(AuditType type, int userId, int objectId, string? entityType) => - _auditRepository.Save(new AuditItem(objectId, type, userId, entityType)); + AuditAsync(type, userId, objectId, entityType).GetAwaiter().GetResult(); + + private async Task AuditAsync(AuditType type, int userId, int objectId, string? entityType) + { + Guid userKey = await _userIdKeyResolver.GetAsync(userId); + + await _auditService.AddAsync( + type, + userKey, + objectId, + entityType); + } /// [Obsolete("Please use IStylesheetService for stylesheet operations - will be removed in Umbraco 15")] diff --git a/src/Umbraco.Core/Services/FileServiceOperationBase.cs b/src/Umbraco.Core/Services/FileServiceOperationBase.cs index e7b392d949..88501af28a 100644 --- a/src/Umbraco.Core/Services/FileServiceOperationBase.cs +++ b/src/Umbraco.Core/Services/FileServiceOperationBase.cs @@ -1,4 +1,6 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Notifications; @@ -16,14 +18,41 @@ public abstract class FileServiceOperationBase _logger; private readonly IUserIdKeyResolver _userIdKeyResolver; - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; - protected FileServiceOperationBase(ICoreScopeProvider provider, ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, TRepository repository, ILogger logger, IUserIdKeyResolver userIdKeyResolver, IAuditRepository auditRepository) + protected FileServiceOperationBase( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + TRepository repository, + ILogger logger, + IUserIdKeyResolver userIdKeyResolver, + IAuditService auditService) : base(provider, loggerFactory, eventMessagesFactory, repository) { _logger = logger; _userIdKeyResolver = userIdKeyResolver; - _auditRepository = auditRepository; + _auditService = auditService; + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + protected FileServiceOperationBase( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + TRepository repository, + ILogger logger, + IUserIdKeyResolver userIdKeyResolver, + IAuditRepository auditRepository) + : this( + provider, + loggerFactory, + eventMessagesFactory, + repository, + logger, + userIdKeyResolver, + StaticServiceProvider.Instance.GetRequiredService()) + { } protected abstract TOperationStatus Success { get; } @@ -249,10 +278,7 @@ public abstract class FileServiceOperationBase await _auditService.AddAsync(type, userKey, -1, EntityType); private string GetFilePath(string? parentPath, string fileName) => Path.Join(parentPath, fileName); diff --git a/src/Umbraco.Core/Services/LanguageService.cs b/src/Umbraco.Core/Services/LanguageService.cs index 01a249dbd0..e32b2c988e 100644 --- a/src/Umbraco.Core/Services/LanguageService.cs +++ b/src/Umbraco.Core/Services/LanguageService.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Core.Services; internal sealed class LanguageService : RepositoryService, ILanguageService { private readonly ILanguageRepository _languageRepository; - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; private readonly IUserIdKeyResolver _userIdKeyResolver; private readonly IIsoCodeValidator _isoCodeValidator; @@ -22,13 +22,13 @@ internal sealed class LanguageService : RepositoryService, ILanguageService ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, ILanguageRepository languageRepository, - IAuditRepository auditRepository, + IAuditService auditService, IUserIdKeyResolver userIdKeyResolver, IIsoCodeValidator isoCodeValidator) : base(provider, loggerFactory, eventMessagesFactory) { _languageRepository = languageRepository; - _auditRepository = auditRepository; + _auditService = auditService; _userIdKeyResolver = userIdKeyResolver; _isoCodeValidator = isoCodeValidator; } @@ -160,8 +160,7 @@ internal sealed class LanguageService : RepositoryService, ILanguageService scope.Notifications.Publish( new LanguageDeletedNotification(language, eventMessages).WithStateFrom(deletingLanguageNotification)); - var currentUserId = await _userIdKeyResolver.GetAsync(userKey); - Audit(AuditType.Delete, "Delete Language", currentUserId, language.Id, UmbracoObjectTypes.Language.GetName()); + await AuditAsync(AuditType.Delete, "Delete Language", userKey, language.Id, UmbracoObjectTypes.Language.GetName()); scope.Complete(); return Attempt.SucceedWithStatus(LanguageOperationStatus.Success, language); } @@ -213,16 +212,20 @@ internal sealed class LanguageService : RepositoryService, ILanguageService scope.Notifications.Publish( new LanguageSavedNotification(language, eventMessages).WithStateFrom(savingNotification)); - var currentUserId = await _userIdKeyResolver.GetAsync(userKey); - Audit(auditType, auditMessage, currentUserId, language.Id, UmbracoObjectTypes.Language.GetName()); + await AuditAsync(auditType, auditMessage, userKey, language.Id, UmbracoObjectTypes.Language.GetName()); scope.Complete(); return Attempt.SucceedWithStatus(LanguageOperationStatus.Success, language); } } - private void Audit(AuditType type, string message, int userId, int objectId, string? entityType) => - _auditRepository.Save(new AuditItem(objectId, type, userId, entityType, message)); + private async Task AuditAsync(AuditType type, string message, Guid userKey, int objectId, string? entityType) => + await _auditService.AddAsync( + type, + userKey, + objectId, + entityType, + message); private bool HasInvalidFallbackLanguage(ILanguage language) { diff --git a/src/Umbraco.Core/Services/LocalizationService.cs b/src/Umbraco.Core/Services/LocalizationService.cs index 989b8f8206..0e0d2ad922 100644 --- a/src/Umbraco.Core/Services/LocalizationService.cs +++ b/src/Umbraco.Core/Services/LocalizationService.cs @@ -17,7 +17,6 @@ namespace Umbraco.Cms.Core.Services; [Obsolete("Please use ILanguageService and IDictionaryItemService for localization. Will be removed in V15.")] internal class LocalizationService : RepositoryService, ILocalizationService { - private readonly IAuditRepository _auditRepository; private readonly IDictionaryRepository _dictionaryRepository; private readonly ILanguageRepository _languageRepository; private readonly ILanguageService _languageService; @@ -30,14 +29,12 @@ internal class LocalizationService : RepositoryService, ILocalizationService ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDictionaryRepository dictionaryRepository, - IAuditRepository auditRepository, ILanguageRepository languageRepository) : this( provider, loggerFactory, eventMessagesFactory, dictionaryRepository, - auditRepository, languageRepository, StaticServiceProvider.Instance.GetRequiredService(), StaticServiceProvider.Instance.GetRequiredService(), @@ -51,7 +48,6 @@ internal class LocalizationService : RepositoryService, ILocalizationService ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IDictionaryRepository dictionaryRepository, - IAuditRepository auditRepository, ILanguageRepository languageRepository, ILanguageService languageService, IDictionaryItemService dictionaryItemService, @@ -59,7 +55,6 @@ internal class LocalizationService : RepositoryService, ILocalizationService : base(provider, loggerFactory, eventMessagesFactory) { _dictionaryRepository = dictionaryRepository; - _auditRepository = auditRepository; _languageRepository = languageRepository; _languageService = languageService; _dictionaryItemService = dictionaryItemService; diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index f2ee90696b..2ff78811f3 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -1,5 +1,7 @@ using System.Globalization; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; @@ -22,7 +24,7 @@ namespace Umbraco.Cms.Core.Services { private readonly IMediaRepository _mediaRepository; private readonly IMediaTypeRepository _mediaTypeRepository; - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; private readonly IEntityRepository _entityRepository; private readonly IShortStringHelper _shortStringHelper; private readonly IUserIdKeyResolver _userIdKeyResolver; @@ -37,7 +39,7 @@ namespace Umbraco.Cms.Core.Services ILoggerFactory loggerFactory, IEventMessagesFactory eventMessagesFactory, IMediaRepository mediaRepository, - IAuditRepository auditRepository, + IAuditService auditService, IMediaTypeRepository mediaTypeRepository, IEntityRepository entityRepository, IShortStringHelper shortStringHelper, @@ -46,13 +48,66 @@ namespace Umbraco.Cms.Core.Services { _mediaFileManager = mediaFileManager; _mediaRepository = mediaRepository; - _auditRepository = auditRepository; + _auditService = auditService; _mediaTypeRepository = mediaTypeRepository; _entityRepository = entityRepository; _shortStringHelper = shortStringHelper; _userIdKeyResolver = userIdKeyResolver; } + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public MediaService( + ICoreScopeProvider provider, + MediaFileManager mediaFileManager, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IMediaRepository mediaRepository, + IAuditRepository auditRepository, + IMediaTypeRepository mediaTypeRepository, + IEntityRepository entityRepository, + IShortStringHelper shortStringHelper, + IUserIdKeyResolver userIdKeyResolver) + : this( + provider, + mediaFileManager, + loggerFactory, + eventMessagesFactory, + mediaRepository, + StaticServiceProvider.Instance.GetRequiredService(), + mediaTypeRepository, + entityRepository, + shortStringHelper, + userIdKeyResolver) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public MediaService( + ICoreScopeProvider provider, + MediaFileManager mediaFileManager, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IMediaRepository mediaRepository, + IAuditService auditService, + IAuditRepository auditRepository, + IMediaTypeRepository mediaTypeRepository, + IEntityRepository entityRepository, + IShortStringHelper shortStringHelper, + IUserIdKeyResolver userIdKeyResolver) + : this( + provider, + mediaFileManager, + loggerFactory, + eventMessagesFactory, + mediaRepository, + auditService, + mediaTypeRepository, + entityRepository, + shortStringHelper, + userIdKeyResolver) + { + } + #endregion #region Count @@ -788,7 +843,7 @@ namespace Umbraco.Cms.Core.Services scope.Notifications.Publish(new MediaSavedNotification(mediasA, messages).WithStateFrom(savingNotification)); // TODO: See note about suppressing events in content service scope.Notifications.Publish(new MediaTreeChangeNotification(treeChanges, messages)); - Audit(AuditType.Save, userId == -1 ? 0 : userId, Constants.System.Root, "Bulk save media"); + Audit(AuditType.Save, userId, Constants.System.Root, "Bulk save media"); scope.Complete(); } @@ -1235,9 +1290,20 @@ namespace Umbraco.Cms.Core.Services #region Private Methods - private void Audit(AuditType type, int userId, int objectId, string? message = null) + private void Audit(AuditType type, int userId, int objectId, string? message = null) => + AuditAsync(type, userId, objectId, message).GetAwaiter().GetResult(); + + private async Task AuditAsync(AuditType type, int userId, int objectId, string? message = null, string? parameters = null) { - _auditRepository.Save(new AuditItem(objectId, type, userId, ObjectTypes.GetName(UmbracoObjectTypes.Media), message)); + Guid userKey = await _userIdKeyResolver.GetAsync(userId); + + await _auditService.AddAsync( + type, + userKey, + objectId, + UmbracoObjectTypes.Media.GetName(), + message, + parameters); } #endregion diff --git a/src/Umbraco.Core/Services/MediaTypeContainerService.cs b/src/Umbraco.Core/Services/MediaTypeContainerService.cs index 6aeb9af484..548b38b70d 100644 --- a/src/Umbraco.Core/Services/MediaTypeContainerService.cs +++ b/src/Umbraco.Core/Services/MediaTypeContainerService.cs @@ -14,10 +14,10 @@ internal sealed class MediaTypeContainerService : EntityTypeContainerService MediaService = mediaService; + contentTypeFilters) + { + MediaService = mediaService; + } + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public MediaTypeService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IMediaService mediaService, + IMediaTypeRepository mediaTypeRepository, + IAuditRepository auditRepository, + IMediaTypeContainerRepository entityContainerRepository, + IEntityRepository entityRepository, + IEventAggregator eventAggregator, + IUserIdKeyResolver userIdKeyResolver, + ContentTypeFilterCollection contentTypeFilters) + : this( + provider, + loggerFactory, + eventMessagesFactory, + mediaService, + mediaTypeRepository, + StaticServiceProvider.Instance.GetRequiredService(), + entityContainerRepository, + entityRepository, + eventAggregator, + userIdKeyResolver, + contentTypeFilters) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public MediaTypeService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IMediaService mediaService, + IMediaTypeRepository mediaTypeRepository, + IAuditService auditService, + IAuditRepository auditRepository, + IMediaTypeContainerRepository entityContainerRepository, + IEntityRepository entityRepository, + IEventAggregator eventAggregator, + IUserIdKeyResolver userIdKeyResolver, + ContentTypeFilterCollection contentTypeFilters) + : this( + provider, + loggerFactory, + eventMessagesFactory, + mediaService, + mediaTypeRepository, + auditService, + entityContainerRepository, + entityRepository, + eventAggregator, + userIdKeyResolver, + contentTypeFilters) + { + } protected override int[] ReadLockIds => MediaTypeLocks.ReadLockIds; diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs index e88881be42..588eefcc96 100644 --- a/src/Umbraco.Core/Services/MemberService.cs +++ b/src/Umbraco.Core/Services/MemberService.cs @@ -1,4 +1,6 @@ +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Membership; @@ -19,9 +21,10 @@ namespace Umbraco.Cms.Core.Services private readonly IMemberRepository _memberRepository; private readonly IMemberTypeRepository _memberTypeRepository; private readonly IMemberGroupRepository _memberGroupRepository; - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; private readonly IMemberGroupService _memberGroupService; private readonly Lazy _idKeyMap; + private readonly IUserIdKeyResolver _userIdKeyResolver; #region Constructor @@ -33,18 +36,72 @@ namespace Umbraco.Cms.Core.Services IMemberRepository memberRepository, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, - IAuditRepository auditRepository, - Lazy idKeyMap) + IAuditService auditService, + Lazy idKeyMap, + IUserIdKeyResolver userIdKeyResolver) : base(provider, loggerFactory, eventMessagesFactory) { _memberRepository = memberRepository; _memberTypeRepository = memberTypeRepository; _memberGroupRepository = memberGroupRepository; - _auditRepository = auditRepository; + _auditService = auditService; _idKeyMap = idKeyMap; + _userIdKeyResolver = userIdKeyResolver; _memberGroupService = memberGroupService ?? throw new ArgumentNullException(nameof(memberGroupService)); } + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public MemberService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IMemberGroupService memberGroupService, + IMemberRepository memberRepository, + IMemberTypeRepository memberTypeRepository, + IMemberGroupRepository memberGroupRepository, + IAuditRepository auditRepository, + Lazy idKeyMap) + : this( + provider, + loggerFactory, + eventMessagesFactory, + memberGroupService, + memberRepository, + memberTypeRepository, + memberGroupRepository, + StaticServiceProvider.Instance.GetRequiredService(), + idKeyMap, + StaticServiceProvider.Instance.GetRequiredService()) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public MemberService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IMemberGroupService memberGroupService, + IMemberRepository memberRepository, + IMemberTypeRepository memberTypeRepository, + IMemberGroupRepository memberGroupRepository, + IAuditService auditService, + IAuditRepository auditRepository, + Lazy idKeyMap, + IUserIdKeyResolver userIdKeyResolver) + : this( + provider, + loggerFactory, + eventMessagesFactory, + memberGroupService, + memberRepository, + memberTypeRepository, + memberGroupRepository, + auditService, + idKeyMap, + userIdKeyResolver) + { + } + #endregion #region Count @@ -1139,7 +1196,21 @@ namespace Umbraco.Cms.Core.Services #region Private Methods - private void Audit(AuditType type, int userId, int objectId, string? message = null) => _auditRepository.Save(new AuditItem(objectId, type, userId, ObjectTypes.GetName(UmbracoObjectTypes.Member), message)); + private void Audit(AuditType type, int userId, int objectId, string? message = null) => + AuditAsync(type, userId, objectId, message).GetAwaiter().GetResult(); + + private async Task AuditAsync(AuditType type, int userId, int objectId, string? message = null, string? parameters = null) + { + Guid userKey = await _userIdKeyResolver.GetAsync(userId); + + await _auditService.AddAsync( + type, + userKey, + objectId, + UmbracoObjectTypes.Member.GetName(), + message, + parameters); + } private IMember? GetMemberFromRepository(Guid id) => _idKeyMap.Value.GetIdForKey(id, UmbracoObjectTypes.Member) switch diff --git a/src/Umbraco.Core/Services/MemberTypeService.cs b/src/Umbraco.Core/Services/MemberTypeService.cs index c8313ad618..228a10a026 100644 --- a/src/Umbraco.Core/Services/MemberTypeService.cs +++ b/src/Umbraco.Core/Services/MemberTypeService.cs @@ -1,4 +1,6 @@ +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Notifications; @@ -20,7 +22,7 @@ public class MemberTypeService : ContentTypeServiceBase(), + entityContainerRepository, + entityRepository, + eventAggregator, + userIdKeyResolver, + contentTypeFilters) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public MemberTypeService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IMemberService memberService, + IMemberTypeRepository memberTypeRepository, + IAuditService auditService, + IAuditRepository auditRepository, + IMemberTypeContainerRepository entityContainerRepository, + IEntityRepository entityRepository, + IEventAggregator eventAggregator, + IUserIdKeyResolver userIdKeyResolver, + ContentTypeFilterCollection contentTypeFilters) + : this( + provider, + loggerFactory, + eventMessagesFactory, + memberService, + memberTypeRepository, + auditService, + entityContainerRepository, + entityRepository, + eventAggregator, + userIdKeyResolver, + contentTypeFilters) + { + } + // beware! order is important to avoid deadlocks protected override int[] ReadLockIds { get; } = { Constants.Locks.MemberTypes }; diff --git a/src/Umbraco.Core/Services/PartialViewService.cs b/src/Umbraco.Core/Services/PartialViewService.cs index 9543f45f28..043eac5ac4 100644 --- a/src/Umbraco.Core/Services/PartialViewService.cs +++ b/src/Umbraco.Core/Services/PartialViewService.cs @@ -1,4 +1,6 @@ +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Notifications; @@ -14,6 +16,19 @@ public class PartialViewService : FileServiceOperationBase logger, + IUserIdKeyResolver userIdKeyResolver, + IAuditService auditService, + PartialViewSnippetCollection snippetCollection) + : base(provider, loggerFactory, eventMessagesFactory, repository, logger, userIdKeyResolver, auditService) + => _snippetCollection = snippetCollection; + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] public PartialViewService( ICoreScopeProvider provider, ILoggerFactory loggerFactory, @@ -23,8 +38,40 @@ public class PartialViewService : FileServiceOperationBase _snippetCollection = snippetCollection; + : this( + provider, + loggerFactory, + eventMessagesFactory, + repository, + logger, + userIdKeyResolver, + StaticServiceProvider.Instance.GetRequiredService(), + snippetCollection) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public PartialViewService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IPartialViewRepository repository, + ILogger logger, + IUserIdKeyResolver userIdKeyResolver, + IAuditService auditService, + IAuditRepository auditRepository, + PartialViewSnippetCollection snippetCollection) + : this( + provider, + loggerFactory, + eventMessagesFactory, + repository, + logger, + userIdKeyResolver, + auditService, + snippetCollection) + { + } protected override string[] AllowedFileExtensions { get; } = { ".cshtml" }; diff --git a/src/Umbraco.Core/Services/RelationService.cs b/src/Umbraco.Core/Services/RelationService.cs index 456a3bb8dc..35adb2e217 100644 --- a/src/Umbraco.Core/Services/RelationService.cs +++ b/src/Umbraco.Core/Services/RelationService.cs @@ -1,4 +1,6 @@ +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -13,7 +15,7 @@ namespace Umbraco.Cms.Core.Services; public class RelationService : RepositoryService, IRelationService { - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; private readonly IUserIdKeyResolver _userIdKeyResolver; private readonly IEntityService _entityService; private readonly IRelationRepository _relationRepository; @@ -26,17 +28,62 @@ public class RelationService : RepositoryService, IRelationService IEntityService entityService, IRelationRepository relationRepository, IRelationTypeRepository relationTypeRepository, - IAuditRepository auditRepository, + IAuditService auditService, IUserIdKeyResolver userIdKeyResolver) : base(uowProvider, loggerFactory, eventMessagesFactory) { _relationRepository = relationRepository; _relationTypeRepository = relationTypeRepository; - _auditRepository = auditRepository; + _auditService = auditService; _userIdKeyResolver = userIdKeyResolver; _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); } + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public RelationService( + ICoreScopeProvider uowProvider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IEntityService entityService, + IRelationRepository relationRepository, + IRelationTypeRepository relationTypeRepository, + IAuditRepository auditRepository, + IUserIdKeyResolver userIdKeyResolver) + : this( + uowProvider, + loggerFactory, + eventMessagesFactory, + entityService, + relationRepository, + relationTypeRepository, + StaticServiceProvider.Instance.GetRequiredService(), + userIdKeyResolver) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public RelationService( + ICoreScopeProvider uowProvider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IEntityService entityService, + IRelationRepository relationRepository, + IRelationTypeRepository relationTypeRepository, + IAuditService auditService, + IAuditRepository auditRepository, + IUserIdKeyResolver userIdKeyResolver) + : this( + uowProvider, + loggerFactory, + eventMessagesFactory, + entityService, + relationRepository, + relationTypeRepository, + auditService, + userIdKeyResolver) + { + } + /// public IRelation? GetById(int id) { @@ -601,8 +648,7 @@ public class RelationService : RepositoryService, IRelationService } _relationTypeRepository.Save(relationType); - var currentUser = await _userIdKeyResolver.GetAsync(userKey); - Audit(auditType, currentUser, relationType.Id, auditMessage); + await AuditAsync(auditType, userKey, relationType.Id, auditMessage); scope.Complete(); scope.Notifications.Publish( new RelationTypeSavedNotification(relationType, eventMessages).WithStateFrom(savingNotification)); @@ -666,8 +712,7 @@ public class RelationService : RepositoryService, IRelationService } _relationTypeRepository.Delete(relationType); - var currentUser = await _userIdKeyResolver.GetAsync(userKey); - Audit(AuditType.Delete, currentUser, relationType.Id, "Deleted relation type"); + await AuditAsync(AuditType.Delete, userKey, relationType.Id, "Deleted relation type"); scope.Notifications.Publish(new RelationTypeDeletedNotification(relationType, eventMessages).WithStateFrom(deletingNotification)); scope.Complete(); return Attempt.SucceedWithStatus(RelationTypeOperationStatus.Success, relationType); @@ -744,7 +789,23 @@ public class RelationService : RepositoryService, IRelationService } private void Audit(AuditType type, int userId, int objectId, string? message = null) => - _auditRepository.Save(new AuditItem(objectId, type, userId, UmbracoObjectTypes.RelationType.GetName(), message)); + AuditAsync(type, userId, objectId, message).GetAwaiter().GetResult(); + + private async Task AuditAsync(AuditType type, int userId, int objectId, string? message = null, string? parameters = null) + { + Guid userKey = await _userIdKeyResolver.GetAsync(userId); + + await AuditAsync(type, userKey, objectId, message, parameters); + } + + private async Task AuditAsync(AuditType type, Guid userKey, int objectId, string? message = null, string? parameters = null) => + await _auditService.AddAsync( + type, + userKey, + objectId, + UmbracoObjectTypes.RelationType.GetName(), + message, + parameters); #endregion } diff --git a/src/Umbraco.Core/Services/ScriptService.cs b/src/Umbraco.Core/Services/ScriptService.cs index e64822c1e1..91a89298b2 100644 --- a/src/Umbraco.Core/Services/ScriptService.cs +++ b/src/Umbraco.Core/Services/ScriptService.cs @@ -1,4 +1,6 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Notifications; @@ -10,6 +12,19 @@ namespace Umbraco.Cms.Core.Services; public class ScriptService : FileServiceOperationBase, IScriptService { + public ScriptService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IScriptRepository repository, + ILogger logger, + IUserIdKeyResolver userIdKeyResolver, + IAuditService auditService) + : base(provider, loggerFactory, eventMessagesFactory, repository, logger, userIdKeyResolver, auditService) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] public ScriptService( ICoreScopeProvider provider, ILoggerFactory loggerFactory, @@ -18,7 +33,35 @@ public class ScriptService : FileServiceOperationBase logger, IUserIdKeyResolver userIdKeyResolver, IAuditRepository auditRepository) - : base(provider, loggerFactory, eventMessagesFactory, repository, logger, userIdKeyResolver, auditRepository) + : this( + provider, + loggerFactory, + eventMessagesFactory, + repository, + logger, + userIdKeyResolver, + StaticServiceProvider.Instance.GetRequiredService()) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public ScriptService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IScriptRepository repository, + ILogger logger, + IUserIdKeyResolver userIdKeyResolver, + IAuditService auditService, + IAuditRepository auditRepository) + : this( + provider, + loggerFactory, + eventMessagesFactory, + repository, + logger, + userIdKeyResolver, + auditService) { } diff --git a/src/Umbraco.Core/Services/StylesheetService.cs b/src/Umbraco.Core/Services/StylesheetService.cs index 08bab2a84a..2137de92b8 100644 --- a/src/Umbraco.Core/Services/StylesheetService.cs +++ b/src/Umbraco.Core/Services/StylesheetService.cs @@ -1,4 +1,6 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Notifications; @@ -10,6 +12,19 @@ namespace Umbraco.Cms.Core.Services; public class StylesheetService : FileServiceOperationBase, IStylesheetService { + public StylesheetService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IStylesheetRepository repository, + ILogger logger, + IUserIdKeyResolver userIdKeyResolver, + IAuditService auditService) + : base(provider, loggerFactory, eventMessagesFactory, repository, logger, userIdKeyResolver, auditService) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] public StylesheetService( ICoreScopeProvider provider, ILoggerFactory loggerFactory, @@ -18,7 +33,35 @@ public class StylesheetService : FileServiceOperationBase logger, IUserIdKeyResolver userIdKeyResolver, IAuditRepository auditRepository) - : base(provider, loggerFactory, eventMessagesFactory, repository, logger, userIdKeyResolver, auditRepository) + : this( + provider, + loggerFactory, + eventMessagesFactory, + repository, + logger, + userIdKeyResolver, + StaticServiceProvider.Instance.GetRequiredService()) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public StylesheetService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IStylesheetRepository repository, + ILogger logger, + IUserIdKeyResolver userIdKeyResolver, + IAuditService auditService, + IAuditRepository auditRepository) + : this( + provider, + loggerFactory, + eventMessagesFactory, + repository, + logger, + userIdKeyResolver, + auditService) { } diff --git a/src/Umbraco.Core/Services/TemplateService.cs b/src/Umbraco.Core/Services/TemplateService.cs index 80391c28b5..cfb70aefe5 100644 --- a/src/Umbraco.Core/Services/TemplateService.cs +++ b/src/Umbraco.Core/Services/TemplateService.cs @@ -1,4 +1,6 @@ +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models; @@ -16,11 +18,26 @@ public class TemplateService : RepositoryService, ITemplateService { private readonly IShortStringHelper _shortStringHelper; private readonly ITemplateRepository _templateRepository; - private readonly IAuditRepository _auditRepository; + private readonly IAuditService _auditService; private readonly ITemplateContentParserService _templateContentParserService; - private readonly IUserIdKeyResolver _userIdKeyResolver; - private readonly IDefaultViewContentProvider _defaultViewContentProvider; + public TemplateService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IShortStringHelper shortStringHelper, + ITemplateRepository templateRepository, + IAuditService auditService, + ITemplateContentParserService templateContentParserService) + : base(provider, loggerFactory, eventMessagesFactory) + { + _shortStringHelper = shortStringHelper; + _templateRepository = templateRepository; + _auditService = auditService; + _templateContentParserService = templateContentParserService; + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] public TemplateService( ICoreScopeProvider provider, ILoggerFactory loggerFactory, @@ -31,14 +48,38 @@ public class TemplateService : RepositoryService, ITemplateService ITemplateContentParserService templateContentParserService, IUserIdKeyResolver userIdKeyResolver, IDefaultViewContentProvider defaultViewContentProvider) - : base(provider, loggerFactory, eventMessagesFactory) + : this( + provider, + loggerFactory, + eventMessagesFactory, + shortStringHelper, + templateRepository, + StaticServiceProvider.Instance.GetRequiredService(), + templateContentParserService) + { + } + + [Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")] + public TemplateService( + ICoreScopeProvider provider, + ILoggerFactory loggerFactory, + IEventMessagesFactory eventMessagesFactory, + IShortStringHelper shortStringHelper, + ITemplateRepository templateRepository, + IAuditService auditService, + IAuditRepository auditRepository, + ITemplateContentParserService templateContentParserService, + IUserIdKeyResolver userIdKeyResolver, + IDefaultViewContentProvider defaultViewContentProvider) + : this( + provider, + loggerFactory, + eventMessagesFactory, + shortStringHelper, + templateRepository, + auditService, + templateContentParserService) { - _shortStringHelper = shortStringHelper; - _templateRepository = templateRepository; - _auditRepository = auditRepository; - _templateContentParserService = templateContentParserService; - _userIdKeyResolver = userIdKeyResolver; - _defaultViewContentProvider = defaultViewContentProvider; } /// @@ -81,8 +122,7 @@ public class TemplateService : RepositoryService, ITemplateService scope.Notifications.Publish( new TemplateSavedNotification(template, eventMessages).WithStateFrom(savingEvent)); - var currentUserId = await _userIdKeyResolver.GetAsync(userKey); - Audit(AuditType.New, currentUserId, template.Id, UmbracoObjectTypes.Template.GetName()); + await Audit(AuditType.New, userKey, template.Id, UmbracoObjectTypes.Template.GetName()); scope.Complete(); } @@ -270,8 +310,7 @@ public class TemplateService : RepositoryService, ITemplateService scope.Notifications.Publish( new TemplateSavedNotification(template, eventMessages).WithStateFrom(savingNotification)); - var currentUserId = await _userIdKeyResolver.GetAsync(userKey); - Audit(auditType, currentUserId, template.Id, UmbracoObjectTypes.Template.GetName()); + await Audit(auditType, userKey, template.Id, UmbracoObjectTypes.Template.GetName()); scope.Complete(); return Attempt.SucceedWithStatus(TemplateOperationStatus.Success, template); } @@ -391,8 +430,8 @@ public class TemplateService : RepositoryService, ITemplateService } } - private void Audit(AuditType type, int userId, int objectId, string? entityType) => - _auditRepository.Save(new AuditItem(objectId, type, userId, entityType)); + private Task Audit(AuditType type, Guid userKey, int objectId, string? entityType) => + _auditService.AddAsync(type, userKey, objectId, entityType); private async Task> DeleteAsync(Func> getTemplate, Guid userKey) { @@ -424,8 +463,7 @@ public class TemplateService : RepositoryService, ITemplateService scope.Notifications.Publish( new TemplateDeletedNotification(template, eventMessages).WithStateFrom(deletingNotification)); - var currentUserId = await _userIdKeyResolver.GetAsync(userKey); - Audit(AuditType.Delete, currentUserId, template.Id, UmbracoObjectTypes.Template.GetName()); + await Audit(AuditType.Delete, userKey, template.Id, UmbracoObjectTypes.Template.GetName()); scope.Complete(); return Attempt.SucceedWithStatus(TemplateOperationStatus.Success, template); } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/AuditServiceTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/AuditServiceTests.cs index d5fdaa7537..ed7ad3bcd4 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/AuditServiceTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/AuditServiceTests.cs @@ -23,7 +23,7 @@ public class AuditServiceTests private Mock _scopeProviderMock; private Mock _auditRepositoryMock; private Mock _entityServiceMock; - private Mock _userServiceMock; + private Mock _userIdKeyResolverMock; [SetUp] public void Setup() @@ -31,14 +31,14 @@ public class AuditServiceTests _scopeProviderMock = new Mock(MockBehavior.Strict); _auditRepositoryMock = new Mock(MockBehavior.Strict); _entityServiceMock = new Mock(MockBehavior.Strict); - _userServiceMock = new Mock(MockBehavior.Strict); + _userIdKeyResolverMock = new Mock(MockBehavior.Strict); _auditService = new AuditService( _scopeProviderMock.Object, Mock.Of(MockBehavior.Strict), Mock.Of(MockBehavior.Strict), _auditRepositoryMock.Object, - _userServiceMock.Object, + _userIdKeyResolverMock.Object, _entityServiceMock.Object); } @@ -59,10 +59,8 @@ public class AuditServiceTests Assert.AreEqual(parameters, item.Parameters); }); - Mock mockUser = new Mock(); - mockUser.Setup(x => x.Id).Returns(Constants.Security.SuperUserId); - - _userServiceMock.Setup(x => x.GetAsync(Constants.Security.SuperUserKey)).ReturnsAsync(mockUser.Object); + _userIdKeyResolverMock.Setup(x => x.TryGetAsync(Constants.Security.SuperUserKey)) + .ReturnsAsync(Attempt.Succeed(Constants.Security.SuperUserId)); var result = await _auditService.AddAsync( type, @@ -79,7 +77,7 @@ public class AuditServiceTests [Test] public async Task AddAsync_Does_Not_Succeed_When_Non_Existing_User_Is_Provided() { - _userServiceMock.Setup(x => x.GetAsync(It.IsAny())).ReturnsAsync((IUser?)null); + _userIdKeyResolverMock.Setup(x => x.TryGetAsync(It.IsAny())).ReturnsAsync(Attempt.Fail()); var result = await _auditService.AddAsync( AuditType.Publish,