/****************************************************************************** // MARECHAI: Master repository of computing history artifacts information // ---------------------------------------------------------------------------- // // Author(s) : Natalia Portillo // // --[ License ] -------------------------------------------------------------- // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // ---------------------------------------------------------------------------- // Copyright © 2003-2026 Natalia Portillo *******************************************************************************/ using System; using System.ComponentModel.DataAnnotations; namespace Marechai.Database.Models; /// /// Single-use registration invitation. The string (length 9, format /// XXXX-YYYY using a 32-char unambiguous alphabet) is the primary key. A code is consumed by setting /// + in the same transaction that creates the user, with /// acting as the optimistic concurrency token (rotated on consume) so that two /// simultaneous registration attempts using the same code can never both succeed. /// public class InvitationCode { [Key] [Required] [StringLength(9, MinimumLength = 9)] public string Code { get; set; } [Required] public string CreatedById { get; set; } [Required] public DateTime CreatedOn { get; set; } public string UsedById { get; set; } public DateTime? UsedOn { get; set; } /// /// Optimistic concurrency token. MariaDB has no native rowversion type so we store a /// and configure it as IsConcurrencyToken; the consumer must rotate this value in the same UPDATE /// that sets . /// [ConcurrencyCheck] public Guid RowVersion { get; set; } = Guid.NewGuid(); public virtual ApplicationUser CreatedBy { get; set; } public virtual ApplicationUser UsedBy { get; set; } }