mirror of
https://github.com/claunia/marechai.git
synced 2025-12-16 19:14:25 +00:00
Add person editing in admin view.
This commit is contained in:
@@ -1,96 +0,0 @@
|
||||
@model Marechai.Database.Models.Person
|
||||
|
||||
@{
|
||||
ViewData["Title"] = "Edit";
|
||||
}
|
||||
<h1>Edit</h1>
|
||||
<h4>Person</h4>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<form asp-action="Edit">
|
||||
<div asp-validation-summary="ModelOnly" class="text-danger">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Name" class="control-label">
|
||||
</label>
|
||||
<input asp-for="Name" class="form-control" />
|
||||
<span asp-validation-for="Name" class="text-danger">
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Surname" class="control-label">
|
||||
</label>
|
||||
<input asp-for="Surname" class="form-control" />
|
||||
<span asp-validation-for="Surname" class="text-danger">
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Alias" class="control-label">
|
||||
</label>
|
||||
<input asp-for="Alias" class="form-control" />
|
||||
<span asp-validation-for="Alias" class="text-danger">
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="DisplayName" class="control-label">
|
||||
</label>
|
||||
<input asp-for="DisplayName" class="form-control" />
|
||||
<span asp-validation-for="DisplayName" class="text-danger">
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="BirthDate" class="control-label">
|
||||
</label>
|
||||
<input asp-for="BirthDate" class="form-control" />
|
||||
<span asp-validation-for="BirthDate" class="text-danger">
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="DeathDate" class="control-label">
|
||||
</label>
|
||||
<input asp-for="DeathDate" class="form-control" />
|
||||
<span asp-validation-for="DeathDate" class="text-danger">
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Webpage" class="control-label">
|
||||
</label>
|
||||
<input asp-for="Webpage" class="form-control" />
|
||||
<span asp-validation-for="Webpage" class="text-danger">
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Twitter" class="control-label">
|
||||
</label>
|
||||
<input asp-for="Twitter" class="form-control" />
|
||||
<span asp-validation-for="Twitter" class="text-danger">
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="Facebook" class="control-label">
|
||||
</label>
|
||||
<input asp-for="Facebook" class="form-control" />
|
||||
<span asp-validation-for="Facebook" class="text-danger">
|
||||
</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label asp-for="CountryOfBirth" class="control-label">
|
||||
</label>
|
||||
<select asp-for="CountryOfBirthId" class="form-control" asp-items="ViewBag.CountryOfBirthId">
|
||||
</select>
|
||||
</div>
|
||||
<input type="hidden" asp-for="Id" />
|
||||
<div class="form-group">
|
||||
<input class="btn btn-primary" type="submit" value="Save" />
|
||||
<a asp-action="Index" class="btn btn-secondary">
|
||||
Back to List
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
@{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<Version>3.0.99.1224</Version>
|
||||
<Version>3.0.99.1225</Version>
|
||||
<Company>Canary Islands Computer Museum</Company>
|
||||
<Copyright>Copyright © 2003-2020 Natalia Portillo</Copyright>
|
||||
<Product>Canary Islands Computer Museum Website</Product>
|
||||
|
||||
@@ -31,9 +31,11 @@
|
||||
}
|
||||
|
||||
@page "/admin/people/details/{Id:int}"
|
||||
@page "/admin/people/edit/{Id:int}"
|
||||
@inherits OwningComponentBase<PeopleService>
|
||||
@inject IStringLocalizer<PeopleService> L
|
||||
@inject Iso31661NumericService CountriesService
|
||||
@inject NavigationManager NavigationManager
|
||||
@attribute [Authorize(Roles = "UberAdmin, Admin")]
|
||||
<h3>@L["Person details"]</h3>
|
||||
<hr />
|
||||
@@ -46,80 +48,213 @@
|
||||
}
|
||||
|
||||
<div>
|
||||
@if (_editable || _model.Name != null)
|
||||
@if (_editing || _model.Name != null)
|
||||
{
|
||||
<Field>
|
||||
<FieldLabel>@L["Name"]</FieldLabel>
|
||||
<TextEdit ReadOnly="!_editable" @bind-Text="@_model.Name" />
|
||||
@if (_editing)
|
||||
{
|
||||
<Check TValue="bool" @bind-Checked="@_unknownName">@L["Unknown (name)"]</Check>
|
||||
}
|
||||
@if (!_editing ||
|
||||
!_unknownName)
|
||||
{
|
||||
<Validation Validator="@ValidateName">
|
||||
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Name">
|
||||
<Feedback>
|
||||
<ValidationError>@L["Please enter a valid name."]</ValidationError>
|
||||
</Feedback>
|
||||
</TextEdit>
|
||||
</Validation>
|
||||
}
|
||||
</Field>
|
||||
}
|
||||
@if (_editable || _model.Surname != null)
|
||||
@if (_editing || _model.Surname != null)
|
||||
{
|
||||
<Field>
|
||||
<FieldLabel>@L["Surname"]</FieldLabel>
|
||||
<TextEdit ReadOnly="!_editable" @bind-Text="@_model.Surname" />
|
||||
@if (_editing)
|
||||
{
|
||||
<Check TValue="bool" @bind-Checked="@_unknownSurname">@L["Unknown (surname)"]</Check>
|
||||
}
|
||||
@if (!_editing ||
|
||||
!_unknownSurname)
|
||||
{
|
||||
<Validation Validator="@ValidateSurname">
|
||||
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Surname">
|
||||
<Feedback>
|
||||
<ValidationError>@L["Please enter a valid surname."]</ValidationError>
|
||||
</Feedback>
|
||||
</TextEdit>
|
||||
</Validation>
|
||||
}
|
||||
</Field>
|
||||
}
|
||||
@if (_editable || _model.Alias != null)
|
||||
@if (_editing || _model.Alias != null)
|
||||
{
|
||||
<Field>
|
||||
<FieldLabel>@L["Alias"]</FieldLabel>
|
||||
<TextEdit ReadOnly="!_editable" @bind-Text="@_model.Alias" />
|
||||
@if (_editing)
|
||||
{
|
||||
<Check TValue="bool" @bind-Checked="@_unknownAlias">@L["Unknown (alias)"]</Check>
|
||||
}
|
||||
@if (!_editing ||
|
||||
!_unknownAlias)
|
||||
{
|
||||
<Validation Validator="@ValidateAlias">
|
||||
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Alias">
|
||||
<Feedback>
|
||||
<ValidationError>@L["Please enter a valid alias."]</ValidationError>
|
||||
</Feedback>
|
||||
</TextEdit>
|
||||
</Validation>
|
||||
}
|
||||
</Field>
|
||||
}
|
||||
@if (_editable || _model.DisplayName != null)
|
||||
@if (_editing || _model.DisplayName != null)
|
||||
{
|
||||
<Field>
|
||||
<FieldLabel>@L["Display name"]</FieldLabel>
|
||||
<TextEdit ReadOnly="!_editable" @bind-Text="@_model.DisplayName" />
|
||||
@if (_editing)
|
||||
{
|
||||
<Check TValue="bool" @bind-Checked="@_unknownDisplayName">@L["Unknown (display name)"]</Check>
|
||||
}
|
||||
@if (!_editing ||
|
||||
!_unknownDisplayName)
|
||||
{
|
||||
<Validation Validator="@ValidateDisplayName">
|
||||
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.DisplayName">
|
||||
<Feedback>
|
||||
<ValidationError>@L["Please enter a valid display name."]</ValidationError>
|
||||
</Feedback>
|
||||
</TextEdit>
|
||||
</Validation>
|
||||
}
|
||||
</Field>
|
||||
}
|
||||
@if (_editable || _model.CountryOfBirthId != null)
|
||||
@if (_editing || _model.CountryOfBirthId != null)
|
||||
{
|
||||
<Field>
|
||||
<FieldLabel>@L["Country of birth"]</FieldLabel>
|
||||
<Select Disabled="!_editable" TValue="short?" @bind-SelectedValue="@_model.CountryOfBirthId">
|
||||
@foreach (var country in _countries)
|
||||
{
|
||||
<SelectItem TValue="short?" Value="@country.Id">@country.Name</SelectItem>
|
||||
}
|
||||
</Select>
|
||||
@if (_editing)
|
||||
{
|
||||
<Check TValue="bool" @bind-Checked="@_unknownCountry">@L["Unknown (country of birth)"]</Check>
|
||||
}
|
||||
@if (!_editing ||
|
||||
!_unknownCountry)
|
||||
{
|
||||
<Select Disabled="!_editing" TValue="short?" @bind-SelectedValue="@_model.CountryOfBirthId">
|
||||
@foreach (var country in _countries)
|
||||
{
|
||||
<SelectItem TValue="short?" Value="@country.Id">@country.Name</SelectItem>
|
||||
}
|
||||
</Select>
|
||||
}
|
||||
</Field>
|
||||
}
|
||||
<Field>
|
||||
<FieldLabel>@L["Birth date"]</FieldLabel>
|
||||
<DateEdit TValue="DateTime" ReadOnly="!_editable" @bind-Text="@_model.BirthDate" />
|
||||
<Validation Validator="@ValidateBirthDate">
|
||||
<DateEdit TValue="DateTime" ReadOnly="!_editing" @bind-Text="@_model.BirthDate" >
|
||||
<Feedback>
|
||||
<ValidationError>@L["Please enter a valid birth date."]</ValidationError>
|
||||
</Feedback>
|
||||
</DateEdit>
|
||||
</Validation>
|
||||
</Field>
|
||||
@if (_editable || _model.DeathDate != null)
|
||||
@if (_editing || _model.DeathDate != null)
|
||||
{
|
||||
<Field>
|
||||
<FieldLabel>@L["Date of death"]</FieldLabel>
|
||||
<DateEdit TValue="DateTime?" ReadOnly="!_editable" @bind-Text="@_model.DeathDate" />
|
||||
@if (_editing)
|
||||
{
|
||||
<Check TValue="bool" @bind-Checked="@_unknownDeathDate">@L["Unknown (death date)"]</Check>
|
||||
}
|
||||
@if (!_editing || !_unknownDeathDate)
|
||||
{
|
||||
<Validation Validator="@ValidateDeathDate">
|
||||
<DateEdit TValue="DateTime?" ReadOnly="!_editing" @bind-Text="@_model.DeathDate" >
|
||||
<Feedback>
|
||||
<ValidationError>@L["Please enter a valid death date."]</ValidationError>
|
||||
</Feedback>
|
||||
</DateEdit>
|
||||
</Validation>
|
||||
}
|
||||
</Field>
|
||||
}
|
||||
@if (_editable || _model.Webpage != null)
|
||||
@if (_editing || _model.Webpage != null)
|
||||
{
|
||||
<Field>
|
||||
<FieldLabel>@L["Webpage"]</FieldLabel>
|
||||
<TextEdit ReadOnly="!_editable" @bind-Text="@_model.Webpage" />
|
||||
@if (_editing)
|
||||
{
|
||||
<Check TValue="bool" @bind-Checked="@_unknownWebpage">@L["Unknown (webpage)"]</Check>
|
||||
}
|
||||
@if (!_editing ||
|
||||
!_unknownWebpage)
|
||||
{
|
||||
<Validation Validator="@ValidateWebpage">
|
||||
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Webpage">
|
||||
<Feedback>
|
||||
<ValidationError>@L["Please enter a valid webpage."]</ValidationError>
|
||||
</Feedback>
|
||||
</TextEdit>
|
||||
</Validation>
|
||||
}
|
||||
</Field>
|
||||
}
|
||||
@if (_editable || _model.Twitter != null)
|
||||
@if (_editing || _model.Twitter != null)
|
||||
{
|
||||
<Field>
|
||||
<FieldLabel>@L["Twitter"]</FieldLabel>
|
||||
<TextEdit ReadOnly="!_editable" @bind-Text="@_model.Twitter" />
|
||||
@if (_editing)
|
||||
{
|
||||
<Check TValue="bool" @bind-Checked="@_unknownTwitter">@L["Unknown (twitter)"]</Check>
|
||||
}
|
||||
@if (!_editing ||
|
||||
!_unknownTwitter)
|
||||
{
|
||||
<Validation Validator="@ValidateTwitter">
|
||||
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Twitter">
|
||||
<Feedback>
|
||||
<ValidationError>@L["Please enter a valid Twitter handle."]</ValidationError>
|
||||
</Feedback>
|
||||
</TextEdit>
|
||||
</Validation>
|
||||
}
|
||||
</Field>
|
||||
}
|
||||
@if (_editable || _model.Facebook != null)
|
||||
@if (_editing || _model.Facebook != null)
|
||||
{
|
||||
<Field>
|
||||
<FieldLabel>@L["Facebook"]</FieldLabel>
|
||||
<TextEdit ReadOnly="!_editable" @bind-Text="@_model.Facebook" />
|
||||
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Facebook" />
|
||||
@if (_editing)
|
||||
{
|
||||
<Check TValue="bool" @bind-Checked="@_unknownFacebook">@L["Unknown (facebook)"]</Check>
|
||||
}
|
||||
@if (!_editing ||
|
||||
!_unknownFacebook)
|
||||
{
|
||||
<Validation Validator="@ValidateFacebook">
|
||||
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Facebook">
|
||||
<Feedback>
|
||||
<ValidationError>@L["Please enter a valid Facebook user name."]</ValidationError>
|
||||
</Feedback>
|
||||
</TextEdit>
|
||||
</Validation>
|
||||
}
|
||||
</Field>
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
<span class="btn btn-primary">@L["Edit"]</span>
|
||||
@if (!_editing)
|
||||
{
|
||||
<Button Color="Color.Primary" Clicked="@OnEditClicked">@L["Edit"]</Button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<Button Color="Color.Success" Clicked="@OnSaveClicked">@L["Save"]</Button>
|
||||
<Button Color="Color.Danger" Clicked="@OnCancelClicked">@L["Cancel"]</Button>
|
||||
}
|
||||
<a href="/admin/people" class="btn btn-secondary">@L["Back to list"]</a>
|
||||
</div>
|
||||
@@ -1,16 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Blazorise;
|
||||
using Marechai.Database.Models;
|
||||
using Marechai.Shared;
|
||||
using Marechai.ViewModels;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Match = System.Text.RegularExpressions.Match;
|
||||
|
||||
namespace Marechai.Pages.Admin.Details
|
||||
{
|
||||
public partial class Person
|
||||
{
|
||||
List<Iso31661Numeric> _countries;
|
||||
bool _editable;
|
||||
bool _loaded;
|
||||
Database.Models.Person _model;
|
||||
const string _webpageRegex =
|
||||
@"^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$";
|
||||
List<Iso31661Numeric> _countries;
|
||||
bool _editing;
|
||||
bool _loaded;
|
||||
PersonViewModel _model;
|
||||
bool _unknownAlias;
|
||||
bool _unknownCountry;
|
||||
bool _unknownDeathDate;
|
||||
bool _unknownDisplayName;
|
||||
bool _unknownFacebook;
|
||||
bool _unknownName;
|
||||
bool _unknownSurname;
|
||||
bool _unknownTwitter;
|
||||
bool _unknownWebpage;
|
||||
[Parameter]
|
||||
public int Id { get; set; }
|
||||
|
||||
@@ -27,7 +44,275 @@ namespace Marechai.Pages.Admin.Details
|
||||
_countries = await CountriesService.GetAsync();
|
||||
_model = await Service.GetAsync(Id);
|
||||
|
||||
_editing = NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant().
|
||||
StartsWith("admin/people/edit/", StringComparison.InvariantCulture);
|
||||
|
||||
if(_editing)
|
||||
SetCheckboxes();
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void SetCheckboxes()
|
||||
{
|
||||
_unknownAlias = string.IsNullOrWhiteSpace(_model.Alias);
|
||||
_unknownCountry = !_model.CountryOfBirthId.HasValue;
|
||||
_unknownDeathDate = !_model.DeathDate.HasValue;
|
||||
_unknownDisplayName = string.IsNullOrWhiteSpace(_model.DisplayName);
|
||||
_unknownFacebook = string.IsNullOrWhiteSpace(_model.Facebook);
|
||||
_unknownName = string.IsNullOrWhiteSpace(_model.Name);
|
||||
_unknownSurname = string.IsNullOrWhiteSpace(_model.Surname);
|
||||
_unknownTwitter = string.IsNullOrWhiteSpace(_model.Twitter);
|
||||
_unknownWebpage = string.IsNullOrWhiteSpace(_model.Webpage);
|
||||
}
|
||||
|
||||
void OnEditClicked()
|
||||
{
|
||||
_editing = true;
|
||||
SetCheckboxes();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
async void OnCancelClicked()
|
||||
{
|
||||
_editing = false;
|
||||
_model = await Service.GetAsync(Id);
|
||||
SetCheckboxes();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
async void OnSaveClicked()
|
||||
{
|
||||
if(_unknownAlias)
|
||||
_model.Alias = null;
|
||||
else if(string.IsNullOrWhiteSpace(_model.Alias))
|
||||
return;
|
||||
|
||||
if(_unknownCountry)
|
||||
_model.CountryOfBirthId = null;
|
||||
else if(_model.CountryOfBirthId < 0)
|
||||
return;
|
||||
|
||||
if(_model.BirthDate.Date >= DateTime.UtcNow.Date)
|
||||
return;
|
||||
|
||||
if(_unknownDeathDate)
|
||||
_model.DeathDate = null;
|
||||
else if(_model.DeathDate?.Date >= DateTime.UtcNow.Date)
|
||||
return;
|
||||
else if(_model.DeathDate?.Date <= _model.BirthDate.Date)
|
||||
return;
|
||||
|
||||
if(_unknownAlias)
|
||||
_model.Alias = null;
|
||||
else if(string.IsNullOrWhiteSpace(_model.Alias))
|
||||
return;
|
||||
|
||||
if(_unknownDisplayName)
|
||||
_model.Alias = null;
|
||||
else if(string.IsNullOrWhiteSpace(_model.Alias))
|
||||
return;
|
||||
|
||||
if(_unknownFacebook)
|
||||
_model.Alias = null;
|
||||
else if(string.IsNullOrWhiteSpace(_model.Alias))
|
||||
return;
|
||||
|
||||
if(_unknownName)
|
||||
_model.Alias = null;
|
||||
else if(string.IsNullOrWhiteSpace(_model.Alias))
|
||||
return;
|
||||
|
||||
if(_unknownSurname)
|
||||
_model.Alias = null;
|
||||
else if(string.IsNullOrWhiteSpace(_model.Alias))
|
||||
return;
|
||||
|
||||
if(_unknownWebpage)
|
||||
_model.Alias = null;
|
||||
else if(string.IsNullOrWhiteSpace(_model.Alias))
|
||||
return;
|
||||
|
||||
if((_unknownName && !_unknownSurname) ||
|
||||
(!_unknownName && _unknownSurname))
|
||||
return;
|
||||
|
||||
// TODO: Show error here
|
||||
if(_unknownName &&
|
||||
_unknownSurname &&
|
||||
_unknownAlias &&
|
||||
_unknownDisplayName)
|
||||
return;
|
||||
|
||||
_editing = false;
|
||||
await Service.UpdateAsync(_model);
|
||||
_model = await Service.GetAsync(Id);
|
||||
SetCheckboxes();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void ValidateName(ValidatorEventArgs e)
|
||||
{
|
||||
if(!(e.Value is string name))
|
||||
{
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(name.Length < 1 ||
|
||||
name.Length > 256)
|
||||
{
|
||||
e.ErrorText = L["Name must be smaller than 256 characters."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(_model.Surname) &&
|
||||
!_unknownSurname)
|
||||
return;
|
||||
|
||||
e.ErrorText = L["Both name and surname must be known and filled, or both unknown."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
}
|
||||
|
||||
void ValidateSurname(ValidatorEventArgs e)
|
||||
{
|
||||
if(!(e.Value is string surname))
|
||||
{
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(surname.Length < 1 ||
|
||||
surname.Length > 256)
|
||||
{
|
||||
e.ErrorText = L["Surname must be smaller than 256 characters."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(_model.Surname) &&
|
||||
!_unknownSurname)
|
||||
return;
|
||||
|
||||
e.ErrorText = L["Both name and surname must be known and filled, or both unknown."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
}
|
||||
|
||||
void ValidateAlias(ValidatorEventArgs e) =>
|
||||
Validators.ValidateString(e, L["Alias must be smaller than 256 characters."], 256);
|
||||
|
||||
void ValidateDisplayName(ValidatorEventArgs e) =>
|
||||
Validators.ValidateString(e, L["Display name must be smaller than 256 characters."], 256);
|
||||
|
||||
void ValidateBirthDate(ValidatorEventArgs e)
|
||||
{
|
||||
if(!(e.Value is DateTime date))
|
||||
{
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(date.Date >= DateTime.UtcNow.Date)
|
||||
{
|
||||
e.ErrorText = L["Birth date must be before today."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(_unknownDeathDate || !_model.DeathDate.HasValue)
|
||||
return;
|
||||
|
||||
if(date.Date < _model.DeathDate?.Date)
|
||||
return;
|
||||
|
||||
e.ErrorText = L["Birth date must be before death date."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
}
|
||||
|
||||
void ValidateDeathDate(ValidatorEventArgs e)
|
||||
{
|
||||
if(!(e.Value is DateTime date))
|
||||
{
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(date.Date >= DateTime.UtcNow.Date)
|
||||
{
|
||||
e.ErrorText = L["Death date must be before today."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(date.Date > _model.BirthDate.Date)
|
||||
return;
|
||||
|
||||
e.ErrorText = L["Death date must be after birth date."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
}
|
||||
|
||||
void ValidateWebpage(ValidatorEventArgs e)
|
||||
{
|
||||
if(!(e.Value is string webpage))
|
||||
{
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(webpage.Length < 1 ||
|
||||
webpage.Length > 255)
|
||||
{
|
||||
e.ErrorText = L["Webpage must be smaller than 255 characters."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var rx = new Regex(_webpageRegex);
|
||||
Match m = rx.Match(webpage);
|
||||
|
||||
if(m.Success)
|
||||
return;
|
||||
|
||||
e.Status = ValidationStatus.Error;
|
||||
}
|
||||
|
||||
void ValidateTwitter(ValidatorEventArgs e)
|
||||
{
|
||||
if(!(e.Value is string twitter))
|
||||
{
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(twitter.Length < 1 ||
|
||||
twitter.Length > 255)
|
||||
{
|
||||
e.ErrorText = L["Twitter handle must be smaller than 255 characters."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(twitter[0] == '@')
|
||||
return;
|
||||
|
||||
e.ErrorText = L["Invalid Twitter handle."];
|
||||
e.Status = ValidationStatus.Error;
|
||||
}
|
||||
|
||||
void ValidateFacebook(ValidatorEventArgs e) =>
|
||||
Validators.ValidateString(e, L["Facebook username must be smaller than 256 characters."], 256);
|
||||
}
|
||||
}
|
||||
@@ -106,9 +106,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-primary" href="/admin/people/details/@item.Id">@L["Details"]</a>
|
||||
<span class="btn btn-secondary">
|
||||
@L["Edit"]
|
||||
</span>
|
||||
<a class="btn btn-primary" href="/admin/edit/details/@item.Id">@L["Edit"]</a>
|
||||
<Button Color="Color.Danger" Clicked="() => {ShowModal(item.Id);}">@L["Delete"]</Button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
157
Marechai/Resources/Services/PeopleService.en.resx
Normal file
157
Marechai/Resources/Services/PeopleService.en.resx
Normal file
@@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- ReSharper disable MarkupTextTypo -->
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Unknown (name)" xml:space="preserve">
|
||||
<value>Unknown</value>
|
||||
<comment>Unknown, referring to a name</comment>
|
||||
</data>
|
||||
<data name="Unknown (surname)" xml:space="preserve">
|
||||
<value>Unknown</value>
|
||||
<comment>Unknown, referring to one or more surnames</comment>
|
||||
</data>
|
||||
<data name="Unknown (alias)" xml:space="preserve">
|
||||
<value>Unknown</value>
|
||||
<comment>Unknown, referring to an alias</comment>
|
||||
</data>
|
||||
<data name="Unknown (display name)" xml:space="preserve">
|
||||
<value>Unknown</value>
|
||||
<comment>Unknown, referring to a display name</comment>
|
||||
</data>
|
||||
<data name="Unknown (country of birth)" xml:space="preserve">
|
||||
<value>Unknown</value>
|
||||
<comment>Unknown, referring to a country</comment>
|
||||
</data>
|
||||
<data name="Unknown (death date)" xml:space="preserve">
|
||||
<value>Unknown</value>
|
||||
<comment>Unknown, referring to the death date</comment>
|
||||
</data>
|
||||
<data name="Unknown (webpage)" xml:space="preserve">
|
||||
<value>Unknown</value>
|
||||
<comment>Unknown, referring to a webpage</comment>
|
||||
</data>
|
||||
<data name="Unknown (twitter)" xml:space="preserve">
|
||||
<value>Unknown</value>
|
||||
<comment>Unknown, referring to a twitter handle</comment>
|
||||
</data>
|
||||
<data name="Unknown (facebook)" xml:space="preserve">
|
||||
<value>Unknown</value>
|
||||
<comment>Unknown, referring to a facebook username</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -188,7 +188,7 @@
|
||||
</data>
|
||||
<data name="Surname" xml:space="preserve">
|
||||
<value>Apellido</value>
|
||||
<comment>Surnam</comment>
|
||||
<comment>Surname</comment>
|
||||
</data>
|
||||
<data name="Alias" xml:space="preserve">
|
||||
<value>Alias</value>
|
||||
@@ -206,4 +206,132 @@
|
||||
<value>Volver a la lista</value>
|
||||
<comment>Back to list</comment>
|
||||
</data>
|
||||
<data name="Save" xml:space="preserve">
|
||||
<value>Guardar</value>
|
||||
<comment>Save</comment>
|
||||
</data>
|
||||
<data name="Unknown (name)" xml:space="preserve">
|
||||
<value>Desconocido</value>
|
||||
<comment>Unknown, referring to a name</comment>
|
||||
</data>
|
||||
<data name="Unknown (surname)" xml:space="preserve">
|
||||
<value>Desconocidos</value>
|
||||
<comment>Unknown, referring to one or more surnames</comment>
|
||||
</data>
|
||||
<data name="Unknown (alias)" xml:space="preserve">
|
||||
<value>Desconocido</value>
|
||||
<comment>Unknown, referring to an alias</comment>
|
||||
</data>
|
||||
<data name="Unknown (display name)" xml:space="preserve">
|
||||
<value>Desconocido</value>
|
||||
<comment>Unknown, referring to a display name</comment>
|
||||
</data>
|
||||
<data name="Unknown (country of birth)" xml:space="preserve">
|
||||
<value>Desconocido</value>
|
||||
<comment>Unknown, referring to a country</comment>
|
||||
</data>
|
||||
<data name="Unknown (death date)" xml:space="preserve">
|
||||
<value>Desconocida</value>
|
||||
<comment>Unknown, referring to the death date</comment>
|
||||
</data>
|
||||
<data name="Unknown (webpage)" xml:space="preserve">
|
||||
<value>Desconocida</value>
|
||||
<comment>Unknown, referring to a webpage</comment>
|
||||
</data>
|
||||
<data name="Unknown (twitter)" xml:space="preserve">
|
||||
<value>Desconocido</value>
|
||||
<comment>Unknown, referring to a twitter handle</comment>
|
||||
</data>
|
||||
<data name="Unknown (facebook)" xml:space="preserve">
|
||||
<value>Desconocido</value>
|
||||
<comment>Unknown, referring to a facebook username</comment>
|
||||
</data>
|
||||
<data name="Please enter a valid name." xml:space="preserve">
|
||||
<value>Por favor introduce un nombre válido.</value>
|
||||
<comment>Please enter a valid name.</comment>
|
||||
</data>
|
||||
<data name="Please enter a valid surname." xml:space="preserve">
|
||||
<value>Por favor introduce un apellido (o varios) válido.</value>
|
||||
<comment>Please enter a valid surname.</comment>
|
||||
</data>
|
||||
<data name="Please enter a valid alias." xml:space="preserve">
|
||||
<value>Por favor introduce un alias válido.</value>
|
||||
<comment>Please enter a valid alias.</comment>
|
||||
</data>
|
||||
<data name="Please enter a valid display name." xml:space="preserve">
|
||||
<value>Por favor introduce un nombre para mostrar válido.</value>
|
||||
<comment>Please enter a valid display name.</comment>
|
||||
</data>
|
||||
<data name="Please enter a valid birth date." xml:space="preserve">
|
||||
<value>Por favor introduce una fecha de nacimiento válida.</value>
|
||||
<comment>Please enter a valid birth date.</comment>
|
||||
</data>
|
||||
<data name="Please enter a valid death date." xml:space="preserve">
|
||||
<value>Por favor introduce una fecha de fallecimiento válida.</value>
|
||||
<comment>Please enter a valid death date.</comment>
|
||||
</data>
|
||||
<data name="Please enter a valid webpage." xml:space="preserve">
|
||||
<value>Por favor introduce una página web válida.</value>
|
||||
<comment>Please enter a valid webpage.</comment>
|
||||
</data>
|
||||
<data name="Please enter a valid Twitter handle." xml:space="preserve">
|
||||
<value>Por favor introduce un identificador de Twitter válido.</value>
|
||||
<comment>Please enter a valid Twitter handle.</comment>
|
||||
</data>
|
||||
<data name="Please enter a valid Facebook user name." xml:space="preserve">
|
||||
<value>Por favor introduce un nombre de usuario de Facebook válido.</value>
|
||||
<comment>Please enter a valid Facebook user name.</comment>
|
||||
</data>
|
||||
<data name="Name must be smaller than 256 characters." xml:space="preserve">
|
||||
<value>El nombre debe contener menos de 256 caracteres.</value>
|
||||
<comment>Name must be smaller than 256 characters.</comment>
|
||||
</data>
|
||||
<data name="Both name and surname must be known and filled, or both unknown." xml:space="preserve">
|
||||
<value>Tanto el nombre como el/los apellido(s) deben rellenarse, or ser desconocidos.</value>
|
||||
<comment>Both name and surname must be known and filled, or both unknown.</comment>
|
||||
</data>
|
||||
<data name="Surname must be smaller than 256 characters." xml:space="preserve">
|
||||
<value>El/los apellido(s) deben contener menos de 256 caracteres.</value>
|
||||
<comment>Surname must be smaller than 256 characters.</comment>
|
||||
</data>
|
||||
<data name="Alias must be smaller than 256 characters." xml:space="preserve">
|
||||
<value>El alias debe contener menos de 256 caracteres.</value>
|
||||
<comment>Alias must be smaller than 256 characters.</comment>
|
||||
</data>
|
||||
<data name="Display name must be smaller than 256 characters." xml:space="preserve">
|
||||
<value>El nombre para mostrar debe contener menos de 256 caracteres.</value>
|
||||
<comment>Display name must be smaller than 256 characters.</comment>
|
||||
</data>
|
||||
<data name="Birth date must be before today." xml:space="preserve">
|
||||
<value>La fecha de nacimiento debe ser anterior a hoy.</value>
|
||||
<comment>Birth date must be before today.</comment>
|
||||
</data>
|
||||
<data name="Birth date must be before death date." xml:space="preserve">
|
||||
<value>La fecha de nacimiento debe ser anterior a la de fallecimiento</value>
|
||||
<comment>Birth date must be before death date.</comment>
|
||||
</data>
|
||||
<data name="Death date must be before today." xml:space="preserve">
|
||||
<value>La fecha de fallecimiento debe ser anterior a hoy.</value>
|
||||
<comment>Death date must be before today.</comment>
|
||||
</data>
|
||||
<data name="Death date must be after birth date." xml:space="preserve">
|
||||
<value>La fecha de fallecimiento debe ser posterior a la de nacimiento.</value>
|
||||
<comment>Death date must be after birth date.</comment>
|
||||
</data>
|
||||
<data name="Webpage must be smaller than 255 characters." xml:space="preserve">
|
||||
<value>La página web debe contener menos de 255 caracteres.</value>
|
||||
<comment>Webpage must be smaller than 255 characters.</comment>
|
||||
</data>
|
||||
<data name="Twitter handle must be smaller than 255 characters." xml:space="preserve">
|
||||
<value>El identificador de Twitter debe contener menos de 255 caracteres.</value>
|
||||
<comment>Twitter handle must be smaller than 255 characters.</comment>
|
||||
</data>
|
||||
<data name="Invalid Twitter handle." xml:space="preserve">
|
||||
<value>Identificador de Twitter inválido.</value>
|
||||
<comment>Invalid Twitter handle.</comment>
|
||||
</data>
|
||||
<data name="Facebook username must be smaller than 256 characters." xml:space="preserve">
|
||||
<value>El nombre de usuario de Facebook debe contener menos de 256 caracteres.</value>
|
||||
<comment>Facebook username must be smaller than 256 characters.</comment>
|
||||
</data>
|
||||
</root>
|
||||
@@ -23,7 +23,35 @@ namespace Marechai.Services
|
||||
DisplayName = p.DisplayName
|
||||
}).ToListAsync();
|
||||
|
||||
public async Task<Person> GetAsync(int id) => await _context.People.FindAsync(id);
|
||||
public async Task<PersonViewModel> GetAsync(int id) =>
|
||||
await _context.People.Where(p => p.Id == id).Select(p => new PersonViewModel
|
||||
{
|
||||
Id = p.Id, Name = p.Name, Surname = p.Surname, CountryOfBirthId = p.CountryOfBirthId,
|
||||
BirthDate = p.BirthDate, DeathDate = p.DeathDate, Webpage = p.Webpage, Twitter = p.Twitter,
|
||||
Facebook = p.Facebook, Photo = p.Photo, Alias = p.Alias, DisplayName = p.DisplayName
|
||||
}).FirstOrDefaultAsync();
|
||||
|
||||
public async Task UpdateAsync(PersonViewModel viewModel)
|
||||
{
|
||||
Person model = await _context.People.FindAsync(viewModel.Id);
|
||||
|
||||
if(model is null)
|
||||
return;
|
||||
|
||||
model.Name = viewModel.Name;
|
||||
model.Surname = viewModel.Surname;
|
||||
model.CountryOfBirthId = viewModel.CountryOfBirthId;
|
||||
model.BirthDate = viewModel.BirthDate;
|
||||
model.DeathDate = viewModel.DeathDate;
|
||||
model.Webpage = viewModel.Webpage;
|
||||
model.Twitter = viewModel.Twitter;
|
||||
model.Facebook = viewModel.Facebook;
|
||||
model.Photo = viewModel.Photo;
|
||||
model.Alias = viewModel.Alias;
|
||||
model.DisplayName = viewModel.DisplayName;
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(int id)
|
||||
{
|
||||
|
||||
@@ -4,17 +4,18 @@ namespace Marechai.ViewModels
|
||||
{
|
||||
public class PersonViewModel : BaseViewModel<int>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Surname { get; set; }
|
||||
public string CountryOfBirth { get; set; }
|
||||
public DateTime BirthDate { get; set; }
|
||||
public DateTime? DeathDate { get; set; }
|
||||
public string Webpage { get; set; }
|
||||
public string Twitter { get; set; }
|
||||
public string Facebook { get; set; }
|
||||
public Guid Photo { get; set; }
|
||||
public string Alias { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Surname { get; set; }
|
||||
public string CountryOfBirth { get; set; }
|
||||
public DateTime BirthDate { get; set; }
|
||||
public DateTime? DeathDate { get; set; }
|
||||
public string Webpage { get; set; }
|
||||
public string Twitter { get; set; }
|
||||
public string Facebook { get; set; }
|
||||
public Guid Photo { get; set; }
|
||||
public string Alias { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
public short? CountryOfBirthId { get; set; }
|
||||
|
||||
public string FullName => DisplayName ?? Alias ?? $"{Name} {Surname}";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user