Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/Umbraco.Core/Models/PublishNotificationSaveOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace Umbraco.Cms.Core.Models;

/// <summary>
/// Specifies options for publishing notifcations when saving.
/// </summary>
[Flags]
public enum PublishNotificationSaveOptions
{
/// <summary>
/// Do not publish any notifications.
/// </summary>
None = 0,

/// <summary>
/// Only publish the saving notification.
/// </summary>
Saving = 1,

/// <summary>
/// Only publish the saved notification.
/// </summary>
Saved = 2,

/// <summary>
/// Publish all the notifications.
/// </summary>
All = Saving | Saved,
}
8 changes: 8 additions & 0 deletions src/Umbraco.Core/Services/IMembershipMemberService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,14 @@ public interface IMembershipMemberService<T> : IService
/// <param name="entity"><see cref="IMember" /> or <see cref="IUser" /> to Save</param>
void Save(T entity);

/// <summary>
/// Saves an <see cref="IMembershipUser" />
/// </summary>
/// <remarks>An <see cref="IMembershipUser" /> can be of type <see cref="IMember" /> or <see cref="IUser" /></remarks>
/// <param name="entity"><see cref="IMember" /> or <see cref="IUser" /> to Save</param>
/// <param name="publishNotificationSaveOptions"> Enum for deciding which notifications to publish.</param>
void Save(T entity, PublishNotificationSaveOptions publishNotificationSaveOptions) => Save(entity);

/// <summary>
/// Saves a list of <see cref="IMembershipUser" /> objects
/// </summary>
Expand Down
24 changes: 18 additions & 6 deletions src/Umbraco.Core/Services/MemberService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Microsoft.Extensions.Logging;

Check notice on line 1 in src/Umbraco.Core/Services/MemberService.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v13/dev)

✅ Getting better: Primitive Obsession

The ratio of primitive types in function arguments decreases from 79.55% to 78.65%, threshold = 30.0%. The functions in this file have too many primitive types (e.g. int, double, float) in their function argument lists. Using many primitive types lead to the code smell Primitive Obsession. Avoid adding more primitive arguments.

Check notice on line 1 in src/Umbraco.Core/Services/MemberService.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v13/dev)

✅ Getting better: String Heavy Function Arguments

The ratio of strings in function arguments decreases from 53.41% to 52.81%, threshold = 39.0%. The functions in this file have a high ratio of strings as arguments. Avoid adding more.
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
Expand Down Expand Up @@ -736,7 +736,9 @@
public void SetLastLogin(string username, DateTime date) => throw new NotImplementedException();

/// <inheritdoc />
public void Save(IMember member)
public void Save(IMember member) => Save(member, PublishNotificationSaveOptions.All);

public void Save(IMember member, PublishNotificationSaveOptions publishNotificationSaveOptions)
{
// trimming username and email to make sure we have no trailing space
member.Username = member.Username.Trim();
Expand All @@ -745,11 +747,15 @@
EventMessages evtMsgs = EventMessagesFactory.Get();

using ICoreScope scope = ScopeProvider.CreateCoreScope();
var savingNotification = new MemberSavingNotification(member, evtMsgs);
if (scope.Notifications.PublishCancelable(savingNotification))
MemberSavingNotification? savingNotification = null;
if (publishNotificationSaveOptions.HasFlag(PublishNotificationSaveOptions.Saving))
{
scope.Complete();
return;
savingNotification = new MemberSavingNotification(member, evtMsgs);
if (scope.Notifications.PublishCancelable(savingNotification))
{
scope.Complete();
return;
}
}

if (string.IsNullOrWhiteSpace(member.Name))
Expand All @@ -761,7 +767,13 @@

_memberRepository.Save(member);

scope.Notifications.Publish(new MemberSavedNotification(member, evtMsgs).WithStateFrom(savingNotification));
if (publishNotificationSaveOptions.HasFlag(PublishNotificationSaveOptions.Saved))
{
scope.Notifications.Publish(
savingNotification is null
? new MemberSavedNotification(member, evtMsgs)
: new MemberSavedNotification(member, evtMsgs).WithStateFrom(savingNotification));
}

Audit(AuditType.Save, 0, member.Id);

Expand Down
2 changes: 1 addition & 1 deletion src/Umbraco.Infrastructure/Security/MemberUserStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public override Task<IdentityResult> CreateAsync(
UpdateMemberProperties(memberEntity, user, out bool _);

// create the member
_memberService.Save(memberEntity);
_memberService.Save(memberEntity, PublishNotificationSaveOptions.Saving);

// We need to add roles now that the member has an Id. It do not work implicit in UpdateMemberProperties
_memberService.AssignRoles(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public async Task GivenICreateANewUser_AndTheUserIsPopulatedCorrectly_ThenIShoul
_mockMemberService
.Setup(x => x.CreateMember(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
.Returns(mockMember);
_mockMemberService.Setup(x => x.Save(mockMember));
_mockMemberService.Setup(x => x.Save(mockMember, PublishNotificationSaveOptions.Saving));

// act
var identityResult = await sut.CreateAsync(fakeUser, CancellationToken.None);
Expand All @@ -132,7 +132,7 @@ public async Task GivenICreateANewUser_AndTheUserIsPopulatedCorrectly_ThenIShoul
Assert.IsTrue(!identityResult.Errors.Any());
_mockMemberService.Verify(x =>
x.CreateMember(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()));
_mockMemberService.Verify(x => x.Save(mockMember));
_mockMemberService.Verify(x => x.Save(mockMember, PublishNotificationSaveOptions.Saving));
}

[Test]
Expand Down
Loading