From 30e0408edb0ca013add5519a36dc25dca7f87d1b Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Fri, 7 Aug 2020 22:30:34 +0100 Subject: [PATCH] Add document admin page. --- Marechai/Marechai.csproj | 2 +- Marechai/Pages/Admin/Details/Document.razor | 138 ++++++++++++ .../Pages/Admin/Details/Document.razor.cs | 151 +++++++++++++ Marechai/Pages/Admin/Documents.razor | 104 +++++++++ Marechai/Pages/Admin/Documents.razor.cs | 88 ++++++++ .../Services/DocumentsService.en.resx | 95 ++++++++ .../Services/DocumentsService.es.resx | 211 ++++++++++++++++++ Marechai/Services/DocumentsService.cs | 114 ++++++++++ Marechai/Services/Register.cs | 1 + Marechai/ViewModels/DocumentViewModel.cs | 4 + 10 files changed, 907 insertions(+), 1 deletion(-) create mode 100644 Marechai/Pages/Admin/Details/Document.razor create mode 100644 Marechai/Pages/Admin/Details/Document.razor.cs create mode 100644 Marechai/Pages/Admin/Documents.razor create mode 100644 Marechai/Pages/Admin/Documents.razor.cs create mode 100644 Marechai/Resources/Services/DocumentsService.en.resx create mode 100644 Marechai/Resources/Services/DocumentsService.es.resx create mode 100644 Marechai/Services/DocumentsService.cs create mode 100644 Marechai/ViewModels/DocumentViewModel.cs diff --git a/Marechai/Marechai.csproj b/Marechai/Marechai.csproj index 8552f77b..ca4f69d1 100644 --- a/Marechai/Marechai.csproj +++ b/Marechai/Marechai.csproj @@ -2,7 +2,7 @@ netcoreapp3.1 - 4.0.0.1801 + 4.0.0.1803 Canary Islands Computer Museum Copyright © 2003-2020 Natalia Portillo Canary Islands Computer Museum Website diff --git a/Marechai/Pages/Admin/Details/Document.razor b/Marechai/Pages/Admin/Details/Document.razor new file mode 100644 index 00000000..d54a768e --- /dev/null +++ b/Marechai/Pages/Admin/Details/Document.razor @@ -0,0 +1,138 @@ +@{ +/****************************************************************************** +// 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-2020 Natalia Portillo +*******************************************************************************/ +} + +@page "/admin/documents/details/{Id:long}" +@page "/admin/documents/edit/{Id:long}" +@page "/admin/documents/create" +@using Marechai.Database +@using Marechai.Database.Models +@inherits OwningComponentBase +@inject IStringLocalizer L +@inject Iso31661NumericService CountriesService +@inject NavigationManager NavigationManager +@inject IWebHostEnvironment Host +@inject IJSRuntime JSRuntime +@inject Microsoft.AspNetCore.Identity.UserManager UserManager +@inject AuthenticationStateProvider AuthenticationStateProvider +@attribute [Authorize(Roles = "UberAdmin, Admin")] + + +

@L["Document details"]

