mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 07:13:12 +00:00
fix(team-members): do not report an invite email for a deactivated member
This commit is contained in:
parent
afc2330184
commit
cc328ce22a
3 changed files with 24 additions and 7 deletions
|
|
@ -89,13 +89,13 @@ public sealed class TeamMemberInviteService : ITeamMemberInviteService
|
||||||
if (user.IsDeleted == true || user.PendingRegistration != true || string.IsNullOrWhiteSpace(user.Email))
|
if (user.IsDeleted == true || user.PendingRegistration != true || string.IsNullOrWhiteSpace(user.Email))
|
||||||
return ResendFailure("Only pending team members can be re-invited.");
|
return ResendFailure("Only pending team members can be re-invited.");
|
||||||
|
|
||||||
if (!await ReissueAsync(user, cancellationToken))
|
if (await ReissueAsync(user, cancellationToken) != true)
|
||||||
return ResendFailure("The invite could not be emailed. Try again.");
|
return ResendFailure("The invite could not be emailed. Try again.");
|
||||||
|
|
||||||
return new TeamMemberInviteResendOutcomeDTO { Success = true };
|
return new TeamMemberInviteResendOutcomeDTO { Success = true };
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ReissueAsync(ApplicationUser user, CancellationToken cancellationToken)
|
public async Task<bool?> ReissueAsync(ApplicationUser user, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(user);
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
ArgumentException.ThrowIfNullOrWhiteSpace(user.Email);
|
ArgumentException.ThrowIfNullOrWhiteSpace(user.Email);
|
||||||
|
|
@ -105,7 +105,7 @@ public sealed class TeamMemberInviteService : ITeamMemberInviteService
|
||||||
|
|
||||||
// A deactivated member cannot register; the admin re-sends the invite after reactivating them.
|
// A deactivated member cannot register; the admin re-sends the invite after reactivating them.
|
||||||
if (user.IsDeleted == true)
|
if (user.IsDeleted == true)
|
||||||
return true;
|
return null;
|
||||||
|
|
||||||
var name = $"{user.FirstName ?? ""} {user.LastName ?? ""}".Trim();
|
var name = $"{user.FirstName ?? ""} {user.LastName ?? ""}".Trim();
|
||||||
return await SendAsync(issued, user.Email, name, cancellationToken);
|
return await SendAsync(issued, user.Email, name, cancellationToken);
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ public interface ITeamMemberInviteService
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Revokes the member's open invites, including any email confirmation made through them,
|
/// Revokes the member's open invites, including any email confirmation made through them,
|
||||||
/// and emails a new invite to their current address unless they are deactivated.
|
/// and emails a new invite to their current address unless they are deactivated.
|
||||||
/// Returns false when that email failed.
|
/// Returns whether that email went out, or null when the member is deactivated and nothing was emailed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task<bool> ReissueAsync(ApplicationUser user, CancellationToken cancellationToken);
|
Task<bool?> ReissueAsync(ApplicationUser user, CancellationToken cancellationToken);
|
||||||
|
|
||||||
/// <summary>Admin-only: revokes a pending member's open invites and emails a new one.</summary>
|
/// <summary>Admin-only: revokes a pending member's open invites and emails a new one.</summary>
|
||||||
Task<TeamMemberInviteResendOutcomeDTO> ResendAsync(
|
Task<TeamMemberInviteResendOutcomeDTO> ResendAsync(
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,21 @@ public sealed class TeamMemberInviteLifecycleTests
|
||||||
Assert.False(updated.Member.InviteEmailSent);
|
Assert.False(updated.Member.InviteEmailSent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DeactivatingAPendingMemberWhileChangingTheirEmail_RevokesTheInviteWithoutClaimingAnEmail()
|
||||||
|
{
|
||||||
|
await using var host = await TeamMemberInviteTestHost.CreateAsync();
|
||||||
|
var (userId, oldToken) = await host.AddPendingMemberAsync(Email);
|
||||||
|
|
||||||
|
var updated = await UpdateAsync(host, userId, CorrectedEmail, role: "dispatcher", isActive: false);
|
||||||
|
|
||||||
|
Assert.True(updated.Success, updated.Error);
|
||||||
|
Assert.Null(updated.Member!.InviteEmailSent);
|
||||||
|
Assert.DoesNotContain(host.Sent.Messages, message => message.To == CorrectedEmail);
|
||||||
|
Assert.Equal(TeamMemberRegistrationStatus.InvalidInvite,
|
||||||
|
(await host.RegistrationAsync(service => service.ResolveAsync(oldToken, CancellationToken.None))).Status);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task EditingAPendingMemberWithoutChangingTheirEmail_KeepsTheirInvite()
|
public async Task EditingAPendingMemberWithoutChangingTheirEmail_KeepsTheirInvite()
|
||||||
{
|
{
|
||||||
|
|
@ -96,7 +111,8 @@ public sealed class TeamMemberInviteLifecycleTests
|
||||||
TeamMemberInviteTestHost host,
|
TeamMemberInviteTestHost host,
|
||||||
string userId,
|
string userId,
|
||||||
string email,
|
string email,
|
||||||
string role) =>
|
string role,
|
||||||
|
bool isActive = true) =>
|
||||||
host.InScopeAsync(provider => provider.GetRequiredService<ITeamMemberService>().UpdateAsync(
|
host.InScopeAsync(provider => provider.GetRequiredService<ITeamMemberService>().UpdateAsync(
|
||||||
userId,
|
userId,
|
||||||
new UpdateTeamMemberRequestDTO
|
new UpdateTeamMemberRequestDTO
|
||||||
|
|
@ -106,7 +122,8 @@ public sealed class TeamMemberInviteLifecycleTests
|
||||||
Color = "#0D9488",
|
Color = "#0D9488",
|
||||||
Email = email,
|
Email = email,
|
||||||
Phone = "555-0100",
|
Phone = "555-0100",
|
||||||
ServiceAreas = role == "dispatcher" ? new[] { "East" } : Array.Empty<string>()
|
ServiceAreas = role == "dispatcher" ? new[] { "East" } : Array.Empty<string>(),
|
||||||
|
IsActive = isActive
|
||||||
},
|
},
|
||||||
TeamMemberInviteTestHost.Admin(),
|
TeamMemberInviteTestHost.Admin(),
|
||||||
CancellationToken.None));
|
CancellationToken.None));
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue