Add document admin page.

This commit is contained in:
2020-08-07 22:30:34 +01:00
parent db16a77988
commit 30e0408edb
10 changed files with 907 additions and 1 deletions

View File

@@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<Version>4.0.0.1801</Version> <Version>4.0.0.1803</Version>
<Company>Canary Islands Computer Museum</Company> <Company>Canary Islands Computer Museum</Company>
<Copyright>Copyright © 2003-2020 Natalia Portillo</Copyright> <Copyright>Copyright © 2003-2020 Natalia Portillo</Copyright>
<Product>Canary Islands Computer Museum Website</Product> <Product>Canary Islands Computer Museum Website</Product>

View File

@@ -0,0 +1,138 @@
@{
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// 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<DocumentsService>
@inject IStringLocalizer<DocumentsService> L
@inject Iso31661NumericService CountriesService
@inject NavigationManager NavigationManager
@inject IWebHostEnvironment Host
@inject IJSRuntime JSRuntime
@inject Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> UserManager
@inject AuthenticationStateProvider AuthenticationStateProvider
@attribute [Authorize(Roles = "UberAdmin, Admin")]
<h3>@L["Document details"]</h3>
<hr />
@if (!_loaded)
{
<p align="center">@L["Loading..."]</p>
return;
}
<div>
<Field>
<FieldLabel>@L["Title using latin script"]</FieldLabel>
<Validation Validator="@ValidateTitle">
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Title">
<Feedback>
<ValidationError>@L["Please enter a valid title."]</ValidationError>
</Feedback>
</TextEdit>
</Validation>
</Field>
@if (_editing || _model.NativeTitle != null)
{
<Field>
<FieldLabel>@L["Native title, that is, title using native script (cyrillic, chinese, etc)"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownNativeTitle">@L["Unknown (native title)"]</Check>
}
@if (!_editing ||
!_unknownNativeTitle)
{
<Validation Validator="@ValidateNativeTitle">
<TextEdit Disabled="!_editing" @bind-Text="@_model.NativeTitle">
<Feedback>
<ValidationError>@L["Please enter a valid native title."]</ValidationError>
</Feedback>
</TextEdit>
</Validation>
}
</Field>
}
@if (_editing || _model.Published != null)
{
<Field>
<FieldLabel>@L["Published"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownPublished">@L["Unknown (publication date)"]</Check>
}
@if (!_editing || !_unknownPublished)
{
<Validation Validator="@ValidatePublished">
<DateEdit TValue="DateTime?" ReadOnly="!_editing" @bind-Date="@_model.Published" >
<Feedback>
<ValidationError>@L["Please enter a valid publication date."]</ValidationError>
</Feedback>
</DateEdit>
</Validation>
}
</Field>
}
@if (_editing || _model.CountryId != null)
{
<Field>
<FieldLabel>@L["Country of publication"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownCountry">@L["Unknown (country of publication)"]</Check>
}
@if (!_editing ||
!_unknownCountry)
{
<Select Disabled="!_editing" TValue="short?" @bind-SelectedValue="@_model.CountryId">
@foreach (var country in _countries)
{
<SelectItem TValue="short?" Value="@country.Id">@country.Name</SelectItem>
}
</Select>
}
</Field>
}
</div>
<div>
@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/documents" class="btn btn-secondary">@L["Back to list"]</a>
</div>

View File

@@ -0,0 +1,151 @@
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// 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<Iso31661Numeric> _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);
}
}

View File

@@ -0,0 +1,104 @@
@{
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2003-2020 Natalia Portillo
*******************************************************************************/
}
@page "/admin/documents"
@using Marechai.Database.Models
@inherits OwningComponentBase<DocumentsService>
@inject IStringLocalizer<DocumentsService> L
@inject Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> UserManager
@inject AuthenticationStateProvider AuthenticationStateProvider
@attribute [Authorize(Roles = "UberAdmin, Admin")]
<h3>@L["Documents"]</h3>
@if (_documents is null)
{
<p>@L["Loading..."]</p>
return;
}
<p>
<a class="btn btn-primary" href="/admin/documents/create">@L["Create new"]</a>
</p>
<table class="table table-striped">
<thead>
<tr>
<th>
@L["Title"]
</th>
<th>
@L["Native title"]
</th>
<th>
@L["Published"]
</th>
<th>
@L["Country"]
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in _documents)
{
<tr>
<td>
@item.Title
</td>
<td>
@item.NativeTitle
</td>
<td>
@($"{item.Published:d}")
</td>
<td>
@item.Country
</td>
<td>
<a class="btn btn-primary" href="/admin/documents/details/@item.Id">@L["Details"]</a>
<a class="btn btn-secondary" href="/admin/documents/edit/@item.Id">@L["Edit"]</a>
<Button Color="Color.Danger" Clicked="() => {ShowModal(item.Id);}">@L["Delete"]</Button>
</td>
</tr>
}
</tbody>
</table>
<Modal @ref="_frmDelete" IsCentered="true" Closing="@ModalClosing">
<ModalBackdrop/>
<ModalContent Centered="true">
<ModalHeader>
<ModalTitle>@L["Delete document"]</ModalTitle>
<CloseButton Clicked="@HideModal"/>
</ModalHeader>
<ModalBody>
<Text>@string.Format(@L["Are you sure you want to delete the document {0}?"], _currentDocument?.Title)</Text>
</ModalBody>
<ModalFooter>
<Button Color="Color.Primary" Clicked="@HideModal" Disabled="@_deleteInProgress">@L["Cancel"]</Button>
<Button Color="Color.Danger" Clicked="@ConfirmDelete" Disabled="@_deleteInProgress">@L["Delete"]</Button>
</ModalFooter>
</ModalContent>
</Modal>

View File

@@ -0,0 +1,88 @@
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// 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<DocumentViewModel> _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;
}
}

View File

@@ -0,0 +1,95 @@
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Are you sure you want to delete the document {0}?" xml:space="preserve">
<value>Are you sure you want to delete the document {0}?</value>
</data>
<data name="Documents" xml:space="preserve">
<value>Documents</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="Country" xml:space="preserve">
<value>Country</value>
</data>
<data name="Create new" xml:space="preserve">
<value>Create new</value>
</data>
<data name="Delete" xml:space="preserve">
<value>Delete</value>
</data>
<data name="Delete document" xml:space="preserve">
<value>Delete document</value>
</data>
<data name="Details" xml:space="preserve">
<value>Details</value>
</data>
<data name="Edit" xml:space="preserve">
<value>Edit</value>
</data>
<data name="ISBN" xml:space="preserve">
<value>ISBN</value>
</data>
<data name="Loading..." xml:space="preserve">
<value>Loading...</value>
</data>
<data name="Native title" xml:space="preserve">
<value>Native title</value>
</data>
<data name="Published" xml:space="preserve">
<value>Published</value>
</data>
<data name="Title" xml:space="preserve">
<value>Title</value>
</data>
<data name="Document details" xml:space="preserve">
<value>Document details</value>
</data>
<data name="Title using latin script" xml:space="preserve">
<value>Title using latin script</value>
</data>
<data name="Please enter a valid title." xml:space="preserve">
<value>Please enter a valid title.</value>
</data>
<data name="Native title, that is, title using native script (cyrillic, chinese, etc)" xml:space="preserve">
<value>Native title, that is, title using native script (cyrillic, chinese, etc)</value>
</data>
<data name="Unknown (native title)" xml:space="preserve">
<value>Unknown</value>
</data>
<data name="Please enter a valid native title." xml:space="preserve">
<value>Please enter a valid native title.</value>
</data>
<data name="Unknown (publication date)" xml:space="preserve">
<value>Unknown</value>
</data>
<data name="Please enter a valid publication date." xml:space="preserve">
<value>Please enter a valid publication date.</value>
</data>
<data name="Country of publication" xml:space="preserve">
<value>Country of publication</value>
</data>
<data name="Back to list" xml:space="preserve">
<value>Back to list</value>
</data>
<data name="Title must be smaller than 256 characters." xml:space="preserve">
<value>Title must be smaller than 256 characters.</value>
</data>
<data name="Native title must be smaller than 256 characters." xml:space="preserve">
<value>Native title must be smaller than 256 characters.</value>
</data>
<data name="Unknown (country of publication)" xml:space="preserve">
<value>Unknown</value>
</data>
</root>

View File

@@ -0,0 +1,211 @@
<?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="Documents" xml:space="preserve">
<value>Libros</value>
<comment>Documents</comment>
</data>
<data name="Loading..." xml:space="preserve">
<value>Cargando...</value>
<comment>Message that appears while data is being loaded from database</comment>
</data>
<data name="Country" xml:space="preserve">
<value>País</value>
<comment>Country where the document was published</comment>
</data>
<data name="Details" xml:space="preserve">
<value>Detalles</value>
<comment>Details</comment>
</data>
<data name="Edit" xml:space="preserve">
<value>Editar</value>
<comment>Edit</comment>
</data>
<data name="Delete" xml:space="preserve">
<value>Eliminar</value>
<comment>Delete</comment>
</data>
<data name="Delete document" xml:space="preserve">
<value>Eliminar libro</value>
<comment>Delete document</comment>
</data>
<data name="Are you sure you want to delete the document {0}?" xml:space="preserve">
<value>¿Está seguro de que desea borrar el libro {0}?</value>
<comment>{0} document name</comment>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancelar</value>
<comment>Cancel</comment>
</data>
<data name="Create new" xml:space="preserve">
<value>Crear nuevo</value>
</data>
<data name="Title" xml:space="preserve">
<value>Título</value>
</data>
<data name="Native title" xml:space="preserve">
<value>Título nativo</value>
</data>
<data name="Published" xml:space="preserve">
<value>Publicado el</value>
</data>
<data name="ISBN" xml:space="preserve">
<value>ISBN</value>
</data>
<data name="Document details" xml:space="preserve">
<value>Detalles de libro</value>
</data>
<data name="Title using latin script" xml:space="preserve">
<value>Título utilizando escritura latina</value>
</data>
<data name="Please enter a valid title." xml:space="preserve">
<value>Por favor introduce un título válido.</value>
</data>
<data name="Native title, that is, title using native script (cyrillic, chinese, etc)" xml:space="preserve">
<value>Título nativo, es decir, el título usando el sistema de escritura nativo (cirílico, chino, etc)</value>
</data>
<data name="Unknown (native title)" xml:space="preserve">
<value>Desconocido</value>
</data>
<data name="Please enter a valid native title." xml:space="preserve">
<value>Por favor introduce un título nativo válido.</value>
</data>
<data name="Unknown (publication date)" xml:space="preserve">
<value>Desconocida</value>
</data>
<data name="Please enter a valid publication date." xml:space="preserve">
<value>Por favor introduce una fecha de publicación válida.</value>
</data>
<data name="Country of publication" xml:space="preserve">
<value>País de publicación</value>
</data>
<data name="Unknown (country of publication)" xml:space="preserve">
<value>Desconocido</value>
</data>
<data name="Back to list" xml:space="preserve">
<value>Volver a la lista</value>
</data>
<data name="Title must be smaller than 256 characters." xml:space="preserve">
<value>El título debe contener menos de 256 caracteres.</value>
</data>
<data name="Native title must be smaller than 256 characters." xml:space="preserve">
<value>El título nativo debe contener menos de 256 caracteres.</value>
</data>
</root>

View File

@@ -0,0 +1,114 @@
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ 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 <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// 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<List<DocumentViewModel>> 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<DocumentViewModel> 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<long> 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<string> 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);
}
}
}

View File

@@ -71,6 +71,7 @@ namespace Marechai.Services
services.AddScoped<CurrencyInflationService>(); services.AddScoped<CurrencyInflationService>();
services.AddScoped<Iso4217Service>(); services.AddScoped<Iso4217Service>();
services.AddScoped<CurrencyPeggingService>(); services.AddScoped<CurrencyPeggingService>();
services.AddScoped<DocumentsService>();
} }
} }
} }

View File

@@ -0,0 +1,4 @@
namespace Marechai.ViewModels
{
public class DocumentViewModel : DocumentBaseViewModel {}
}