+
+ +@if (!_loaded) +{ +

@L["Loading..."]

+ + return; +} + +
+ + @L["Title using latin script"] + + + + @L["Please enter a valid title."] + + + + + @if (_editing || _model.NativeTitle != null) + { + + @L["Native title, that is, title using native script (cyrillic, chinese, etc)"] + @if (_editing) + { + @L["Unknown (native title)"] + } + @if (!_editing || + !_unknownNativeTitle) + { + + + + @L["Please enter a valid native title."] + + + + } + + } + @if (_editing || _model.Published != null) + { + + @L["Published"] + @if (_editing) + { + @L["Unknown (publication date)"] + } + @if (!_editing || !_unknownPublished) + { + + + + @L["Please enter a valid publication date."] + + + + } + + } + @if (_editing || _model.CountryId != null) + { + + @L["Country of publication"] + @if (_editing) + { + @L["Unknown (country of publication)"] + } + @if (!_editing || + !_unknownCountry) + { + + } + + } +
+
+ @if (!_editing) + { + + } + else + { + + + } + @L["Back to list"] +
diff --git a/Marechai/Pages/Admin/Details/Document.razor.cs b/Marechai/Pages/Admin/Details/Document.razor.cs new file mode 100644 index 00000000..54b37310 --- /dev/null +++ b/Marechai/Pages/Admin/Details/Document.razor.cs @@ -0,0 +1,151 @@ +/****************************************************************************** +// 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-2020 Natalia Portillo +*******************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Blazorise; +using Marechai.Database.Models; +using Marechai.Shared; +using Marechai.ViewModels; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Authorization; + +namespace Marechai.Pages.Admin.Details +{ + public partial class Document + { + AuthenticationState _authState; + List _countries; + bool _creating; + bool _editing; + bool _loaded; + DocumentViewModel _model; + bool _unknownCountry; + bool _unknownNativeTitle; + bool _unknownPublished; + + [Parameter] + public long Id { get; set; } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if(_loaded) + return; + + _loaded = true; + + _creating = NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant(). + StartsWith("admin/documents/create", StringComparison.InvariantCulture); + + if(Id <= 0 && + !_creating) + return; + + _countries = await CountriesService.GetAsync(); + _model = _creating ? new DocumentViewModel() : await Service.GetAsync(Id); + _authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); + + _editing = _creating || NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant(). + StartsWith("admin/documents/edit/", + StringComparison.InvariantCulture); + + if(_editing) + SetCheckboxes(); + + StateHasChanged(); + } + + void SetCheckboxes() + { + _unknownCountry = !_model.CountryId.HasValue; + _unknownNativeTitle = string.IsNullOrWhiteSpace(_model.NativeTitle); + _unknownPublished = !_model.Published.HasValue; + } + + void OnEditClicked() + { + _editing = true; + SetCheckboxes(); + StateHasChanged(); + } + + async void OnCancelClicked() + { + _editing = false; + + if(_creating) + { + NavigationManager.ToBaseRelativePath("admin/documents"); + + return; + } + + _model = await Service.GetAsync(Id); + SetCheckboxes(); + StateHasChanged(); + } + + async void OnSaveClicked() + { + if(_unknownNativeTitle) + _model.NativeTitle = null; + else if(string.IsNullOrWhiteSpace(_model.NativeTitle)) + return; + + if(_unknownCountry) + _model.CountryId = null; + else if(_model.CountryId < 0) + return; + + if(_unknownPublished) + _model.Published = null; + else if(_model.Published?.Date >= DateTime.UtcNow.Date) + return; + + if(string.IsNullOrWhiteSpace(_model.Title)) + return; + + if(_creating) + Id = await Service.CreateAsync(_model, (await UserManager.GetUserAsync(_authState.User)).Id); + else + await Service.UpdateAsync(_model, (await UserManager.GetUserAsync(_authState.User)).Id); + + _editing = false; + _creating = false; + _model = await Service.GetAsync(Id); + SetCheckboxes(); + StateHasChanged(); + } + + void ValidateTitle(ValidatorEventArgs e) => + Validators.ValidateString(e, L["Title must be smaller than 256 characters."], 256); + + void ValidatePublished(ValidatorEventArgs e) => Validators.ValidateDate(e); + + void ValidateNativeTitle(ValidatorEventArgs e) => + Validators.ValidateString(e, L["Native title must be smaller than 256 characters."], 256); + } +} \ No newline at end of file diff --git a/Marechai/Pages/Admin/Documents.razor b/Marechai/Pages/Admin/Documents.razor new file mode 100644 index 00000000..05db5849 --- /dev/null +++ b/Marechai/Pages/Admin/Documents.razor @@ -0,0 +1,104 @@ +@{ +/****************************************************************************** +// 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-2020 Natalia Portillo +*******************************************************************************/ +} + +@page "/admin/documents" +@using Marechai.Database.Models +@inherits OwningComponentBase +@inject IStringLocalizer L +@inject Microsoft.AspNetCore.Identity.UserManager UserManager +@inject AuthenticationStateProvider AuthenticationStateProvider +@attribute [Authorize(Roles = "UberAdmin, Admin")] +

