Replace static events with notifications in MemberService, PublicAccessService and UserService, and clean up unused components etc.
This commit is contained in:
@@ -49,18 +49,6 @@ namespace Umbraco.Cms.Core.Cache
|
||||
|
||||
_logger.LogInformation("Initializing Umbraco internal event handlers for cache refreshing.");
|
||||
|
||||
// bind to user and user group events
|
||||
Bind(() => UserService.SavedUserGroup += UserService_SavedUserGroup,
|
||||
() => UserService.SavedUserGroup -= UserService_SavedUserGroup);
|
||||
Bind(() => UserService.DeletedUserGroup += UserService_DeletedUserGroup,
|
||||
() => UserService.DeletedUserGroup -= UserService_DeletedUserGroup);
|
||||
Bind(() => UserService.SavedUser += UserService_SavedUser,
|
||||
() => UserService.SavedUser -= UserService_SavedUser);
|
||||
Bind(() => UserService.DeletedUser += UserService_DeletedUser,
|
||||
() => UserService.DeletedUser -= UserService_DeletedUser);
|
||||
Bind(() => UserService.UserGroupPermissionsAssigned += UserService_UserGroupPermissionsAssigned,
|
||||
() => UserService.UserGroupPermissionsAssigned -= UserService_UserGroupPermissionsAssigned);
|
||||
|
||||
// bind to dictionary events
|
||||
Bind(() => LocalizationService.DeletedDictionaryItem += LocalizationService_DeletedDictionaryItem,
|
||||
() => LocalizationService.DeletedDictionaryItem -= LocalizationService_DeletedDictionaryItem);
|
||||
@@ -112,10 +100,6 @@ namespace Umbraco.Cms.Core.Cache
|
||||
() => MacroService.Deleted -= MacroService_Deleted);
|
||||
|
||||
// bind to member events
|
||||
Bind(() => MemberService.Saved += MemberService_Saved,
|
||||
() => MemberService.Saved -= MemberService_Saved);
|
||||
Bind(() => MemberService.Deleted += MemberService_Deleted,
|
||||
() => MemberService.Deleted -= MemberService_Deleted);
|
||||
Bind(() => MemberGroupService.Saved += MemberGroupService_Saved,
|
||||
() => MemberGroupService.Saved -= MemberGroupService_Saved);
|
||||
Bind(() => MemberGroupService.Deleted += MemberGroupService_Deleted,
|
||||
@@ -135,12 +119,6 @@ namespace Umbraco.Cms.Core.Cache
|
||||
//Bind(() => ContentService.DeletedBlueprint += ContentService_DeletedBlueprint,
|
||||
// () => ContentService.DeletedBlueprint -= ContentService_DeletedBlueprint);
|
||||
|
||||
// bind to public access events
|
||||
Bind(() => PublicAccessService.Saved += PublicAccessService_Saved,
|
||||
() => PublicAccessService.Saved -= PublicAccessService_Saved);
|
||||
Bind(() => PublicAccessService.Deleted += PublicAccessService_Deleted,
|
||||
() => PublicAccessService.Deleted -= PublicAccessService_Deleted);
|
||||
|
||||
// bind to relation type events
|
||||
Bind(() => RelationService.SavedRelationType += RelationService_SavedRelationType,
|
||||
() => RelationService.SavedRelationType -= RelationService_SavedRelationType);
|
||||
@@ -148,21 +126,6 @@ namespace Umbraco.Cms.Core.Cache
|
||||
() => RelationService.DeletedRelationType -= RelationService_DeletedRelationType);
|
||||
}
|
||||
|
||||
#region PublicAccessService
|
||||
|
||||
private void PublicAccessService_Saved(IPublicAccessService sender, SaveEventArgs<PublicAccessEntry> e)
|
||||
{
|
||||
|
||||
_distributedCache.RefreshPublicAccess();
|
||||
}
|
||||
|
||||
private void PublicAccessService_Deleted(IPublicAccessService sender, DeleteEventArgs<PublicAccessEntry> e)
|
||||
{
|
||||
_distributedCache.RefreshPublicAccess();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ContentService
|
||||
|
||||
/// <summary>
|
||||
@@ -296,45 +259,6 @@ namespace Umbraco.Cms.Core.Cache
|
||||
|
||||
#endregion
|
||||
|
||||
#region UserService
|
||||
|
||||
private void UserService_UserGroupPermissionsAssigned(IUserService sender, SaveEventArgs<EntityPermission> e)
|
||||
{
|
||||
// TODO: Not sure if we need this yet depends if we start caching permissions
|
||||
//var groupIds = e.SavedEntities.Select(x => x.UserGroupId).Distinct();
|
||||
//foreach (var groupId in groupIds)
|
||||
//{
|
||||
// DistributedCache.Instance.RefreshUserGroupPermissionsCache(groupId);
|
||||
//}
|
||||
}
|
||||
|
||||
private void UserService_SavedUser(IUserService sender, SaveEventArgs<IUser> e)
|
||||
{
|
||||
foreach (var entity in e.SavedEntities)
|
||||
_distributedCache.RefreshUserCache(entity.Id);
|
||||
}
|
||||
|
||||
private void UserService_DeletedUser(IUserService sender, DeleteEventArgs<IUser> e)
|
||||
{
|
||||
foreach (var entity in e.DeletedEntities)
|
||||
_distributedCache.RemoveUserCache(entity.Id);
|
||||
}
|
||||
|
||||
private void UserService_SavedUserGroup(IUserService sender, SaveEventArgs<UserGroupWithUsers> e)
|
||||
{
|
||||
foreach (var entity in e.SavedEntities)
|
||||
_distributedCache.RefreshUserGroupCache(entity.UserGroup.Id);
|
||||
}
|
||||
|
||||
private void UserService_DeletedUserGroup(IUserService sender, DeleteEventArgs<IUserGroup> e)
|
||||
{
|
||||
|
||||
foreach (var entity in e.DeletedEntities)
|
||||
_distributedCache.RemoveUserGroupCache(entity.Id);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FileService
|
||||
|
||||
/// <summary>
|
||||
@@ -390,20 +314,6 @@ namespace Umbraco.Cms.Core.Cache
|
||||
|
||||
#endregion
|
||||
|
||||
#region MemberService
|
||||
|
||||
private void MemberService_Deleted(IMemberService sender, DeleteEventArgs<IMember> e)
|
||||
{
|
||||
_distributedCache.RemoveMemberCache(e.DeletedEntities.ToArray());
|
||||
}
|
||||
|
||||
private void MemberService_Saved(IMemberService sender, SaveEventArgs<IMember> e)
|
||||
{
|
||||
_distributedCache.RefreshMemberCache(e.SavedEntities.ToArray());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MemberGroupService
|
||||
|
||||
private void MemberGroupService_Deleted(IMemberGroupService sender, DeleteEventArgs<IMemberGroup> e)
|
||||
|
||||
64
src/Umbraco.Infrastructure/Cache/DistributedCacheHandler.cs
Normal file
64
src/Umbraco.Infrastructure/Cache/DistributedCacheHandler.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Infrastructure.Services.Notifications;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Cache
|
||||
{
|
||||
internal class DistributedCacheHandler :
|
||||
INotificationHandler<SavedNotification<IMember>>,
|
||||
INotificationHandler<DeletedNotification<IMember>>,
|
||||
INotificationHandler<SavedNotification<IUser>>,
|
||||
INotificationHandler<DeletedNotification<IUser>>,
|
||||
INotificationHandler<SavedNotification<IUserGroup>>,
|
||||
INotificationHandler<DeletedNotification<IUserGroup>>,
|
||||
INotificationHandler<SavedNotification<PublicAccessEntry>>,
|
||||
INotificationHandler<DeletedNotification<PublicAccessEntry>>
|
||||
{
|
||||
private readonly DistributedCache _distributedCache;
|
||||
|
||||
public DistributedCacheHandler(DistributedCache distributedCache) => _distributedCache = distributedCache;
|
||||
|
||||
public void Handle(SavedNotification<IMember> notification) => _distributedCache.RefreshMemberCache(notification.SavedEntities.ToArray());
|
||||
|
||||
public void Handle(DeletedNotification<IMember> notification) => _distributedCache.RemoveMemberCache(notification.DeletedEntities.ToArray());
|
||||
|
||||
public void Handle(SavedNotification<IUser> notification)
|
||||
{
|
||||
foreach (var entity in notification.SavedEntities)
|
||||
{
|
||||
_distributedCache.RefreshUserCache(entity.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(DeletedNotification<IUser> notification)
|
||||
{
|
||||
foreach (var entity in notification.DeletedEntities)
|
||||
{
|
||||
_distributedCache.RemoveUserCache(entity.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(SavedNotification<IUserGroup> notification)
|
||||
{
|
||||
foreach (var entity in notification.SavedEntities)
|
||||
{
|
||||
_distributedCache.RefreshUserGroupCache(entity.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(DeletedNotification<IUserGroup> notification)
|
||||
{
|
||||
foreach (var entity in notification.DeletedEntities)
|
||||
{
|
||||
_distributedCache.RemoveUserGroupCache(entity.Id);
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(SavedNotification<PublicAccessEntry> notification) => _distributedCache.RefreshPublicAccess();
|
||||
|
||||
public void Handle(DeletedNotification<PublicAccessEntry> notification) => _distributedCache.RefreshPublicAccess();
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
|
||||
namespace Umbraco.Cms.Core.Compose
|
||||
{
|
||||
public sealed class AuditEventsComposer : ComponentComposer<AuditEventsComponent>, ICoreComposer
|
||||
{ }
|
||||
}
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
@@ -10,12 +9,21 @@ using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Net;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Implement;
|
||||
using Umbraco.Cms.Infrastructure.Services.Notifications;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Compose
|
||||
{
|
||||
public sealed class AuditEventsComponent : IComponent
|
||||
public sealed class AuditNotificationsHandler :
|
||||
INotificationHandler<SavedNotification<IMember>>,
|
||||
INotificationHandler<DeletedNotification<IMember>>,
|
||||
INotificationHandler<AssignedMemberRolesNotification>,
|
||||
INotificationHandler<RemovedMemberRolesNotification>,
|
||||
INotificationHandler<ExportedMemberNotification>,
|
||||
INotificationHandler<SavedNotification<IUser>>,
|
||||
INotificationHandler<DeletedNotification<IUser>>,
|
||||
INotificationHandler<SavedNotification<UserGroupWithUsers>>,
|
||||
INotificationHandler<AssignedUserGroupPermissionsNotification>
|
||||
{
|
||||
private readonly IAuditService _auditService;
|
||||
private readonly IUserService _userService;
|
||||
@@ -23,55 +31,26 @@ namespace Umbraco.Cms.Core.Compose
|
||||
private readonly IIpResolver _ipResolver;
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IMemberService _memberService;
|
||||
|
||||
public AuditEventsComponent(
|
||||
public AuditNotificationsHandler(
|
||||
IAuditService auditService,
|
||||
IUserService userService,
|
||||
IEntityService entityService,
|
||||
IIpResolver ipResolver,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
|
||||
IMemberService memberService)
|
||||
{
|
||||
_auditService = auditService;
|
||||
_userService = userService;
|
||||
_entityService = entityService;
|
||||
_ipResolver = ipResolver;
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
_memberService = memberService;
|
||||
_globalSettings = globalSettings.Value;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
UserService.SavedUserGroup += OnSavedUserGroupWithUsers;
|
||||
|
||||
UserService.SavedUser += OnSavedUser;
|
||||
UserService.DeletedUser += OnDeletedUser;
|
||||
UserService.UserGroupPermissionsAssigned += UserGroupPermissionAssigned;
|
||||
|
||||
MemberService.Saved += OnSavedMember;
|
||||
MemberService.Deleted += OnDeletedMember;
|
||||
MemberService.AssignedRoles += OnAssignedRoles;
|
||||
MemberService.RemovedRoles += OnRemovedRoles;
|
||||
MemberService.Exported += OnMemberExported;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
UserService.SavedUserGroup -= OnSavedUserGroupWithUsers;
|
||||
|
||||
UserService.SavedUser -= OnSavedUser;
|
||||
UserService.DeletedUser -= OnDeletedUser;
|
||||
UserService.UserGroupPermissionsAssigned -= UserGroupPermissionAssigned;
|
||||
|
||||
MemberService.Saved -= OnSavedMember;
|
||||
MemberService.Deleted -= OnDeletedMember;
|
||||
MemberService.AssignedRoles -= OnAssignedRoles;
|
||||
MemberService.RemovedRoles -= OnRemovedRoles;
|
||||
MemberService.Exported -= OnMemberExported;
|
||||
}
|
||||
|
||||
public static IUser UnknownUser(GlobalSettings globalSettings) => new User(globalSettings) { Id = Cms.Core.Constants.Security.UnknownUserId, Name = Cms.Core.Constants.Security.UnknownUserName, Email = "" };
|
||||
|
||||
private IUser CurrentPerformingUser
|
||||
{
|
||||
get
|
||||
@@ -82,45 +61,48 @@ namespace Umbraco.Cms.Core.Compose
|
||||
}
|
||||
}
|
||||
|
||||
private IUser GetPerformingUser(int userId)
|
||||
{
|
||||
var found = userId >= 0 ? _userService.GetUserById(userId) : null;
|
||||
return found ?? UnknownUser(_globalSettings);
|
||||
}
|
||||
public static IUser UnknownUser(GlobalSettings globalSettings) => new User(globalSettings) { Id = Cms.Core.Constants.Security.UnknownUserId, Name = Cms.Core.Constants.Security.UnknownUserName, Email = "" };
|
||||
|
||||
private string PerformingIp => _ipResolver.GetCurrentRequestIpAddress();
|
||||
|
||||
private string FormatEmail(IMember member)
|
||||
{
|
||||
return member == null ? string.Empty : member.Email.IsNullOrWhiteSpace() ? "" : $"<{member.Email}>";
|
||||
}
|
||||
private string FormatEmail(IMember member) => member == null ? string.Empty : member.Email.IsNullOrWhiteSpace() ? "" : $"<{member.Email}>";
|
||||
|
||||
private string FormatEmail(IUser user)
|
||||
{
|
||||
return user == null ? string.Empty : user.Email.IsNullOrWhiteSpace() ? "" : $"<{user.Email}>";
|
||||
}
|
||||
private string FormatEmail(IUser user) => user == null ? string.Empty : user.Email.IsNullOrWhiteSpace() ? "" : $"<{user.Email}>";
|
||||
|
||||
private void OnRemovedRoles(IMemberService sender, RolesEventArgs args)
|
||||
public void Handle(SavedNotification<IMember> notification)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var roles = string.Join(", ", args.Roles);
|
||||
var members = sender.GetAllMembers(args.MemberIds).ToDictionary(x => x.Id, x => x);
|
||||
foreach (var id in args.MemberIds)
|
||||
var members = notification.SavedEntities;
|
||||
foreach (var member in members)
|
||||
{
|
||||
members.TryGetValue(id, out var member);
|
||||
var dp = string.Join(", ", ((Member)member).GetWereDirtyProperties());
|
||||
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
DateTime.UtcNow,
|
||||
-1, $"Member {id} \"{member?.Name ?? "(unknown)"}\" {FormatEmail(member)}",
|
||||
"umbraco/member/roles/removed", $"roles modified, removed {roles}");
|
||||
-1, $"Member {member.Id} \"{member.Name}\" {FormatEmail(member)}",
|
||||
"umbraco/member/save", $"updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAssignedRoles(IMemberService sender, RolesEventArgs args)
|
||||
public void Handle(DeletedNotification<IMember> notification)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var roles = string.Join(", ", args.Roles);
|
||||
var members = sender.GetAllMembers(args.MemberIds).ToDictionary(x => x.Id, x => x);
|
||||
foreach (var id in args.MemberIds)
|
||||
var members = notification.DeletedEntities;
|
||||
foreach (var member in members)
|
||||
{
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
DateTime.UtcNow,
|
||||
-1, $"Member {member.Id} \"{member.Name}\" {FormatEmail(member)}",
|
||||
"umbraco/member/delete", $"delete member id:{member.Id} \"{member.Name}\" {FormatEmail(member)}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(AssignedMemberRolesNotification notification)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var roles = string.Join(", ", notification.Roles);
|
||||
var members = _memberService.GetAllMembers(notification.MemberIds).ToDictionary(x => x.Id, x => x);
|
||||
foreach (var id in notification.MemberIds)
|
||||
{
|
||||
members.TryGetValue(id, out var member);
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
@@ -130,10 +112,25 @@ namespace Umbraco.Cms.Core.Compose
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMemberExported(IMemberService sender, ExportedMemberEventArgs exportedMemberEventArgs)
|
||||
public void Handle(RemovedMemberRolesNotification notification)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var member = exportedMemberEventArgs.Member;
|
||||
var roles = string.Join(", ", notification.Roles);
|
||||
var members = _memberService.GetAllMembers(notification.MemberIds).ToDictionary(x => x.Id, x => x);
|
||||
foreach (var id in notification.MemberIds)
|
||||
{
|
||||
members.TryGetValue(id, out var member);
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
DateTime.UtcNow,
|
||||
-1, $"Member {id} \"{member?.Name ?? "(unknown)"}\" {FormatEmail(member)}",
|
||||
"umbraco/member/roles/removed", $"roles modified, removed {roles}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ExportedMemberNotification notification)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var member = notification.Member;
|
||||
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
DateTime.UtcNow,
|
||||
@@ -141,10 +138,40 @@ namespace Umbraco.Cms.Core.Compose
|
||||
"umbraco/member/exported", "exported member data");
|
||||
}
|
||||
|
||||
private void OnSavedUserGroupWithUsers(IUserService sender, SaveEventArgs<UserGroupWithUsers> saveEventArgs)
|
||||
public void Handle(SavedNotification<IUser> notification)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
foreach (var groupWithUser in saveEventArgs.SavedEntities)
|
||||
var affectedUsers = notification.SavedEntities;
|
||||
foreach (var affectedUser in affectedUsers)
|
||||
{
|
||||
var groups = affectedUser.WasPropertyDirty("Groups")
|
||||
? string.Join(", ", affectedUser.Groups.Select(x => x.Alias))
|
||||
: null;
|
||||
|
||||
var dp = string.Join(", ", ((User)affectedUser).GetWereDirtyProperties());
|
||||
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
DateTime.UtcNow,
|
||||
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
|
||||
"umbraco/user/save", $"updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)}{(groups == null ? "" : "; groups assigned: " + groups)}");
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(DeletedNotification<IUser> notification)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var affectedUsers = notification.DeletedEntities;
|
||||
foreach (var affectedUser in affectedUsers)
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
DateTime.UtcNow,
|
||||
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
|
||||
"umbraco/user/delete", "delete user");
|
||||
}
|
||||
|
||||
public void Handle(SavedNotification<UserGroupWithUsers> notification)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
foreach (var groupWithUser in notification.SavedEntities)
|
||||
{
|
||||
var group = groupWithUser.UserGroup;
|
||||
|
||||
@@ -192,13 +219,13 @@ namespace Umbraco.Cms.Core.Compose
|
||||
}
|
||||
}
|
||||
|
||||
private void UserGroupPermissionAssigned(IUserService sender, SaveEventArgs<EntityPermission> saveEventArgs)
|
||||
public void Handle(AssignedUserGroupPermissionsNotification notification)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var perms = saveEventArgs.SavedEntities;
|
||||
var perms = notification.EntityPermissions;
|
||||
foreach (var perm in perms)
|
||||
{
|
||||
var group = sender.GetUserGroupById(perm.UserGroupId);
|
||||
var group = _userService.GetUserGroupById(perm.UserGroupId);
|
||||
var assigned = string.Join(", ", perm.AssignedPermissions);
|
||||
var entity = _entityService.Get(perm.EntityId);
|
||||
|
||||
@@ -208,100 +235,5 @@ namespace Umbraco.Cms.Core.Compose
|
||||
"umbraco/user-group/permissions-change", $"assigning {(string.IsNullOrWhiteSpace(assigned) ? "(nothing)" : assigned)} on id:{perm.EntityId} \"{entity.Name}\"");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSavedMember(IMemberService sender, SaveEventArgs<IMember> saveEventArgs)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var members = saveEventArgs.SavedEntities;
|
||||
foreach (var member in members)
|
||||
{
|
||||
var dp = string.Join(", ", ((Member) member).GetWereDirtyProperties());
|
||||
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
DateTime.UtcNow,
|
||||
-1, $"Member {member.Id} \"{member.Name}\" {FormatEmail(member)}",
|
||||
"umbraco/member/save", $"updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDeletedMember(IMemberService sender, DeleteEventArgs<IMember> deleteEventArgs)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var members = deleteEventArgs.DeletedEntities;
|
||||
foreach (var member in members)
|
||||
{
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
DateTime.UtcNow,
|
||||
-1, $"Member {member.Id} \"{member.Name}\" {FormatEmail(member)}",
|
||||
"umbraco/member/delete", $"delete member id:{member.Id} \"{member.Name}\" {FormatEmail(member)}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSavedUser(IUserService sender, SaveEventArgs<IUser> saveEventArgs)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var affectedUsers = saveEventArgs.SavedEntities;
|
||||
foreach (var affectedUser in affectedUsers)
|
||||
{
|
||||
var groups = affectedUser.WasPropertyDirty("Groups")
|
||||
? string.Join(", ", affectedUser.Groups.Select(x => x.Alias))
|
||||
: null;
|
||||
|
||||
var dp = string.Join(", ", ((User)affectedUser).GetWereDirtyProperties());
|
||||
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
DateTime.UtcNow,
|
||||
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
|
||||
"umbraco/user/save", $"updating {(string.IsNullOrWhiteSpace(dp) ? "(nothing)" : dp)}{(groups == null ? "" : "; groups assigned: " + groups)}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDeletedUser(IUserService sender, DeleteEventArgs<IUser> deleteEventArgs)
|
||||
{
|
||||
var performingUser = CurrentPerformingUser;
|
||||
var affectedUsers = deleteEventArgs.DeletedEntities;
|
||||
foreach (var affectedUser in affectedUsers)
|
||||
_auditService.Write(performingUser.Id, $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}", PerformingIp,
|
||||
DateTime.UtcNow,
|
||||
affectedUser.Id, $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}",
|
||||
"umbraco/user/delete", "delete user");
|
||||
}
|
||||
|
||||
private void WriteAudit(int performingId, int affectedId, string ipAddress, string eventType, string eventDetails, string affectedDetails = null)
|
||||
{
|
||||
var performingUser = _userService.GetUserById(performingId);
|
||||
|
||||
var performingDetails = performingUser == null
|
||||
? $"User UNKNOWN:{performingId}"
|
||||
: $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}";
|
||||
|
||||
WriteAudit(performingId, performingDetails, affectedId, ipAddress, eventType, eventDetails, affectedDetails);
|
||||
}
|
||||
|
||||
private void WriteAudit(IUser performingUser, int affectedId, string ipAddress, string eventType, string eventDetails)
|
||||
{
|
||||
var performingDetails = performingUser == null
|
||||
? $"User UNKNOWN"
|
||||
: $"User \"{performingUser.Name}\" {FormatEmail(performingUser)}";
|
||||
|
||||
WriteAudit(performingUser?.Id ?? 0, performingDetails, affectedId, ipAddress, eventType, eventDetails);
|
||||
}
|
||||
|
||||
private void WriteAudit(int performingId, string performingDetails, int affectedId, string ipAddress, string eventType, string eventDetails, string affectedDetails = null)
|
||||
{
|
||||
if (affectedDetails == null)
|
||||
{
|
||||
var affectedUser = _userService.GetUserById(affectedId);
|
||||
affectedDetails = affectedUser == null
|
||||
? $"User UNKNOWN:{affectedId}"
|
||||
: $"User \"{affectedUser.Name}\" {FormatEmail(affectedUser)}";
|
||||
}
|
||||
|
||||
_auditService.Write(performingId, performingDetails,
|
||||
ipAddress,
|
||||
DateTime.UtcNow,
|
||||
affectedId, affectedDetails,
|
||||
eventType, eventDetails);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Actions;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Implement;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Compose
|
||||
{
|
||||
/// <remarks>
|
||||
/// TODO: this component must be removed entirely - there is some code duplication in <see cref="UserNotificationsHandler"/> in anticipation of this component being deleted
|
||||
/// </remarks>
|
||||
public sealed class NotificationsComponent : IComponent
|
||||
{
|
||||
private readonly Notifier _notifier;
|
||||
private readonly ActionCollection _actions;
|
||||
private readonly IContentService _contentService;
|
||||
|
||||
public NotificationsComponent(Notifier notifier, ActionCollection actions, IContentService contentService)
|
||||
{
|
||||
_notifier = notifier;
|
||||
_actions = actions;
|
||||
_contentService = contentService;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
//Send notifications for the public access changed action
|
||||
PublicAccessService.Saved += PublicAccessService_Saved;
|
||||
|
||||
UserService.UserGroupPermissionsAssigned += UserService_UserGroupPermissionsAssigned;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
PublicAccessService.Saved -= PublicAccessService_Saved;
|
||||
UserService.UserGroupPermissionsAssigned -= UserService_UserGroupPermissionsAssigned;
|
||||
}
|
||||
|
||||
private void UserService_UserGroupPermissionsAssigned(IUserService sender, SaveEventArgs<EntityPermission> args)
|
||||
=> UserServiceUserGroupPermissionsAssigned(args, _contentService);
|
||||
|
||||
private void PublicAccessService_Saved(IPublicAccessService sender, SaveEventArgs<PublicAccessEntry> args)
|
||||
=> PublicAccessServiceSaved(args, _contentService);
|
||||
|
||||
private void UserServiceUserGroupPermissionsAssigned(SaveEventArgs<EntityPermission> args, IContentService contentService)
|
||||
{
|
||||
var entities = contentService.GetByIds(args.SavedEntities.Select(e => e.EntityId)).ToArray();
|
||||
if (entities.Any() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_notifier.Notify(_actions.GetAction<ActionRights>(), entities);
|
||||
}
|
||||
|
||||
private void PublicAccessServiceSaved(SaveEventArgs<PublicAccessEntry> args, IContentService contentService)
|
||||
{
|
||||
var entities = contentService.GetByIds(args.SavedEntities.Select(e => e.ProtectedNodeId)).ToArray();
|
||||
if (entities.Any() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_notifier.Notify(_actions.GetAction<ActionProtect>(), entities);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class is used to send the notifications
|
||||
/// </summary>
|
||||
public sealed class Notifier
|
||||
{
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly ILocalizedTextService _textService;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ILogger<Notifier> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Notifier"/> class.
|
||||
/// </summary>
|
||||
public Notifier(
|
||||
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
INotificationService notificationService,
|
||||
IUserService userService,
|
||||
ILocalizedTextService textService,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
ILogger<Notifier> logger)
|
||||
{
|
||||
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
|
||||
_hostingEnvironment = hostingEnvironment;
|
||||
_notificationService = notificationService;
|
||||
_userService = userService;
|
||||
_textService = textService;
|
||||
_globalSettings = globalSettings.Value;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Notify(IAction action, params IContent[] entities)
|
||||
{
|
||||
var user = _backOfficeSecurityAccessor?.BackOfficeSecurity?.CurrentUser;
|
||||
|
||||
//if there is no current user, then use the admin
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogDebug("There is no current Umbraco user logged in, the notifications will be sent from the administrator");
|
||||
user = _userService.GetUserById(Constants.Security.SuperUserId);
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogWarning("Notifications can not be sent, no admin user with id {SuperUserId} could be resolved", Constants.Security.SuperUserId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SendNotification(user, entities, action, _hostingEnvironment.ApplicationMainUrl);
|
||||
}
|
||||
|
||||
private void SendNotification(IUser sender, IEnumerable<IContent> entities, IAction action, Uri siteUri)
|
||||
{
|
||||
if (sender == null) throw new ArgumentNullException(nameof(sender));
|
||||
if (siteUri == null)
|
||||
{
|
||||
_logger.LogWarning("Notifications can not be sent, no site URL is set (might be during boot process?)");
|
||||
return;
|
||||
}
|
||||
|
||||
//group by the content type variation since the emails will be different
|
||||
foreach(var contentVariantGroup in entities.GroupBy(x => x.ContentType.Variations))
|
||||
{
|
||||
_notificationService.SendNotifications(
|
||||
sender,
|
||||
contentVariantGroup,
|
||||
action.Letter.ToString(CultureInfo.InvariantCulture),
|
||||
_textService.Localize("actions", action.Alias),
|
||||
siteUri,
|
||||
((IUser user, NotificationEmailSubjectParams subject) x)
|
||||
=> _textService.Localize(
|
||||
"notifications/mailSubject",
|
||||
x.user.GetUserCulture(_textService, _globalSettings),
|
||||
new[] { x.subject.SiteUrl, x.subject.Action, x.subject.ItemName }),
|
||||
((IUser user, NotificationEmailBodyParams body, bool isHtml) x)
|
||||
=> _textService.Localize(
|
||||
x.isHtml ? "notifications/mailBodyHtml" : "notifications/mailBody",
|
||||
x.user.GetUserCulture(_textService, _globalSettings),
|
||||
new[]
|
||||
{
|
||||
x.body.RecipientName,
|
||||
x.body.Action,
|
||||
x.body.ItemName,
|
||||
x.body.EditedUser,
|
||||
x.body.SiteUrl,
|
||||
x.body.ItemId,
|
||||
//format the summary depending on if it's variant or not
|
||||
contentVariantGroup.Key == ContentVariation.Culture
|
||||
? (x.isHtml ? _textService.Localize("notifications/mailBodyVariantHtmlSummary", new[]{ x.body.Summary }) : _textService.Localize("notifications/mailBodyVariantSummary", new []{ x.body.Summary }))
|
||||
: x.body.Summary,
|
||||
x.body.ItemUrl
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Infrastructure.Services.Notifications;
|
||||
@@ -12,14 +14,10 @@ using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Compose
|
||||
{
|
||||
public sealed class NotificationsComposer : ComponentComposer<NotificationsComponent>, ICoreComposer
|
||||
public sealed class NotificationsComposer : ICoreComposer
|
||||
{
|
||||
public override void Compose(IUmbracoBuilder builder)
|
||||
public void Compose(IUmbracoBuilder builder)
|
||||
{
|
||||
base.Compose(builder);
|
||||
|
||||
builder.Services.AddUnique<NotificationsComponent.Notifier>();
|
||||
|
||||
// add handlers for sending user notifications (i.e. emails)
|
||||
builder.Services.AddUnique<UserNotificationsHandler.Notifier>();
|
||||
builder
|
||||
@@ -31,7 +29,9 @@ namespace Umbraco.Cms.Core.Compose
|
||||
.AddNotificationHandler<CopiedNotification<IContent>, UserNotificationsHandler>()
|
||||
.AddNotificationHandler<RolledBackNotification<IContent>, UserNotificationsHandler>()
|
||||
.AddNotificationHandler<SentToPublishNotification<IContent>, UserNotificationsHandler>()
|
||||
.AddNotificationHandler<UnpublishedNotification<IContent>, UserNotificationsHandler>();
|
||||
.AddNotificationHandler<UnpublishedNotification<IContent>, UserNotificationsHandler>()
|
||||
.AddNotificationHandler<AssignedUserGroupPermissionsNotification, UserNotificationsHandler>()
|
||||
.AddNotificationHandler<SavedNotification<PublicAccessEntry>, UserNotificationsHandler>();
|
||||
|
||||
// add handlers for building content relations
|
||||
builder
|
||||
@@ -51,10 +51,12 @@ namespace Umbraco.Cms.Core.Compose
|
||||
.AddNotificationHandler<DeletedNotification<IContent>, FileUploadPropertyEditor>()
|
||||
.AddNotificationHandler<DeletedNotification<IMedia>, FileUploadPropertyEditor>()
|
||||
.AddNotificationHandler<SavingNotification<IMedia>, FileUploadPropertyEditor>()
|
||||
.AddNotificationHandler<DeletedNotification<IMember>, FileUploadPropertyEditor>()
|
||||
.AddNotificationHandler<CopiedNotification<IContent>, ImageCropperPropertyEditor>()
|
||||
.AddNotificationHandler<DeletedNotification<IContent>, ImageCropperPropertyEditor>()
|
||||
.AddNotificationHandler<DeletedNotification<IMedia>, ImageCropperPropertyEditor>()
|
||||
.AddNotificationHandler<SavingNotification<IMedia>, ImageCropperPropertyEditor>();
|
||||
.AddNotificationHandler<SavingNotification<IMedia>, ImageCropperPropertyEditor>()
|
||||
.AddNotificationHandler<DeletedNotification<IMember>, ImageCropperPropertyEditor>();
|
||||
|
||||
// add notification handlers for redirect tracking
|
||||
builder
|
||||
@@ -62,6 +64,29 @@ namespace Umbraco.Cms.Core.Compose
|
||||
.AddNotificationHandler<PublishedNotification<IContent>, RedirectTrackingHandler>()
|
||||
.AddNotificationHandler<MovingNotification<IContent>, RedirectTrackingHandler>()
|
||||
.AddNotificationHandler<MovedNotification<IContent>, RedirectTrackingHandler>();
|
||||
|
||||
// add notification handlers for auditing
|
||||
builder
|
||||
.AddNotificationHandler<SavedNotification<IMember>, AuditNotificationsHandler>()
|
||||
.AddNotificationHandler<DeletedNotification<IMember>, AuditNotificationsHandler>()
|
||||
.AddNotificationHandler<AssignedMemberRolesNotification, AuditNotificationsHandler>()
|
||||
.AddNotificationHandler<RemovedMemberRolesNotification, AuditNotificationsHandler>()
|
||||
.AddNotificationHandler<ExportedMemberNotification, AuditNotificationsHandler>()
|
||||
.AddNotificationHandler<SavedNotification<IUser>, AuditNotificationsHandler>()
|
||||
.AddNotificationHandler<DeletedNotification<IUser>, AuditNotificationsHandler>()
|
||||
.AddNotificationHandler<SavedNotification<UserGroupWithUsers>, AuditNotificationsHandler>()
|
||||
.AddNotificationHandler<AssignedUserGroupPermissionsNotification, AuditNotificationsHandler>();
|
||||
|
||||
// add notifications handlers for distributed cache
|
||||
builder
|
||||
.AddNotificationHandler<SavedNotification<IMember>, DistributedCacheHandler>()
|
||||
.AddNotificationHandler<DeletedNotification<IMember>, DistributedCacheHandler>()
|
||||
.AddNotificationHandler<SavedNotification<IUser>, DistributedCacheHandler>()
|
||||
.AddNotificationHandler<DeletedNotification<IUser>, DistributedCacheHandler>()
|
||||
.AddNotificationHandler<SavedNotification<IUserGroup>, DistributedCacheHandler>()
|
||||
.AddNotificationHandler<DeletedNotification<IUserGroup>, DistributedCacheHandler>()
|
||||
.AddNotificationHandler<SavedNotification<PublicAccessEntry>, DistributedCacheHandler>()
|
||||
.AddNotificationHandler<DeletedNotification<PublicAccessEntry>, DistributedCacheHandler>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ namespace Umbraco.Cms.Core.Events
|
||||
INotificationHandler<CopiedNotification<IContent>>,
|
||||
INotificationHandler<RolledBackNotification<IContent>>,
|
||||
INotificationHandler<SentToPublishNotification<IContent>>,
|
||||
INotificationHandler<UnpublishedNotification<IContent>>
|
||||
INotificationHandler<UnpublishedNotification<IContent>>,
|
||||
INotificationHandler<AssignedUserGroupPermissionsNotification>,
|
||||
INotificationHandler<SavedNotification<PublicAccessEntry>>
|
||||
{
|
||||
private readonly Notifier _notifier;
|
||||
private readonly ActionCollection _actions;
|
||||
@@ -211,5 +213,26 @@ namespace Umbraco.Cms.Core.Events
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Handle(AssignedUserGroupPermissionsNotification notification)
|
||||
{
|
||||
var entities = _contentService.GetByIds(notification.EntityPermissions.Select(e => e.EntityId)).ToArray();
|
||||
if (entities.Any() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_notifier.Notify(_actions.GetAction<ActionRights>(), entities);
|
||||
|
||||
}
|
||||
|
||||
public void Handle(SavedNotification<PublicAccessEntry> notification)
|
||||
{
|
||||
var entities = _contentService.GetByIds(notification.SavedEntities.Select(e => e.ProtectedNodeId)).ToArray();
|
||||
if (entities.Any() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_notifier.Notify(_actions.GetAction<ActionProtect>(), entities);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
Icon = "icon-download-alt")]
|
||||
public class FileUploadPropertyEditor : DataEditor, IMediaUrlGenerator,
|
||||
INotificationHandler<CopiedNotification<IContent>>, INotificationHandler<DeletedNotification<IContent>>,
|
||||
INotificationHandler<DeletedNotification<IMedia>>, INotificationHandler<SavingNotification<IMedia>>
|
||||
INotificationHandler<DeletedNotification<IMedia>>, INotificationHandler<SavingNotification<IMedia>>,
|
||||
INotificationHandler<DeletedNotification<IMember>>
|
||||
{
|
||||
private readonly IMediaFileSystem _mediaFileSystem;
|
||||
private readonly ContentSettings _contentSettings;
|
||||
@@ -95,10 +96,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
/// The paths to all file upload property files contained within a collection of content entities
|
||||
/// </summary>
|
||||
/// <param name="entities"></param>
|
||||
/// <remarks>
|
||||
/// This method must be made private once MemberService events have been replaced by notifications
|
||||
/// </remarks>
|
||||
internal IEnumerable<string> ContainedFilePaths(IEnumerable<IContentBase> entities) => entities
|
||||
private IEnumerable<string> ContainedFilePaths(IEnumerable<IContentBase> entities) => entities
|
||||
.SelectMany(x => x.Properties)
|
||||
.Where(IsUploadField)
|
||||
.SelectMany(GetFilePathsFromPropertyValues)
|
||||
@@ -162,6 +160,8 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
|
||||
public void Handle(DeletedNotification<IMedia> notification) => DeleteContainedFiles(notification.DeletedEntities);
|
||||
|
||||
public void Handle(DeletedNotification<IMember> notification) => DeleteContainedFiles(notification.DeletedEntities);
|
||||
|
||||
private void DeleteContainedFiles(IEnumerable<IContentBase> deletedEntities)
|
||||
{
|
||||
var filePathsToDelete = ContainedFilePaths(deletedEntities);
|
||||
|
||||
@@ -34,7 +34,8 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
Icon = "icon-crop")]
|
||||
public class ImageCropperPropertyEditor : DataEditor, IMediaUrlGenerator,
|
||||
INotificationHandler<CopiedNotification<IContent>>, INotificationHandler<DeletedNotification<IContent>>,
|
||||
INotificationHandler<DeletedNotification<IMedia>>, INotificationHandler<SavingNotification<IMedia>>
|
||||
INotificationHandler<DeletedNotification<IMedia>>, INotificationHandler<SavingNotification<IMedia>>,
|
||||
INotificationHandler<DeletedNotification<IMember>>
|
||||
{
|
||||
private readonly IMediaFileSystem _mediaFileSystem;
|
||||
private readonly ContentSettings _contentSettings;
|
||||
@@ -131,10 +132,7 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
/// The paths to all image cropper property files contained within a collection of content entities
|
||||
/// </summary>
|
||||
/// <param name="entities"></param>
|
||||
/// <remarks>
|
||||
/// This method must be made private once MemberService events have been replaced by notifications
|
||||
/// </remarks>
|
||||
internal IEnumerable<string> ContainedFilePaths(IEnumerable<IContentBase> entities) => entities
|
||||
private IEnumerable<string> ContainedFilePaths(IEnumerable<IContentBase> entities) => entities
|
||||
.SelectMany(x => x.Properties)
|
||||
.Where(IsCropperField)
|
||||
.SelectMany(GetFilePathsFromPropertyValues)
|
||||
@@ -218,6 +216,8 @@ namespace Umbraco.Cms.Core.PropertyEditors
|
||||
|
||||
public void Handle(DeletedNotification<IMedia> notification) => DeleteContainedFiles(notification.DeletedEntities);
|
||||
|
||||
public void Handle(DeletedNotification<IMember> notification) => DeleteContainedFiles(notification.DeletedEntities);
|
||||
|
||||
private void DeleteContainedFiles(IEnumerable<IContentBase> deletedEntities)
|
||||
{
|
||||
var filePathsToDelete = ContainedFilePaths(deletedEntities);
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Implement;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
// TODO: delete this component and make the "ContainedFilePaths" methods on FileUploadPropertyEditor and ImageCropperPropertyEditor private once MemberService uses notifications instead of static events
|
||||
public sealed class PropertyEditorsComponent : IComponent
|
||||
{
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
private readonly List<Action> _terminate = new List<Action>();
|
||||
|
||||
public PropertyEditorsComponent(PropertyEditorCollection propertyEditors)
|
||||
{
|
||||
_propertyEditors = propertyEditors;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
var fileUpload = _propertyEditors.OfType<FileUploadPropertyEditor>().FirstOrDefault();
|
||||
if (fileUpload != null) Initialize(fileUpload);
|
||||
|
||||
var imageCropper = _propertyEditors.OfType<ImageCropperPropertyEditor>().FirstOrDefault();
|
||||
if (imageCropper != null) Initialize(imageCropper);
|
||||
|
||||
// grid/examine moved to ExamineComponent
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
foreach (var t in _terminate) t();
|
||||
}
|
||||
|
||||
private void Initialize(FileUploadPropertyEditor fileUpload)
|
||||
{
|
||||
void memberServiceDeleted(IMemberService sender, DeleteEventArgs<IMember> args) => args.MediaFilesToDelete.AddRange(fileUpload.ContainedFilePaths(args.DeletedEntities.Cast<ContentBase>()));
|
||||
MemberService.Deleted += memberServiceDeleted;
|
||||
_terminate.Add(() => MemberService.Deleted -= memberServiceDeleted);
|
||||
}
|
||||
|
||||
private void Initialize(ImageCropperPropertyEditor imageCropper)
|
||||
{
|
||||
void memberServiceDeleted(IMemberService sender, DeleteEventArgs<IMember> args) => args.MediaFilesToDelete.AddRange(imageCropper.ContainedFilePaths(args.DeletedEntities.Cast<ContentBase>()));
|
||||
MemberService.Deleted += memberServiceDeleted;
|
||||
_terminate.Add(() => MemberService.Deleted -= memberServiceDeleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
|
||||
namespace Umbraco.Cms.Core.PropertyEditors
|
||||
{
|
||||
public sealed class PropertyEditorsComposer : ComponentComposer<PropertyEditorsComponent>, ICoreComposer
|
||||
{ }
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Cms.Core.Persistence.Querying;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Querying;
|
||||
using Umbraco.Cms.Infrastructure.Services.Notifications;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Implement
|
||||
@@ -22,7 +23,6 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
private readonly IMemberTypeRepository _memberTypeRepository;
|
||||
private readonly IMemberGroupRepository _memberGroupRepository;
|
||||
private readonly IAuditRepository _auditRepository;
|
||||
private readonly IMemberTypeService _memberTypeService;
|
||||
|
||||
private readonly IMemberGroupService _memberGroupService;
|
||||
|
||||
@@ -773,10 +773,12 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
member.Username = member.Username.Trim();
|
||||
member.Email = member.Email.Trim();
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<IMember>(member);
|
||||
if (raiseEvents && scope.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
var savingNotification = new SavingNotification<IMember>(member, evtMsgs);
|
||||
if (raiseEvents && scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
@@ -793,8 +795,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
scope.Notifications.Publish(new SavedNotification<IMember>(member, evtMsgs).WithStateFrom(savingNotification));
|
||||
}
|
||||
|
||||
Audit(AuditType.Save, 0, member.Id);
|
||||
@@ -808,10 +809,12 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
{
|
||||
var membersA = members.ToArray();
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<IMember>(membersA);
|
||||
if (raiseEvents && scope.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
var savingNotification = new SavingNotification<IMember>(membersA, evtMsgs);
|
||||
if (raiseEvents && scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
@@ -830,8 +833,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
scope.Notifications.Publish(new SavedNotification<IMember>(membersA, evtMsgs).WithStateFrom(savingNotification));
|
||||
}
|
||||
Audit(AuditType.Save, 0, -1, "Save multiple Members");
|
||||
|
||||
@@ -849,32 +851,30 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <param name="member"><see cref="IMember"/> to Delete</param>
|
||||
public void Delete(IMember member)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var deleteEventArgs = new DeleteEventArgs<IMember>(member);
|
||||
if (scope.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
var deletingNotification = new DeletingNotification<IMember>(member, evtMsgs);
|
||||
if (scope.Notifications.PublishCancelable(deletingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
}
|
||||
|
||||
scope.WriteLock(Constants.Locks.MemberTree);
|
||||
DeleteLocked(scope, member, deleteEventArgs);
|
||||
DeleteLocked(scope, member, evtMsgs, deletingNotification.State);
|
||||
|
||||
Audit(AuditType.Delete, 0, member.Id);
|
||||
scope.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteLocked(IScope scope, IMember member, DeleteEventArgs<IMember> args = null)
|
||||
private void DeleteLocked(IScope scope, IMember member, EventMessages evtMsgs, IDictionary<string, object> notificationState = null)
|
||||
{
|
||||
// a member has no descendants
|
||||
_memberRepository.Delete(member);
|
||||
if (args == null)
|
||||
args = new DeleteEventArgs<IMember>(member, false); // raise event & get flagged files
|
||||
else
|
||||
args.CanCancel = false;
|
||||
scope.Events.Dispatch(Deleted, this, args);
|
||||
scope.Notifications.Publish(new DeletedNotification<IMember>(member, evtMsgs).WithState(notificationState));
|
||||
|
||||
// media files deleted by QueuingEventDispatcher
|
||||
}
|
||||
@@ -1017,8 +1017,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
scope.WriteLock(Constants.Locks.MemberTree);
|
||||
int[] ids = _memberGroupRepository.GetMemberIds(usernames);
|
||||
_memberGroupRepository.AssignRoles(ids, roleNames);
|
||||
scope.Events.Dispatch(AssignedRoles, this, new RolesEventArgs(ids, roleNames), nameof(AssignedRoles));
|
||||
scope.Complete();
|
||||
scope.Notifications.Publish(new AssignedMemberRolesNotification(ids, roleNames));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,8 +1030,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
scope.WriteLock(Constants.Locks.MemberTree);
|
||||
int[] ids = _memberGroupRepository.GetMemberIds(usernames);
|
||||
_memberGroupRepository.DissociateRoles(ids, roleNames);
|
||||
scope.Events.Dispatch(RemovedRoles, this, new RolesEventArgs(ids, roleNames), nameof(RemovedRoles));
|
||||
scope.Complete();
|
||||
scope.Notifications.Publish(new RemovedMemberRolesNotification(ids, roleNames));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1044,8 +1042,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
{
|
||||
scope.WriteLock(Constants.Locks.MemberTree);
|
||||
_memberGroupRepository.AssignRoles(memberIds, roleNames);
|
||||
scope.Events.Dispatch(AssignedRoles, this, new RolesEventArgs(memberIds, roleNames), nameof(AssignedRoles));
|
||||
scope.Complete();
|
||||
scope.Notifications.Publish(new AssignedMemberRolesNotification(memberIds, roleNames));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1057,8 +1054,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
{
|
||||
scope.WriteLock(Constants.Locks.MemberTree);
|
||||
_memberGroupRepository.DissociateRoles(memberIds, roleNames);
|
||||
scope.Events.Dispatch(RemovedRoles, this, new RolesEventArgs(memberIds, roleNames), nameof(RemovedRoles));
|
||||
scope.Complete();
|
||||
scope.Notifications.Publish(new RemovedMemberRolesNotification(memberIds, roleNames));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1072,36 +1068,6 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberService, DeleteEventArgs<IMember>> Deleting;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberService, DeleteEventArgs<IMember>> Deleted;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberService, SaveEventArgs<IMember>> Saving;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberService, SaveEventArgs<IMember>> Saved;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after roles have been assigned.
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberService, RolesEventArgs> AssignedRoles;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after roles have been removed.
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberService, RolesEventArgs> RemovedRoles;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after members have been exported.
|
||||
/// </summary>
|
||||
@@ -1145,7 +1111,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
Properties = new List<MemberExportProperty>(GetPropertyExportItems(member))
|
||||
};
|
||||
|
||||
scope.Events.Dispatch(Exported, this, new ExportedMemberEventArgs(member, model));
|
||||
scope.Notifications.Publish(new ExportedMemberNotification(member, model));
|
||||
|
||||
return model;
|
||||
}
|
||||
@@ -1187,6 +1153,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <param name="memberTypeId">Id of the MemberType</param>
|
||||
public void DeleteMembersOfType(int memberTypeId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
// note: no tree to manage here
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
@@ -1196,9 +1164,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
IQuery<IMember> query = Query<IMember>().Where(x => x.ContentTypeId == memberTypeId);
|
||||
|
||||
IMember[] members = _memberRepository.Get(query).ToArray();
|
||||
var deleteEventArgs = new DeleteEventArgs<IMember>(members);
|
||||
|
||||
if (scope.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
if (scope.Notifications.PublishCancelable(new DeletingNotification<IMember>(members, evtMsgs)))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
@@ -1208,7 +1175,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
{
|
||||
// delete media
|
||||
// triggers the deleted event (and handles the files)
|
||||
DeleteLocked(scope, member);
|
||||
DeleteLocked(scope, member, evtMsgs);
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -6,6 +6,7 @@ using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Infrastructure.Services.Notifications;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Implement
|
||||
@@ -129,8 +130,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
return OperationResult.Attempt.Succeed(evtMsgs, entry);
|
||||
}
|
||||
|
||||
var saveEventArgs = new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (scope.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
var savingNotifiation = new SavingNotification<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (scope.Notifications.PublishCancelable(savingNotifiation))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Attempt.Cancel(evtMsgs, entry);
|
||||
@@ -140,8 +141,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
scope.Complete();
|
||||
|
||||
saveEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
scope.Notifications.Publish(new SavedNotification<PublicAccessEntry>(entry, evtMsgs).WithStateFrom(savingNotifiation));
|
||||
}
|
||||
|
||||
return OperationResult.Attempt.Succeed(evtMsgs, entry);
|
||||
@@ -167,8 +167,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
entry.RemoveRule(existingRule);
|
||||
|
||||
var saveEventArgs = new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (scope.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
var savingNotifiation = new SavingNotification<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (scope.Notifications.PublishCancelable(savingNotifiation))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Attempt.Cancel(evtMsgs);
|
||||
@@ -177,8 +177,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
_publicAccessRepository.Save(entry);
|
||||
scope.Complete();
|
||||
|
||||
saveEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
scope.Notifications.Publish(new SavedNotification<PublicAccessEntry>(entry, evtMsgs).WithStateFrom(savingNotifiation));
|
||||
}
|
||||
|
||||
return OperationResult.Attempt.Succeed(evtMsgs);
|
||||
@@ -194,8 +193,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (scope.Events.DispatchCancelable(Saving, this, saveEventArgs))
|
||||
var savingNotifiation = new SavingNotification<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (scope.Notifications.PublishCancelable(savingNotifiation))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Attempt.Cancel(evtMsgs);
|
||||
@@ -204,8 +203,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
_publicAccessRepository.Save(entry);
|
||||
scope.Complete();
|
||||
|
||||
saveEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(Saved, this, saveEventArgs);
|
||||
scope.Notifications.Publish(new SavedNotification<PublicAccessEntry>(entry, evtMsgs).WithStateFrom(savingNotifiation));
|
||||
}
|
||||
|
||||
return OperationResult.Attempt.Succeed(evtMsgs);
|
||||
@@ -221,8 +219,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var deleteEventArgs = new DeleteEventArgs<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (scope.Events.DispatchCancelable(Deleting, this, deleteEventArgs))
|
||||
var deletingNotification = new DeletingNotification<PublicAccessEntry>(entry, evtMsgs);
|
||||
if (scope.Notifications.PublishCancelable(deletingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Attempt.Cancel(evtMsgs);
|
||||
@@ -231,33 +229,10 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
_publicAccessRepository.Delete(entry);
|
||||
scope.Complete();
|
||||
|
||||
deleteEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(Deleted, this, deleteEventArgs);
|
||||
scope.Notifications.Publish(new DeletedNotification<PublicAccessEntry>(entry, evtMsgs).WithStateFrom(deletingNotification));
|
||||
}
|
||||
|
||||
return OperationResult.Attempt.Succeed(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IPublicAccessService, SaveEventArgs<PublicAccessEntry>> Saving;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IPublicAccessService, SaveEventArgs<PublicAccessEntry>> Saved;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IPublicAccessService, DeleteEventArgs<PublicAccessEntry>> Deleting;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IPublicAccessService, DeleteEventArgs<PublicAccessEntry>> Deleted;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Globalization;
|
||||
@@ -14,6 +14,7 @@ using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Querying;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement;
|
||||
using Umbraco.Cms.Infrastructure.Services.Notifications;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services.Implement
|
||||
@@ -109,6 +110,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
if (username == null) throw new ArgumentNullException(nameof(username));
|
||||
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value can't be empty or consist only of white-space characters.", nameof(username));
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
// TODO: PUT lock here!!
|
||||
|
||||
User user;
|
||||
@@ -129,8 +132,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
IsApproved = isApproved
|
||||
};
|
||||
|
||||
var saveEventArgs = new SaveEventArgs<IUser>(user);
|
||||
if (scope.Events.DispatchCancelable(SavingUser, this, saveEventArgs))
|
||||
var savingNotification = new SavingNotification<IUser>(user, evtMsgs);
|
||||
if (scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return user;
|
||||
@@ -138,8 +141,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
_userRepository.Save(user);
|
||||
|
||||
saveEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(SavedUser, this, saveEventArgs);
|
||||
scope.Notifications.Publish(new SavedNotification<IUser>(user, evtMsgs).WithStateFrom(savingNotification));
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
@@ -239,10 +241,12 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
}
|
||||
else
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var deleteEventArgs = new DeleteEventArgs<IUser>(user);
|
||||
if (scope.Events.DispatchCancelable(DeletingUser, this, deleteEventArgs))
|
||||
var deletingNotification = new DeletingNotification<IUser>(user, evtMsgs);
|
||||
if (scope.Notifications.PublishCancelable(deletingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
@@ -250,8 +254,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
_userRepository.Delete(user);
|
||||
|
||||
deleteEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(DeletedUser, this, deleteEventArgs);
|
||||
scope.Notifications.Publish(new DeletedNotification<IUser>(user, evtMsgs).WithStateFrom(deletingNotification));
|
||||
scope.Complete();
|
||||
}
|
||||
}
|
||||
@@ -272,10 +275,12 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// Default is <c>True</c> otherwise set to <c>False</c> to not raise events</param>
|
||||
public void Save(IUser entity, bool raiseEvents = true)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<IUser>(entity);
|
||||
if (raiseEvents && scope.Events.DispatchCancelable(SavingUser, this, saveEventArgs))
|
||||
var savingNotification = new SavingNotification<IUser>(entity, evtMsgs);
|
||||
if (raiseEvents && scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
@@ -292,8 +297,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
_userRepository.Save(entity);
|
||||
if (raiseEvents)
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(SavedUser, this, saveEventArgs);
|
||||
scope.Notifications.Publish(new SavedNotification<IUser>(entity, evtMsgs).WithStateFrom(savingNotification));
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
@@ -319,12 +323,14 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// Default is <c>True</c> otherwise set to <c>False</c> to not raise events</param>
|
||||
public void Save(IEnumerable<IUser> entities, bool raiseEvents = true)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
var entitiesA = entities.ToArray();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<IUser>(entitiesA);
|
||||
if (raiseEvents && scope.Events.DispatchCancelable(SavingUser, this, saveEventArgs))
|
||||
var savingNotification = new SavingNotification<IUser>(entitiesA, evtMsgs);
|
||||
if (raiseEvents && scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
@@ -344,8 +350,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(SavedUser, this, saveEventArgs);
|
||||
scope.Notifications.Publish(new SavedNotification<IUser>(entitiesA, evtMsgs).WithStateFrom(savingNotification));
|
||||
}
|
||||
|
||||
//commit the whole lot in one go
|
||||
@@ -709,14 +714,16 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
if (entityIds.Length == 0)
|
||||
return;
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
_userGroupRepository.ReplaceGroupPermissions(groupId, permissions, entityIds);
|
||||
scope.Complete();
|
||||
|
||||
var assigned = permissions.Select(p => p.ToString(CultureInfo.InvariantCulture)).ToArray();
|
||||
scope.Events.Dispatch(UserGroupPermissionsAssigned, this,
|
||||
new SaveEventArgs<EntityPermission>(entityIds.Select(x => new EntityPermission(groupId, x, assigned)).ToArray(), false));
|
||||
var entityPermissions = entityIds.Select(x => new EntityPermission(groupId, x, assigned)).ToArray();
|
||||
scope.Notifications.Publish(new AssignedUserGroupPermissionsNotification(entityPermissions, evtMsgs));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,14 +738,16 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
if (entityIds.Length == 0)
|
||||
return;
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
_userGroupRepository.AssignGroupPermission(groupId, permission, entityIds);
|
||||
scope.Complete();
|
||||
|
||||
var assigned = new[] { permission.ToString(CultureInfo.InvariantCulture) };
|
||||
scope.Events.Dispatch(UserGroupPermissionsAssigned, this,
|
||||
new SaveEventArgs<EntityPermission>(entityIds.Select(x => new EntityPermission(groupId, x, assigned)).ToArray(), false));
|
||||
var entityPermissions = entityIds.Select(x => new EntityPermission(groupId, x, assigned)).ToArray();
|
||||
scope.Notifications.Publish(new AssignedUserGroupPermissionsNotification(entityPermissions, evtMsgs));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -809,6 +818,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// Default is <c>True</c> otherwise set to <c>False</c> to not raise events</param>
|
||||
public void Save(IUserGroup userGroup, int[] userIds = null, bool raiseEvents = true)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
// we need to figure out which users have been added / removed, for audit purposes
|
||||
@@ -826,9 +837,19 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
removedUsers = groupIds.Except(userIds).Select(x => xGroupUsers[x]).Where(x => x.Id != 0).ToArray();
|
||||
}
|
||||
|
||||
var saveEventArgs = new SaveEventArgs<UserGroupWithUsers>(new UserGroupWithUsers(userGroup, addedUsers, removedUsers));
|
||||
var userGroupWithUsers = new UserGroupWithUsers(userGroup, addedUsers, removedUsers);
|
||||
|
||||
if (raiseEvents && scope.Events.DispatchCancelable(SavingUserGroup, this, saveEventArgs))
|
||||
// this is the default/expected notification for the IUserGroup entity being saved
|
||||
var savingNotification = new SavingNotification<IUserGroup>(userGroup, evtMsgs);
|
||||
if (raiseEvents && scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
}
|
||||
|
||||
// this is an additional notification for special auditing
|
||||
var savingUserGroupWithUsersNotification = new SavingNotification<UserGroupWithUsers>(userGroupWithUsers, evtMsgs);
|
||||
if (raiseEvents && scope.Notifications.PublishCancelable(savingUserGroupWithUsersNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
@@ -838,8 +859,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(SavedUserGroup, this, saveEventArgs);
|
||||
scope.Notifications.Publish(new SavedNotification<IUserGroup>(userGroup, evtMsgs).WithStateFrom(savingNotification));
|
||||
scope.Notifications.Publish(new SavedNotification<UserGroupWithUsers>(userGroupWithUsers, evtMsgs).WithStateFrom(savingUserGroupWithUsersNotification));
|
||||
}
|
||||
|
||||
scope.Complete();
|
||||
@@ -852,10 +873,12 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <param name="userGroup">UserGroup to delete</param>
|
||||
public void DeleteUserGroup(IUserGroup userGroup)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var deleteEventArgs = new DeleteEventArgs<IUserGroup>(userGroup);
|
||||
if (scope.Events.DispatchCancelable(DeletingUserGroup, this, deleteEventArgs))
|
||||
var deletingNotification = new DeletingNotification<IUserGroup>(userGroup, evtMsgs);
|
||||
if (scope.Notifications.PublishCancelable(deletingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
@@ -863,8 +886,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
_userGroupRepository.Delete(userGroup);
|
||||
|
||||
deleteEventArgs.CanCancel = false;
|
||||
scope.Events.Dispatch(DeletedUserGroup, this, deleteEventArgs);
|
||||
scope.Notifications.Publish(new DeletedNotification<IUserGroup>(userGroup, evtMsgs).WithStateFrom(deletingNotification));
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
@@ -1144,49 +1166,5 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IUserService, SaveEventArgs<IUser>> SavingUser;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IUserService, SaveEventArgs<IUser>> SavedUser;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUser>> DeletingUser;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUser>> DeletedUser;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IUserService, SaveEventArgs<UserGroupWithUsers>> SavingUserGroup;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IUserService, SaveEventArgs<UserGroupWithUsers>> SavedUserGroup;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUserGroup>> DeletingUserGroup;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IUserService, DeleteEventArgs<IUserGroup>> DeletedUserGroup;
|
||||
|
||||
// TODO: still don't know if we need this yet unless we start caching permissions, but that also means we'll need another
|
||||
// event on the ContentService since there's a method there to modify node permissions too, or we can proxy events if needed.
|
||||
public static event TypedEventHandler<IUserService, SaveEventArgs<EntityPermission>> UserGroupPermissionsAssigned;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Cms.Infrastructure.Services.Notifications
|
||||
{
|
||||
public class AssignedMemberRolesNotification : MemberRolesNotification
|
||||
{
|
||||
public AssignedMemberRolesNotification(int[] memberIds, string[] roles) : base(memberIds, roles)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Services.Notifications
|
||||
{
|
||||
public class AssignedUserGroupPermissionsNotification : EnumerableObjectNotification<EntityPermission>
|
||||
{
|
||||
public AssignedUserGroupPermissionsNotification(IEnumerable<EntityPermission> target, EventMessages messages) : base(target, messages)
|
||||
{
|
||||
}
|
||||
|
||||
public IEnumerable<EntityPermission> EntityPermissions => Target;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Services.Notifications
|
||||
{
|
||||
public class ExportedMemberNotification : INotification
|
||||
{
|
||||
public ExportedMemberNotification(IMember member, MemberExportModel exported)
|
||||
{
|
||||
Member = member;
|
||||
Exported = exported;
|
||||
}
|
||||
|
||||
public IMember Member { get; }
|
||||
|
||||
public MemberExportModel Exported { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Umbraco.Cms.Core.Events;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Services.Notifications
|
||||
{
|
||||
public abstract class MemberRolesNotification : INotification
|
||||
{
|
||||
protected MemberRolesNotification(int[] memberIds, string[] roles)
|
||||
{
|
||||
MemberIds = memberIds;
|
||||
Roles = roles;
|
||||
}
|
||||
|
||||
public int[] MemberIds { get; }
|
||||
|
||||
public string[] Roles { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Cms.Infrastructure.Services.Notifications
|
||||
{
|
||||
public class RemovedMemberRolesNotification : MemberRolesNotification
|
||||
{
|
||||
public RemovedMemberRolesNotification(int[] memberIds, string[] roles) : base(memberIds, roles)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user