SHA256
Compare commits
3
Commits
26f77bb8fd
...
9f44ff6e3d
| Author | SHA256 | Date | |
|---|---|---|---|
|
|
9f44ff6e3d | ||
|
|
76b2695c02 | ||
|
|
86fadf97b4 |
@@ -6,6 +6,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Extensions.MudBlazor.StaticInput" Version="4.1.0" />
|
||||
<PackageVersion Include="FluentValidation" Version="12.1.1" />
|
||||
<PackageVersion Include="Grpc.AspNetCore" Version="2.64.0" />
|
||||
<PackageVersion Include="MudBlazor" Version="9.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
@using Somnia.GuestLog.Models.DTOs
|
||||
|
||||
<MudDialog>
|
||||
<TitleContent>
|
||||
GuestDocument Details
|
||||
</TitleContent>
|
||||
<DialogContent>
|
||||
<GuestDocForm Model="@DocumentDTO" ReadOnly=true />
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<MudButton Color="Color.Primary" Variant="Variant.Filled" EndIcon="@Icons.Material.Filled.Close"
|
||||
OnClick="Submit">
|
||||
Close
|
||||
</MudButton>
|
||||
</DialogActions>
|
||||
</MudDialog>
|
||||
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
[Parameter]
|
||||
public GuestDocumentDTO DocumentDTO { get; set; } = new();
|
||||
|
||||
private void Submit() => MudDialog.Close(DialogResult.Ok(true));
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
@using Somnia.GuestLog.Models.DTOs;
|
||||
@using Somnia.GuestLog.Validators;
|
||||
|
||||
<MudForm @ref="@_form" Model="@Model" Validation="@(guestDocValidator.ValidateValue)" ValidationDelay="0"
|
||||
ReadOnly="@ReadOnly">
|
||||
<MudGrid>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-4" Elevation="3" Height="100%">
|
||||
<MudText Typo="Typo.subtitle1" Align="Align.Center">Document Details</MudText>
|
||||
<MudDivider DividerType="DividerType.Middle" Class="mb-4" />
|
||||
<MudStack Row>
|
||||
<MudSelect @bind-Value="Model.DocumentType" For="@(() => Model.DocumentType)" Label="DocumentType"
|
||||
Required>
|
||||
@foreach (string docType in GuestConsts.DocumentTypeList)
|
||||
{
|
||||
<MudSelectItem Value="docType">@docType</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField @bind-Value="Model.DocumentNum" For="@(() => Model.DocumentNum)" Label="Document Num"
|
||||
Immediate="true" Required />
|
||||
</MudStack>
|
||||
|
||||
<MudStack Row>
|
||||
<MudDatePicker @bind-Date="Model.IssueDate" For="@(() => Model.IssueDate)" Label="Issue Date"
|
||||
Clearable OpenTo="OpenTo.Year" Editable />
|
||||
|
||||
<MudTextField @bind-Value="Model.SupportNum" For="@(() => Model.SupportNum)" Label="Support Num"
|
||||
Immediate="true" Required="@isSuportNumberRequired" />
|
||||
</MudStack>
|
||||
|
||||
<MudSelect @bind-Value="Model.Nationality" For="@(() => Model.Nationality)" Label="Nationality">
|
||||
@foreach (var countryPair in GuestConsts.CountryList)
|
||||
{
|
||||
<MudSelectItem Value="countryPair.Key">@countryPair.Value</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-4" Elevation="3" Height="100%">
|
||||
<MudText Typo="Typo.subtitle1" Align="Align.Center">Customer Details</MudText>
|
||||
<MudDivider DividerType="DividerType.Middle" Class="mb-4" />
|
||||
|
||||
<MudTextField @bind-Value="Model.Name" For="@(() => Model.Name)" Immediate="true" Label="Name" />
|
||||
<MudTextField @bind-Value="Model.Surname" For="@(() => Model.Surname)" Immediate="true"
|
||||
Label="Surname" />
|
||||
<MudTextField @bind-Value="Model.Surname2" For="@(() => Model.Surname2)" Immediate="true"
|
||||
Label="Surname2" />
|
||||
|
||||
<MudStack Row>
|
||||
<MudDatePicker @bind-Date="Model.BirthDate" For="@(() => Model.BirthDate)" Label="BirthDate"
|
||||
Clearable OpenTo="OpenTo.Year" Editable />
|
||||
|
||||
<MudSelect @bind-Value="Model.Gender" For="@(() => Model.Gender)" Label="Gender">
|
||||
@foreach (var genderPair in GuestConsts.GenderList)
|
||||
{
|
||||
<MudSelectItem Value="genderPair.Key">@genderPair.Value</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-4" Elevation="3" Height="100%">
|
||||
<MudText Typo="Typo.subtitle1" Align="Align.Center">Contact Details</MudText>
|
||||
<MudDivider DividerType="DividerType.Middle" Class="mb-4" />
|
||||
|
||||
<MudStack Row>
|
||||
<MudTextField @bind-Value="Model.PhoneNumber" For="@(() => Model.PhoneNumber)" Immediate="true"
|
||||
Label="Phone Number" />
|
||||
<MudTextField @bind-Value="Model.EmailAddress" For="@(() => Model.EmailAddress)" Immediate="true"
|
||||
Label="Email" />
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="12" md="6">
|
||||
<MudPaper Class="pa-4" Elevation="3" Height="100%">
|
||||
<MudText Typo="Typo.subtitle1" Align="Align.Center">Address</MudText>
|
||||
<MudDivider DividerType="DividerType.Middle" Class="mb-4" />
|
||||
|
||||
<MudTextField @bind-Value="Model.Address" For="@(() => Model.Address)" Immediate="true" Label="Address" />
|
||||
<MudStack Row>
|
||||
<MudTextField @bind-Value="Model.AddressCity" For="@(() => Model.AddressCity)" Immediate="true"
|
||||
Label="City" />
|
||||
<MudTextField @bind-Value="Model.AddressProvince" For="@(() => Model.AddressProvince)" Immediate="true"
|
||||
Label="Province" />
|
||||
<MudTextField @bind-Value="Model.AddressState" For="@(() => Model.AddressState)" Immediate="true"
|
||||
Label="State" />
|
||||
</MudStack>
|
||||
<MudStack Row>
|
||||
<MudSelect @bind-Value="Model.AddressCountry" For="@(() => Model.AddressCountry)" Label="Country">
|
||||
@foreach (var countryPair in GuestConsts.CountryList)
|
||||
{
|
||||
<MudSelectItem Value="countryPair.Key">@countryPair.Value</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField @bind-Value="Model.ZipCode" For="@(() => Model.ZipCode)" Immediate="true"
|
||||
Label="ZipCode" />
|
||||
</MudStack>
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
<MudText Class="mt-4">@CreateTimeString</MudText>
|
||||
</MudForm>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public GuestDocumentDTO Model { get; set; } = new();
|
||||
|
||||
[Parameter]
|
||||
public bool ReadOnly { get; set; } = false;
|
||||
|
||||
|
||||
private MudForm _form = null!;
|
||||
private readonly GuestDocumentDTOValidator guestDocValidator = new();
|
||||
|
||||
private bool isSuportNumberRequired { get => Model?.Nationality == "ESP"; }
|
||||
private string CreateTimeString
|
||||
{
|
||||
get
|
||||
{
|
||||
List<string> textList = [];
|
||||
if (Model.CreateTime != null)
|
||||
{
|
||||
textList.Add($"Created at: {Model.CreateTime.Value.ToString()}");
|
||||
}
|
||||
if (Model.UpdateTime != null)
|
||||
{
|
||||
textList.Add($"Last Update Time: {Model.UpdateTime.Value.ToString()}");
|
||||
}
|
||||
return string.Join("; ", textList);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> ValidateForm()
|
||||
{
|
||||
await _form.ValidateAsync();
|
||||
return _form.IsValid;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<MudDialog>
|
||||
<TitleContent>
|
||||
<MudText Typo="Typo.subtitle1" Align="Align.Center">In progress...</MudText>
|
||||
</TitleContent>
|
||||
<DialogContent>
|
||||
<div class="d-flex flex-grow-1 flex-wrap justify-center align-center ma-8">
|
||||
<MudProgressCircular Indeterminate="true" Color="Color.Primary" Size="Size.Large"/>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</MudDialog>
|
||||
|
||||
@code {
|
||||
[CascadingParameter]
|
||||
private IMudDialogInstance MudDialog { get; set; } = null!;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
var updatedOptions = MudDialog.Options with
|
||||
{
|
||||
BackdropClick = false,
|
||||
CloseButton = false,
|
||||
CloseOnEscapeKey = false,
|
||||
CloseOnNavigation = true,
|
||||
FullWidth = true,
|
||||
};
|
||||
await MudDialog.SetOptionsAsync(updatedOptions);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
<MudAppBar Elevation="1" Style="opacity: 100%;">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start"
|
||||
OnClick="@((e) => DrawerToggle())" />
|
||||
<MudText Typo="Typo.h5" Class="ml-3">Somnia GuestLog</MudText>
|
||||
<MudText Typo="Typo.h5" Class="ml-3">Somnia.GuestLog</MudText>
|
||||
<MudSpacer />
|
||||
<MudToggleIconButton Class="ml-auto" Icon="@Icons.Material.Outlined.LightMode"
|
||||
ToggledIcon="@Icons.Material.Outlined.DarkMode" ToggledColor="Color.Primary" Color="Color.Primary"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
<MudNavLink Href="weather" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.List">Weather</MudNavLink>
|
||||
|
||||
<MudNavLink Href="@GuestConsts.Page_GuestDocs_List" Match="NavLinkMatch.Prefix" Icon="@Icons.Material.Filled.DocumentScanner">Guests</MudNavLink>
|
||||
</MudNavMenu>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
@attribute [Route($"{GuestConsts.Page_GuestDocs_List}")]
|
||||
|
||||
@using Somnia.GuestLog.Models.DTOs;
|
||||
@using Somnia.GuestLog.Services;
|
||||
|
||||
@inject IGuestDocumentService GuestDocService
|
||||
@inject NavigationManager Navigation
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IDialogService DialogService
|
||||
|
||||
|
||||
<PageTitle>Somnia - Guest Docs</PageTitle>
|
||||
|
||||
<MudStack Row="true" Class="my-4">
|
||||
<MudText Typo="Typo.h4" GutterBottom="true">Guest Documents</MudText>
|
||||
<MudSpacer />
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Success" Size="Size.Small" StartIcon="@Icons.Material.Filled.Add"
|
||||
OnClick="() => BtnNewGuest()">
|
||||
New Guest
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<MudSelect T="string" MultiSelection="true" FullWidth="true" Dense="true" Clearable="true" Margin="@Margin.Dense"
|
||||
Class="filter-input category-filter" Label="Module" Placeholder="Select Modules"
|
||||
SelectedValuesChanged="@FilterModuleValuesChanged">
|
||||
@foreach (var module in _moduleList)
|
||||
{
|
||||
<MudSelectItem T="string" Value="@module">@module</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
||||
<MudDataGrid @ref="_dataGrid" T="GuestDocumentDTO" Items="@guestDocList" Loading="@_dataLoading" ReadOnly="true"
|
||||
Hideable="true" ColumnsPanelReordering="true">
|
||||
<ToolBarContent>
|
||||
<MudText Typo="Typo.subtitle1">Document List</MudText>
|
||||
<MudStack Class="ml-auto" Row="true" AlignItems="AlignItems.End">
|
||||
<MudButton StartIcon="@Icons.Material.Outlined.Refresh" Variant="Variant.Outlined" Size="Size.Small"
|
||||
OnClick="() => LoadDataAsync()">
|
||||
Reload Data
|
||||
</MudButton>
|
||||
<MudButton StartIcon="@Icons.Material.Outlined.ViewColumn" Variant="Variant.Outlined" Size="Size.Small"
|
||||
OnClick="(args) => BtnConfigureColumnsClick(args)">
|
||||
Configure Columns
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
</ToolBarContent>
|
||||
<Columns>
|
||||
<PropertyColumn Property="x => x.DocumentType" Hideable="false" />
|
||||
<PropertyColumn Property="x => x.DocumentNum" Hideable="false" />
|
||||
<PropertyColumn Property="x => x.Name" />
|
||||
<PropertyColumn Property="x => x.Surname" />
|
||||
<PropertyColumn Property="x => x.Nationality" />
|
||||
<PropertyColumn Property="x => x.UpdateTime" />
|
||||
|
||||
<TemplateColumn CellClass="d-flex justify-between" Title="Options" StickyRight Hideable="false"
|
||||
ShowColumnOptions="false">
|
||||
<CellTemplate>
|
||||
<MudIconButton Size="@Size.Small" Icon="@Icons.Material.Outlined.Info"
|
||||
OnClick="() => BtnViewDetails(context.Item)" />
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
</Columns>
|
||||
</MudDataGrid>
|
||||
|
||||
|
||||
@code {
|
||||
private IEnumerable<GuestDocumentDTO> guestDocList = [];
|
||||
|
||||
private bool _dataLoading = true;
|
||||
private HashSet<string> _moduleList = [];
|
||||
private HashSet<string> _selectedModuleList = [];
|
||||
|
||||
private MudDataGrid<GuestDocumentDTO>? _dataGrid;
|
||||
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await LoadDataAsync(showMsg: false);
|
||||
|
||||
@* _moduleList = guestDocList.Select(e => e.Module).ToHashSet(); *@
|
||||
}
|
||||
|
||||
#region Data Loading
|
||||
|
||||
private async Task LoadDataAsync(bool showMsg = true)
|
||||
{
|
||||
_dataLoading = true;
|
||||
|
||||
guestDocList = await GuestDocService.GetDtoListAsync();
|
||||
|
||||
if (showMsg)
|
||||
{
|
||||
Snackbar.Add("Data loaded from DB", Severity.Info, o => o.VisibleStateDuration = 1000);
|
||||
}
|
||||
_dataLoading = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private async Task FilterModuleValuesChanged(IReadOnlyCollection<string> newValues)
|
||||
{
|
||||
_selectedModuleList = [.. newValues];
|
||||
|
||||
await LoadDataAsync();
|
||||
}
|
||||
|
||||
private async Task BtnConfigureColumnsClick(MouseEventArgs args)
|
||||
{
|
||||
if (_dataGrid is null)
|
||||
{
|
||||
Snackbar.Add("No ref to grid");
|
||||
return;
|
||||
}
|
||||
_dataGrid.ShowColumnsPanel(args);
|
||||
}
|
||||
|
||||
private async Task BtnViewDetails(GuestDocumentDTO item)
|
||||
{
|
||||
var parameters =
|
||||
new DialogParameters<GuestDocDetailsDialog> { { x => x.DocumentDTO, item } };
|
||||
var options = new DialogOptions()
|
||||
{
|
||||
FullScreen = true,
|
||||
CloseButton = true,
|
||||
CloseOnEscapeKey = true,
|
||||
};
|
||||
|
||||
await DialogService.ShowAsync<GuestDocDetailsDialog>("GuestDoc Details", parameters, options);
|
||||
}
|
||||
|
||||
private void BtnNewGuest()
|
||||
{
|
||||
Navigation.NavigateTo(GuestConsts.Page_GuestDocs_New);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
@attribute [Route($"{GuestConsts.Page_GuestDocs_New}")]
|
||||
|
||||
@using Microsoft.EntityFrameworkCore;
|
||||
@using Somnia.GuestLog.Models.DTOs;
|
||||
@using Somnia.GuestLog.Infrastructure;
|
||||
@using Somnia.GuestLog.Services;
|
||||
|
||||
@inject IDbContextFactory<GuestLogContext> contextFactory
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IDialogService DialogService
|
||||
@inject NavigationManager Navigation
|
||||
@inject IGuestDocumentService guestDocService
|
||||
|
||||
|
||||
<PageTitle>Somnia - Guest Docs - New</PageTitle>
|
||||
|
||||
<MudStack Row="true" Class="my-4">
|
||||
<MudText Typo="Typo.h4" GutterBottom="true">New Guest Document</MudText>
|
||||
<MudSpacer />
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Success" Size="Size.Small" StartIcon="@Icons.Material.Filled.Add"
|
||||
OnClick="() => BtnSaveNewGuest()">
|
||||
Create
|
||||
</MudButton>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Default" Size="Size.Small"
|
||||
StartIcon="@Icons.Material.Filled.ArrowBack" OnClick="() => BtnReturn()">
|
||||
Return
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<GuestDocForm @ref="_form" />
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
GuestDocForm _form = null!;
|
||||
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
private void BtnReturn()
|
||||
{
|
||||
Navigation.NavigateTo(GuestConsts.Page_GuestDocs_List);
|
||||
}
|
||||
|
||||
private async Task BtnSaveNewGuest()
|
||||
{
|
||||
bool isFormValid = await _form.ValidateForm();
|
||||
if (!isFormValid)
|
||||
{
|
||||
Snackbar.Add("Invalid Form!", Severity.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
GuestDocumentDTO model = _form.Model;
|
||||
|
||||
Snackbar.Add($"Document '{model.DocumentNum}' creating...", Severity.Info);
|
||||
|
||||
//Show Loading dialog...
|
||||
var loadingDialog = await DialogService.ShowAsync<LoadingDialog>();
|
||||
|
||||
bool isCreated = await guestDocService.CreateDocumentAsync(model);
|
||||
if (!isCreated)
|
||||
{
|
||||
Snackbar.Add($"Error creating Document '{model.DocumentNum}'", Severity.Error);
|
||||
loadingDialog.Close();
|
||||
return;
|
||||
}
|
||||
|
||||
Snackbar.Add($"Document '{model.DocumentNum}' Created!", Severity.Success);
|
||||
Navigation.NavigateTo(GuestConsts.Page_GuestDocs_List);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
@using Somnia.GuestLog.Components.Controls
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace Somnia.GuestLog;
|
||||
|
||||
public static class GuestConsts
|
||||
{
|
||||
|
||||
public const string Page_GuestDocs_List = "/guest-documents";
|
||||
public const string Page_GuestDocs_New = "/guest-documents/new";
|
||||
|
||||
|
||||
public static HashSet<string> DocumentTypeList { get; private set; } = [
|
||||
"DNI",
|
||||
"NIE",
|
||||
"Passport",
|
||||
"ID Card",
|
||||
"Other",
|
||||
];
|
||||
|
||||
public static Dictionary<string, string> CountryList { get; private set; } = new([
|
||||
new KeyValuePair<string, string>("ESP", "Spain"),
|
||||
new KeyValuePair<string, string>("ITA", "Italy"),
|
||||
new KeyValuePair<string, string>("USA", "United States")
|
||||
]);
|
||||
|
||||
public static Dictionary<string, string> GenderList { get; private set; } = new([
|
||||
new KeyValuePair<string, string>("M", "Male"),
|
||||
new KeyValuePair<string, string>("F", "Female"),
|
||||
new KeyValuePair<string, string>("O", "Other")
|
||||
]);
|
||||
|
||||
|
||||
public const string regexPattern_phoneNum = @"\+?\d{1,4}?[-.\s]?\(?\d{1,3}?\)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9}";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Somnia.GuestLog.Models.Entities;
|
||||
|
||||
namespace Somnia.GuestLog.Infrastructure.EntityConfigs;
|
||||
|
||||
public class GuestDocumentEntityConfig : IEntityTypeConfiguration<GuestDocument>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<GuestDocument> builder)
|
||||
{
|
||||
builder.ToTable("GuestDocument");
|
||||
|
||||
//PK
|
||||
builder.HasKey(e => new { e.DocumentType, e.DocumentNum });
|
||||
|
||||
builder.Property(e => e.DocumentType)
|
||||
.IsRequired()
|
||||
.HasMaxLength(8);
|
||||
builder.Property(e => e.DocumentNum)
|
||||
.IsRequired()
|
||||
.HasMaxLength(64);
|
||||
|
||||
// builder.Property(e => e.IssueDate);
|
||||
|
||||
builder.Property(e => e.SupportNum)
|
||||
.HasMaxLength(10);
|
||||
|
||||
//3 letter code: ISO 3166-1 Alfa-3
|
||||
builder.Property(e => e.Nationality)
|
||||
.HasMaxLength(3);
|
||||
|
||||
builder.Property(e => e.Name)
|
||||
.IsRequired()
|
||||
.HasMaxLength(64);
|
||||
builder.Property(e => e.Surname)
|
||||
.IsRequired()
|
||||
.HasMaxLength(64);
|
||||
builder.Property(e => e.Surname2)
|
||||
.HasMaxLength(64);
|
||||
|
||||
// builder.Property(e => e.BirthDate);
|
||||
|
||||
builder.Property(e => e.Gender)
|
||||
.HasMaxLength(1);
|
||||
|
||||
builder.Property(e => e.PhoneNumber)
|
||||
.HasMaxLength(32);
|
||||
builder.Property(e => e.EmailAddress)
|
||||
.HasMaxLength(256);
|
||||
|
||||
|
||||
var addressBuilder = builder.ComplexProperty(e => e.AddressDetails);
|
||||
|
||||
addressBuilder.Property(e => e.Address)
|
||||
.HasMaxLength(128);
|
||||
addressBuilder.Property(e => e.AddressCity)
|
||||
.HasMaxLength(128);
|
||||
addressBuilder.Property(e => e.AddressProvince)
|
||||
.HasMaxLength(128);
|
||||
addressBuilder.Property(e => e.AddressState)
|
||||
.HasMaxLength(128);
|
||||
|
||||
//3 letter code: ISO 3166-1 Alfa-3
|
||||
addressBuilder.Property(e => e.AddressCountry)
|
||||
.IsRequired()
|
||||
.HasMaxLength(3);
|
||||
|
||||
addressBuilder.Property(e => e.ZipCode)
|
||||
.HasMaxLength(12);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Somnia.GuestLog.Infrastructure.EntityConfigs;
|
||||
using Somnia.GuestLog.Models.Entities;
|
||||
|
||||
namespace Somnia.GuestLog.Infrastructure;
|
||||
|
||||
public partial class GuestLogContext : DbContext
|
||||
{
|
||||
public GuestLogContext(DbContextOptions<GuestLogContext> options)
|
||||
: base(options)
|
||||
{ }
|
||||
|
||||
public DbSet<GuestDocument> GuestDocuments { get; set; }
|
||||
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.ApplyConfiguration<GuestDocument>(new GuestDocumentEntityConfig());
|
||||
|
||||
OnModelCreatingPartial(modelBuilder);
|
||||
base.OnModelCreating(modelBuilder);
|
||||
}
|
||||
|
||||
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
|
||||
|
||||
}
|
||||
Generated
+125
@@ -0,0 +1,125 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using Somnia.GuestLog.Infrastructure;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Somnia.GuestLog.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(GuestLogContext))]
|
||||
[Migration("20260618190348_AddTable_GuestDocuments")]
|
||||
partial class AddTable_GuestDocuments
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.7")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Somnia.GuestLog.Models.GuestDocument", b =>
|
||||
{
|
||||
b.Property<string>("DocumentType")
|
||||
.HasMaxLength(8)
|
||||
.HasColumnType("character varying(8)");
|
||||
|
||||
b.Property<string>("DocumentNum")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateOnly>("BirthDate")
|
||||
.HasColumnType("date");
|
||||
|
||||
b.Property<DateTime>("CreateTime")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("current_timestamp");
|
||||
|
||||
b.Property<string>("EmailAddress")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.HasMaxLength(1)
|
||||
.HasColumnType("character varying(1)");
|
||||
|
||||
b.Property<DateOnly>("IssueDate")
|
||||
.HasColumnType("date");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Nationality")
|
||||
.IsRequired()
|
||||
.HasMaxLength(3)
|
||||
.HasColumnType("character varying(3)");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<string>("SupportNum")
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("character varying(10)");
|
||||
|
||||
b.Property<string>("Surname")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Surname2")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateTime>("UpdateTime")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasDefaultValueSql("current_timestamp");
|
||||
|
||||
b.ComplexProperty(typeof(Dictionary<string, object>), "AddressDetails", "Somnia.GuestLog.Models.GuestDocument.AddressDetails#GuestAddress", b1 =>
|
||||
{
|
||||
b1.Property<string>("Address")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("AddressCity")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("AddressCountry")
|
||||
.IsRequired()
|
||||
.HasMaxLength(3)
|
||||
.HasColumnType("character varying(3)");
|
||||
|
||||
b1.Property<string>("AddressProvince")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("AddressState")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("ZipCode")
|
||||
.HasMaxLength(3)
|
||||
.HasColumnType("character varying(3)");
|
||||
});
|
||||
|
||||
b.HasKey("DocumentType", "DocumentNum");
|
||||
|
||||
b.ToTable("GuestDocument", (string)null);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Somnia.GuestLog.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddTable_GuestDocuments : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "GuestDocument",
|
||||
columns: table => new
|
||||
{
|
||||
DocumentType = table.Column<string>(type: "character varying(8)", maxLength: 8, nullable: false),
|
||||
DocumentNum = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
IssueDate = table.Column<DateOnly>(type: "date", nullable: false),
|
||||
SupportNum = table.Column<string>(type: "character varying(10)", maxLength: 10, nullable: true),
|
||||
Nationality = table.Column<string>(type: "character varying(3)", maxLength: 3, nullable: false),
|
||||
Name = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
Surname = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: false),
|
||||
Surname2 = table.Column<string>(type: "character varying(64)", maxLength: 64, nullable: true),
|
||||
BirthDate = table.Column<DateOnly>(type: "date", nullable: false),
|
||||
Gender = table.Column<string>(type: "character varying(1)", maxLength: 1, nullable: true),
|
||||
PhoneNumber = table.Column<string>(type: "character varying(32)", maxLength: 32, nullable: true),
|
||||
EmailAddress = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
|
||||
CreateTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp"),
|
||||
UpdateTime = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, defaultValueSql: "current_timestamp"),
|
||||
AddressDetails_Address = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||
AddressDetails_AddressCity = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||
AddressDetails_AddressCountry = table.Column<string>(type: "character varying(3)", maxLength: 3, nullable: true),
|
||||
AddressDetails_AddressProvince = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||
AddressDetails_AddressState = table.Column<string>(type: "character varying(128)", maxLength: 128, nullable: true),
|
||||
AddressDetails_ZipCode = table.Column<string>(type: "character varying(3)", maxLength: 3, nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_GuestDocument", x => new { x.DocumentType, x.DocumentNum });
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "GuestDocument");
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
+121
@@ -0,0 +1,121 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using Somnia.GuestLog.Infrastructure;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Somnia.GuestLog.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(GuestLogContext))]
|
||||
[Migration("20260621150802_GuestDocumentFixes")]
|
||||
partial class GuestDocumentFixes
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.7")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Somnia.GuestLog.Models.Entities.GuestDocument", b =>
|
||||
{
|
||||
b.Property<string>("DocumentType")
|
||||
.HasMaxLength(8)
|
||||
.HasColumnType("character varying(8)");
|
||||
|
||||
b.Property<string>("DocumentNum")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateOnly>("BirthDate")
|
||||
.HasColumnType("date");
|
||||
|
||||
b.Property<DateTime>("CreateTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("EmailAddress")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.HasMaxLength(1)
|
||||
.HasColumnType("character varying(1)");
|
||||
|
||||
b.Property<DateOnly>("IssueDate")
|
||||
.HasColumnType("date");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Nationality")
|
||||
.IsRequired()
|
||||
.HasMaxLength(3)
|
||||
.HasColumnType("character varying(3)");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<string>("SupportNum")
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("character varying(10)");
|
||||
|
||||
b.Property<string>("Surname")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Surname2")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateTime>("UpdateTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.ComplexProperty(typeof(Dictionary<string, object>), "AddressDetails", "Somnia.GuestLog.Models.Entities.GuestDocument.AddressDetails#GuestAddress", b1 =>
|
||||
{
|
||||
b1.Property<string>("Address")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("AddressCity")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("AddressCountry")
|
||||
.IsRequired()
|
||||
.HasMaxLength(3)
|
||||
.HasColumnType("character varying(3)");
|
||||
|
||||
b1.Property<string>("AddressProvince")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("AddressState")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("ZipCode")
|
||||
.HasMaxLength(12)
|
||||
.HasColumnType("character varying(12)");
|
||||
});
|
||||
|
||||
b.HasKey("DocumentType", "DocumentNum");
|
||||
|
||||
b.ToTable("GuestDocument", (string)null);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Somnia.GuestLog.Infrastructure.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class GuestDocumentFixes : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "UpdateTime",
|
||||
table: "GuestDocument",
|
||||
type: "timestamp with time zone",
|
||||
nullable: false,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp with time zone",
|
||||
oldDefaultValueSql: "current_timestamp");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "CreateTime",
|
||||
table: "GuestDocument",
|
||||
type: "timestamp with time zone",
|
||||
nullable: false,
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp with time zone",
|
||||
oldDefaultValueSql: "current_timestamp");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "AddressDetails_ZipCode",
|
||||
table: "GuestDocument",
|
||||
type: "character varying(12)",
|
||||
maxLength: 12,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(3)",
|
||||
oldMaxLength: 3,
|
||||
oldNullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "UpdateTime",
|
||||
table: "GuestDocument",
|
||||
type: "timestamp with time zone",
|
||||
nullable: false,
|
||||
defaultValueSql: "current_timestamp",
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp with time zone");
|
||||
|
||||
migrationBuilder.AlterColumn<DateTime>(
|
||||
name: "CreateTime",
|
||||
table: "GuestDocument",
|
||||
type: "timestamp with time zone",
|
||||
nullable: false,
|
||||
defaultValueSql: "current_timestamp",
|
||||
oldClrType: typeof(DateTime),
|
||||
oldType: "timestamp with time zone");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "AddressDetails_ZipCode",
|
||||
table: "GuestDocument",
|
||||
type: "character varying(3)",
|
||||
maxLength: 3,
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "character varying(12)",
|
||||
oldMaxLength: 12,
|
||||
oldNullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using Somnia.GuestLog.Infrastructure;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Somnia.GuestLog.Infrastructure.Migrations
|
||||
{
|
||||
[DbContext(typeof(GuestLogContext))]
|
||||
partial class GuestLogContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "10.0.7")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Somnia.GuestLog.Models.Entities.GuestDocument", b =>
|
||||
{
|
||||
b.Property<string>("DocumentType")
|
||||
.HasMaxLength(8)
|
||||
.HasColumnType("character varying(8)");
|
||||
|
||||
b.Property<string>("DocumentNum")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateOnly>("BirthDate")
|
||||
.HasColumnType("date");
|
||||
|
||||
b.Property<DateTime>("CreateTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("EmailAddress")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("character varying(256)");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.HasMaxLength(1)
|
||||
.HasColumnType("character varying(1)");
|
||||
|
||||
b.Property<DateOnly>("IssueDate")
|
||||
.HasColumnType("date");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Nationality")
|
||||
.IsRequired()
|
||||
.HasMaxLength(3)
|
||||
.HasColumnType("character varying(3)");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasMaxLength(32)
|
||||
.HasColumnType("character varying(32)");
|
||||
|
||||
b.Property<string>("SupportNum")
|
||||
.HasMaxLength(10)
|
||||
.HasColumnType("character varying(10)");
|
||||
|
||||
b.Property<string>("Surname")
|
||||
.IsRequired()
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<string>("Surname2")
|
||||
.HasMaxLength(64)
|
||||
.HasColumnType("character varying(64)");
|
||||
|
||||
b.Property<DateTime>("UpdateTime")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.ComplexProperty(typeof(Dictionary<string, object>), "AddressDetails", "Somnia.GuestLog.Models.Entities.GuestDocument.AddressDetails#GuestAddress", b1 =>
|
||||
{
|
||||
b1.Property<string>("Address")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("AddressCity")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("AddressCountry")
|
||||
.IsRequired()
|
||||
.HasMaxLength(3)
|
||||
.HasColumnType("character varying(3)");
|
||||
|
||||
b1.Property<string>("AddressProvince")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("AddressState")
|
||||
.HasMaxLength(128)
|
||||
.HasColumnType("character varying(128)");
|
||||
|
||||
b1.Property<string>("ZipCode")
|
||||
.HasMaxLength(12)
|
||||
.HasColumnType("character varying(12)");
|
||||
});
|
||||
|
||||
b.HasKey("DocumentType", "DocumentNum");
|
||||
|
||||
b.ToTable("GuestDocument", (string)null);
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace Somnia.GuestLog.Models.DTOs;
|
||||
|
||||
public class GuestDocumentDTO
|
||||
{
|
||||
public string? DocumentType { get; set; }
|
||||
public string? DocumentNum { get; set; }
|
||||
|
||||
public DateTime? IssueDate { get; set; }
|
||||
public string? SupportNum { get; set; }
|
||||
|
||||
public string? Nationality { get; set; }
|
||||
|
||||
public string? Name { get; set; }
|
||||
public string? Surname { get; set; }
|
||||
public string? Surname2 { get; set; }
|
||||
|
||||
public DateTime? BirthDate { get; set; }
|
||||
public string? Gender { get; set; }
|
||||
|
||||
public string? PhoneNumber { get; set; }
|
||||
public string? EmailAddress { get; set; }
|
||||
|
||||
|
||||
public string? Address { get; set; }
|
||||
public string? AddressCity { get; set; }
|
||||
public string? AddressProvince { get; set; }
|
||||
public string? AddressState { get; set; }
|
||||
public string? AddressCountry { get; set; }
|
||||
public string? ZipCode { get; set; }
|
||||
|
||||
|
||||
public DateTime? CreateTime { get; set; }
|
||||
public DateTime? UpdateTime { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Somnia.GuestLog.Models.Entities;
|
||||
|
||||
public abstract class BaseEntity
|
||||
{
|
||||
public abstract string GetFullKey();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Somnia.GuestLog.Models.Entities;
|
||||
|
||||
public class GuestAddress : BaseEntity
|
||||
{
|
||||
public string? Address { get; set; }
|
||||
public string? AddressCity { get; set; }
|
||||
public string? AddressProvince { get; set; }
|
||||
public string? AddressState { get; set; }
|
||||
public required string AddressCountry { get; set; }
|
||||
public string? ZipCode { get; set; }
|
||||
|
||||
public override string GetFullKey() => "N/A";
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Somnia.GuestLog.Models.Entities;
|
||||
|
||||
public class GuestDocument : BaseEntity
|
||||
{
|
||||
public required string DocumentType { get; set; }
|
||||
public required string DocumentNum { get; set; }
|
||||
|
||||
public required DateOnly IssueDate { get; set; }
|
||||
public string? SupportNum { get; set; }
|
||||
|
||||
public required string Nationality { get; set; }
|
||||
|
||||
public required string Name { get; set; }
|
||||
public required string Surname { get; set; }
|
||||
public string? Surname2 { get; set; }
|
||||
|
||||
public required DateOnly BirthDate { get; set; }
|
||||
public string? Gender { get; set; }
|
||||
|
||||
public GuestAddress? AddressDetails { get; set; }
|
||||
|
||||
public string? PhoneNumber { get; set; }
|
||||
public string? EmailAddress { get; set; }
|
||||
|
||||
//Generated Properties.
|
||||
public required DateTime CreateTime { get; set; }
|
||||
public required DateTime UpdateTime { get; set; }
|
||||
|
||||
|
||||
public override string GetFullKey() => $"{DocumentType}-{DocumentNum}";
|
||||
}
|
||||
@@ -1,8 +1,23 @@
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MudBlazor.Services;
|
||||
using Somnia.GuestLog.Components;
|
||||
using Somnia.GuestLog.Infrastructure;
|
||||
using Somnia.GuestLog.Models.DTOs;
|
||||
using Somnia.GuestLog.Services;
|
||||
using Somnia.GuestLog.Validators;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
var connectionStringGuestLog = builder.Configuration.GetConnectionString("DbSomniaGuestLog")
|
||||
?? throw new InvalidOperationException("Connection string 'DbSomniaGuestLog' not found.");
|
||||
builder.Services.AddDbContextFactory<GuestLogContext>(options =>
|
||||
{
|
||||
options.UseNpgsql(connectionStringGuestLog);
|
||||
});
|
||||
|
||||
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
|
||||
|
||||
// Add MudBlazor services
|
||||
builder.Services.AddMudServices();
|
||||
|
||||
@@ -10,6 +25,12 @@ builder.Services.AddMudServices();
|
||||
builder.Services.AddRazorComponents()
|
||||
.AddInteractiveServerComponents();
|
||||
|
||||
// Add Validation Services
|
||||
builder.Services.AddSingleton<IValidator<GuestDocumentDTO>, GuestDocumentDTOValidator>();
|
||||
|
||||
// Add Services
|
||||
builder.Services.AddSingleton<IGuestDocumentService, GuestDocumentService>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:5240",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
@@ -13,7 +13,7 @@
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:7120;http://localhost:5240",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
using FluentValidation;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Somnia.GuestLog.Infrastructure;
|
||||
using Somnia.GuestLog.Models.DTOs;
|
||||
using Somnia.GuestLog.Models.Entities;
|
||||
|
||||
namespace Somnia.GuestLog.Services;
|
||||
|
||||
public class GuestDocumentService(
|
||||
ILogger<GuestDocumentService> logger,
|
||||
IDbContextFactory<GuestLogContext> contextFactory,
|
||||
IValidator<GuestDocumentDTO> dtoValidator
|
||||
) : IGuestDocumentService
|
||||
{
|
||||
public async Task<bool> CreateDocumentAsync(GuestDocumentDTO dto)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dto);
|
||||
|
||||
var valResult = dtoValidator.Validate(dto);
|
||||
if (!valResult.IsValid)
|
||||
{
|
||||
logger.LogWarning("GuestDocumentService - CreateDocument: Dto validation failed. Fix the errors: {errorList}", valResult.Errors);
|
||||
return false;
|
||||
}
|
||||
|
||||
//Dto must be valid, so null warings shouldn't matter.
|
||||
GuestAddress addressItem = new()
|
||||
{
|
||||
Address = dto.Address,
|
||||
AddressCity = dto.AddressCity,
|
||||
AddressProvince = dto.AddressProvince,
|
||||
AddressState = dto.AddressState,
|
||||
AddressCountry = dto.AddressCountry!,
|
||||
ZipCode = dto.ZipCode,
|
||||
};
|
||||
|
||||
GuestDocument dbItem = new()
|
||||
{
|
||||
DocumentType = dto.DocumentType!,
|
||||
DocumentNum = dto.DocumentNum!,
|
||||
IssueDate = DateOnly.FromDateTime(dto.IssueDate!.Value),
|
||||
SupportNum = dto.SupportNum,
|
||||
Nationality = dto.Nationality!,
|
||||
Name = dto.Name!,
|
||||
Surname = dto.Surname!,
|
||||
Surname2 = dto.Surname2,
|
||||
BirthDate = DateOnly.FromDateTime(dto.BirthDate!.Value),
|
||||
Gender = dto.Gender,
|
||||
PhoneNumber = dto.PhoneNumber,
|
||||
EmailAddress = dto.EmailAddress,
|
||||
AddressDetails = addressItem,
|
||||
CreateTime = DateTime.UtcNow,
|
||||
UpdateTime = DateTime.UtcNow,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
await dbContext.AddAsync(dbItem);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
logger.LogInformation("GuestDocumentService - CreateDocument: GuestDocument Created: '{id}'", dbItem.GetFullKey());
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "GuestDocumentService - CreateDocument: Error creating GuestDocument: '{id}'", dbItem.GetFullKey());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool UpdateDocument(GuestDocumentDTO dto)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public async Task<GuestDocumentDTO?> GetDtoByIdAsync(string docType, string docNum)
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
GuestDocument? dbItem = await dbContext.GuestDocuments.FindAsync(new { docType, docNum });
|
||||
return dbItem is not null ? GetDtoFromDb(dbItem) : null;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<GuestDocumentDTO>> GetDtoListAsync()
|
||||
{
|
||||
using var dbContext = contextFactory.CreateDbContext();
|
||||
var dbList = await dbContext.GuestDocuments
|
||||
.OrderByDescending(e => e.UpdateTime)
|
||||
.ToListAsync();
|
||||
|
||||
return dbList.Select(x => GetDtoFromDb(x));
|
||||
}
|
||||
|
||||
|
||||
public GuestDocumentDTO GetDtoFromDb(GuestDocument dbItem)
|
||||
{
|
||||
return new()
|
||||
{
|
||||
DocumentType = dbItem.DocumentType,
|
||||
DocumentNum = dbItem.DocumentNum,
|
||||
IssueDate = dbItem.IssueDate.ToDateTime(TimeOnly.MinValue),
|
||||
SupportNum = dbItem.SupportNum,
|
||||
Nationality = dbItem.Nationality,
|
||||
Name = dbItem.Name,
|
||||
Surname = dbItem.Surname,
|
||||
Surname2 = dbItem.Surname2,
|
||||
BirthDate = dbItem.BirthDate.ToDateTime(TimeOnly.MinValue),
|
||||
Gender = dbItem.Gender,
|
||||
PhoneNumber = dbItem.PhoneNumber,
|
||||
EmailAddress = dbItem.EmailAddress,
|
||||
Address = dbItem.AddressDetails?.Address ?? "",
|
||||
AddressCity = dbItem.AddressDetails?.AddressCity ?? "",
|
||||
AddressProvince = dbItem.AddressDetails?.AddressProvince ?? "",
|
||||
AddressState = dbItem.AddressDetails?.AddressState ?? "",
|
||||
AddressCountry = dbItem.AddressDetails?.AddressCountry! ?? "",
|
||||
ZipCode = dbItem.AddressDetails?.ZipCode ?? "",
|
||||
CreateTime = dbItem.CreateTime,
|
||||
UpdateTime = dbItem.UpdateTime,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Somnia.GuestLog.Models.DTOs;
|
||||
|
||||
namespace Somnia.GuestLog.Services;
|
||||
|
||||
public interface IGuestDocumentService
|
||||
{
|
||||
public Task<bool> CreateDocumentAsync(GuestDocumentDTO dto);
|
||||
public bool UpdateDocument(GuestDocumentDTO dto);
|
||||
|
||||
public Task<GuestDocumentDTO?> GetDtoByIdAsync(string docType, string docNum);
|
||||
public Task<IEnumerable<GuestDocumentDTO>> GetDtoListAsync();
|
||||
|
||||
//TODO: Add Filter
|
||||
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentValidation" />
|
||||
<PackageReference Include="MudBlazor" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace Somnia.GuestLog.Utils;
|
||||
|
||||
/// <summary>
|
||||
/// A glue class to make it easy to define validation rules for single values using FluentValidation
|
||||
/// You can reuse this class for all your fields, like for the credit card rules above.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class FluentValueValidator<T> : AbstractValidator<T>
|
||||
{
|
||||
public FluentValueValidator(Action<IRuleBuilderInitial<T, T>> rule)
|
||||
{
|
||||
rule(RuleFor(x => x));
|
||||
}
|
||||
|
||||
private IEnumerable<string> ValidateValue(T arg)
|
||||
{
|
||||
var result = Validate(arg);
|
||||
if (result.IsValid)
|
||||
return new string[0];
|
||||
return result.Errors.Select(e => e.ErrorMessage);
|
||||
}
|
||||
|
||||
public Func<T, IEnumerable<string>> Validation => ValidateValue;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using FluentValidation;
|
||||
using Somnia.GuestLog.Models.DTOs;
|
||||
|
||||
namespace Somnia.GuestLog.Validators;
|
||||
|
||||
/// <summary>
|
||||
/// Validator for GuestDocumentDTO which contains multiple rules and can be shared with the back end API
|
||||
/// </summary>
|
||||
public class GuestDocumentDTOValidator : AbstractValidator<GuestDocumentDTO>
|
||||
{
|
||||
public GuestDocumentDTOValidator()
|
||||
{
|
||||
RuleFor(x => x.DocumentType)
|
||||
.NotEmpty()
|
||||
.Must(val => val != null && GuestConsts.DocumentTypeList.Contains(val));
|
||||
|
||||
RuleFor(x => x.DocumentNum)
|
||||
.NotEmpty()
|
||||
.Length(6, 32);
|
||||
|
||||
RuleFor(x => x.IssueDate)
|
||||
.NotEmpty()
|
||||
.LessThanOrEqualTo(DateTime.Today);
|
||||
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty()
|
||||
.Length(1, 100);
|
||||
|
||||
RuleFor(x => x.Surname)
|
||||
.NotEmpty()
|
||||
.Length(1, 100);
|
||||
|
||||
RuleFor(x => x.BirthDate)
|
||||
.NotEmpty()
|
||||
.LessThanOrEqualTo(DateTime.Today);
|
||||
|
||||
RuleFor(x => x.Nationality)
|
||||
.NotEmpty()
|
||||
.Must(val => val != null && GuestConsts.CountryList.ContainsKey(val));
|
||||
|
||||
|
||||
//Contact Fields
|
||||
RuleFor(x => x.EmailAddress)
|
||||
.EmailAddress()
|
||||
.When(x => !string.IsNullOrEmpty(x.EmailAddress));
|
||||
|
||||
RuleFor(x => x.PhoneNumber)
|
||||
.Matches(GuestConsts.regexPattern_phoneNum)
|
||||
.When(x => !string.IsNullOrEmpty(x.PhoneNumber));
|
||||
|
||||
RuleFor(x => x.AddressCountry)
|
||||
.NotEmpty()
|
||||
.Must(val => val != null && GuestConsts.CountryList.ContainsKey(val));
|
||||
|
||||
// RuleFor(x => x.Email)
|
||||
// .Cascade(CascadeMode.Stop)
|
||||
// .NotEmpty()
|
||||
// .EmailAddress()
|
||||
// .MustAsync(async (value, _) => await IsUniqueAsync(value));
|
||||
|
||||
// RuleFor(x => x.CCNumber)
|
||||
// .NotEmpty()
|
||||
// .Length(1, 100)
|
||||
// .CreditCard();
|
||||
|
||||
// RuleFor(x => x.Address.Address)
|
||||
// .NotEmpty()
|
||||
// .Length(1, 100);
|
||||
|
||||
// RuleFor(x => x.Address.City)
|
||||
// .NotEmpty()
|
||||
// .Length(1, 100);
|
||||
|
||||
// RuleFor(x => x.Address.Country)
|
||||
// .NotEmpty()
|
||||
// .Length(1, 100);
|
||||
|
||||
// RuleForEach(x => x.OrderDetails)
|
||||
// .SetValidator(new OrderDetailsModelFluentValidator());
|
||||
}
|
||||
|
||||
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
|
||||
{
|
||||
var result = await ValidateAsync(ValidationContext<GuestDocumentDTO>.CreateWithOptions((GuestDocumentDTO)model, x =>
|
||||
x.IncludeProperties(propertyName)));
|
||||
return result.IsValid ? [] : result.Errors.Select(e => e.ErrorMessage);
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"DbSomniaGuestLog": "Host=localhost;Port=5432;Username=postgres;Password=P@ssw0rd;Database=SomniaGuestLog"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
|
||||
Reference in New Issue
Block a user