@L["Documents"]

+@if (_documents is null) +{ +

@L["Loading..."]

+ + return; +} +

+ @L["Create new"] +

+ + + + + + + + + + + + @foreach (var item in _documents) + { + + + + + + + + } + +
+ @L["Title"] + + @L["Native title"] + + @L["Published"] + + @L["Country"] +
+ @item.Title + + @item.NativeTitle + + @($"{item.Published:d}") + + @item.Country + + @L["Details"] + @L["Edit"] + +
+ + + + + + @L["Delete document"] + + + + @string.Format(@L["Are you sure you want to delete the document {0}?"], _currentDocument?.Title) + + + + + + + diff --git a/Marechai/Pages/Admin/Documents.razor.cs b/Marechai/Pages/Admin/Documents.razor.cs new file mode 100644 index 00000000..2b9319b6 --- /dev/null +++ b/Marechai/Pages/Admin/Documents.razor.cs @@ -0,0 +1,88 @@ +/****************************************************************************** +// 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-2020 Natalia Portillo +*******************************************************************************/ + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Blazorise; +using Marechai.ViewModels; +using Microsoft.AspNetCore.Components.Authorization; + +namespace Marechai.Pages.Admin +{ + public partial class Documents + { + DocumentViewModel _currentDocument; + bool _deleteInProgress; + List _documents; + Modal _frmDelete; + bool _loaded; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if(_loaded) + return; + + _documents = await Service.GetAsync(); + _loaded = true; + StateHasChanged(); + } + + void ShowModal(long itemId) + { + _currentDocument = _documents.FirstOrDefault(n => n.Id == itemId); + _frmDelete.Show(); + } + + void HideModal() => _frmDelete.Hide(); + + async void ConfirmDelete() + { + if(_currentDocument is null) + return; + + _deleteInProgress = true; + _documents = null; + AuthenticationState authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); + + // Yield thread to let UI to update + await Task.Yield(); + + await Service.DeleteAsync(_currentDocument.Id, (await UserManager.GetUserAsync(authState.User)).Id); + _documents = await Service.GetAsync(); + + _deleteInProgress = false; + _frmDelete.Hide(); + + // Yield thread to let UI to update + await Task.Yield(); + + // Tell we finished loading + StateHasChanged(); + } + + void ModalClosing(ModalClosingEventArgs obj) => _currentDocument = null; + } +} \ No newline at end of file diff --git a/Marechai/Resources/Services/DocumentsService.en.resx b/Marechai/Resources/Services/DocumentsService.en.resx new file mode 100644 index 00000000..a756bc5a --- /dev/null +++ b/Marechai/Resources/Services/DocumentsService.en.resx @@ -0,0 +1,95 @@ + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Are you sure you want to delete the document {0}? + + + Documents + + + Cancel + + + Country + + + Create new + + + Delete + + + Delete document + + + Details + + + Edit + + + ISBN + + + Loading... + + + Native title + + + Published + + + Title + + + Document details + + + Title using latin script + + + Please enter a valid title. + + + Native title, that is, title using native script (cyrillic, chinese, etc) + + + Unknown + + + Please enter a valid native title. + + + Unknown + + + Please enter a valid publication date. + + + Country of publication + + + Back to list + + + Title must be smaller than 256 characters. + + + Native title must be smaller than 256 characters. + + + Unknown + + \ No newline at end of file diff --git a/Marechai/Resources/Services/DocumentsService.es.resx b/Marechai/Resources/Services/DocumentsService.es.resx new file mode 100644 index 00000000..dae1cc0b --- /dev/null +++ b/Marechai/Resources/Services/DocumentsService.es.resx @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Libros + Documents + + + Cargando... + Message that appears while data is being loaded from database + + + País + Country where the document was published + + + Detalles + Details + + + Editar + Edit + + + Eliminar + Delete + + + Eliminar libro + Delete document + + + ¿Está seguro de que desea borrar el libro {0}? + {0} document name + + + Cancelar + Cancel + + + Crear nuevo + + + Título + + + Título nativo + + + Publicado el + + + ISBN + + + Detalles de libro + + + Título utilizando escritura latina + + + Por favor introduce un título válido. + + + Título nativo, es decir, el título usando el sistema de escritura nativo (cirílico, chino, etc) + + + Desconocido + + + Por favor introduce un título nativo válido. + + + Desconocida + + + Por favor introduce una fecha de publicación válida. + + + País de publicación + + + Desconocido + + + Volver a la lista + + + El título debe contener menos de 256 caracteres. + + + El título nativo debe contener menos de 256 caracteres. + + \ No newline at end of file diff --git a/Marechai/Services/DocumentsService.cs b/Marechai/Services/DocumentsService.cs new file mode 100644 index 00000000..2502e96e --- /dev/null +++ b/Marechai/Services/DocumentsService.cs @@ -0,0 +1,114 @@ +/****************************************************************************** +// 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-2020 Natalia Portillo +*******************************************************************************/ + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Marechai.Database.Models; +using Marechai.ViewModels; +using Microsoft.EntityFrameworkCore; + +namespace Marechai.Services +{ + public class DocumentsService + { + readonly MarechaiContext _context; + + public DocumentsService(MarechaiContext context) => _context = context; + + public async Task> GetAsync() => await _context. + Documents.OrderBy(b => b.NativeTitle). + ThenBy(b => b.Published).ThenBy(b => b.Title). + Select(b => new DocumentViewModel + { + Id = b.Id, + Title = b.Title, + NativeTitle = b.NativeTitle, + Published = b.Published, + Synopsis = b.Synopsis, + CountryId = b.CountryId, + Country = b.Country.Name + }).ToListAsync(); + + public async Task GetAsync(long id) => await _context.Documents.Where(b => b.Id == id). + Select(b => new DocumentViewModel + { + Id = b.Id, + Title = b.Title, + NativeTitle = b.NativeTitle, + Published = b.Published, + Synopsis = b.Synopsis, + CountryId = b.CountryId, + Country = b.Country.Name + }).FirstOrDefaultAsync(); + + public async Task UpdateAsync(DocumentViewModel viewModel, string userId) + { + Document model = await _context.Documents.FindAsync(viewModel.Id); + + if(model is null) + return; + + model.Title = viewModel.Title; + model.NativeTitle = viewModel.NativeTitle; + model.Published = viewModel.Published; + model.Synopsis = viewModel.Synopsis; + model.CountryId = viewModel.CountryId; + await _context.SaveChangesWithUserAsync(userId); + } + + public async Task CreateAsync(DocumentViewModel viewModel, string userId) + { + var model = new Document + { + Title = viewModel.Title, + NativeTitle = viewModel.NativeTitle, + Published = viewModel.Published, + Synopsis = viewModel.Synopsis, + CountryId = viewModel.CountryId + }; + + await _context.Documents.AddAsync(model); + await _context.SaveChangesWithUserAsync(userId); + + return model.Id; + } + + public async Task GetSynopsisTextAsync(int id) => + (await _context.Documents.FirstOrDefaultAsync(d => d.Id == id))?.Synopsis; + + public async Task DeleteAsync(long id, string userId) + { + Document item = await _context.Documents.FindAsync(id); + + if(item is null) + return; + + _context.Documents.Remove(item); + + await _context.SaveChangesWithUserAsync(userId); + } + } +} \ No newline at end of file diff --git a/Marechai/Services/Register.cs b/Marechai/Services/Register.cs index 9505611a..c2547438 100644 --- a/Marechai/Services/Register.cs +++ b/Marechai/Services/Register.cs @@ -71,6 +71,7 @@ namespace Marechai.Services services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } } } \ No newline at end of file diff --git a/Marechai/ViewModels/DocumentViewModel.cs b/Marechai/ViewModels/DocumentViewModel.cs new file mode 100644 index 00000000..aa95e7b7 --- /dev/null +++ b/Marechai/ViewModels/DocumentViewModel.cs @@ -0,0 +1,4 @@ +namespace Marechai.ViewModels +{ + public class DocumentViewModel : DocumentBaseViewModel {} +} \ No newline at end of file