Add init link.
This commit is contained in:
@@ -48,6 +48,8 @@ public static class AuditActions
|
||||
public const string PasswordChanged = "PasswordChanged";
|
||||
public const string UserDeactivated = "UserDeactivated";
|
||||
public const string PermissionChanged = "PermissionChanged";
|
||||
public const string InvitationCreated = "InvitationCreated";
|
||||
public const string InvitationAccepted = "InvitationAccepted";
|
||||
public const string CheckIssued = "CheckIssued";
|
||||
public const string CheckVoided = "CheckVoided";
|
||||
public const string ExpenseApproved = "ExpenseApproved";
|
||||
@@ -56,7 +58,8 @@ public static class AuditActions
|
||||
public static readonly IReadOnlyList<string> All =
|
||||
[
|
||||
Create, Update, Delete, Login, Logout, LoginFailed, RoleChanged,
|
||||
PasswordChanged, UserDeactivated, PermissionChanged, CheckIssued,
|
||||
PasswordChanged, UserDeactivated, PermissionChanged,
|
||||
InvitationCreated, InvitationAccepted, CheckIssued,
|
||||
CheckVoided, ExpenseApproved, StatementFinalized,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace ROLAC.API.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// A single-use, expiring invitation that lets a member set their own password and log in for
|
||||
/// the first time — without an admin-generated temporary password. The raw token is e-mailed /
|
||||
/// copied to the member; only its SHA-256 hash is stored here (same scheme as RefreshToken).
|
||||
/// </summary>
|
||||
public class UserInvitation
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string UserId { get; set; } = null!;
|
||||
public AppUser User { get; set; } = null!;
|
||||
|
||||
/// <summary>SHA-256 hex of the raw invitation token. Never store raw tokens.</summary>
|
||||
public string TokenHash { get; set; } = null!;
|
||||
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
|
||||
/// <summary>Id of the admin who generated the link.</summary>
|
||||
public string CreatedBy { get; set; } = null!;
|
||||
|
||||
/// <summary>Set when the member consumes the link to set their password (single-use).</summary>
|
||||
public DateTime? UsedAt { get; set; }
|
||||
|
||||
/// <summary>Set when superseded by a newer invitation for the same user (re-issue).</summary>
|
||||
public DateTime? RevokedAt { get; set; }
|
||||
|
||||
// Computed helpers — NOT mapped to DB columns (ignored in OnModelCreating)
|
||||
public bool IsExpired => DateTime.UtcNow >= ExpiresAt;
|
||||
public bool IsUsed => UsedAt.HasValue;
|
||||
public bool IsRevoked => RevokedAt.HasValue;
|
||||
public bool IsActive => !IsUsed && !IsRevoked && !IsExpired;
|
||||
}
|
||||
Reference in New Issue
Block a user