Add software family admin page.

This commit is contained in:
2020-08-08 18:57:22 +01:00
parent f24810e808
commit b118afce1e
14 changed files with 866 additions and 1 deletions

View File

@@ -35,6 +35,7 @@ namespace Marechai.Database.Models
public string Name { get; set; }
public DateTime? Introduced { get; set; }
public virtual SoftwareFamily Parent { get; set; }
public ulong? ParentId { get; set; }
public virtual ICollection<SoftwareFamily> Children { get; set; }
public virtual ICollection<CompaniesBySoftwareFamily> Companies { get; set; }

View File

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

View File

@@ -0,0 +1,116 @@
@{
/******************************************************************************
// 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/software_families/details/{Id:ulong}"
@page "/admin/software_families/edit/{Id:ulong}"
@page "/admin/software_families/create"
@using Marechai.Database
@using Marechai.Database.Models
@inherits OwningComponentBase<SoftwareFamiliesService>
@inject IStringLocalizer<SoftwareFamiliesService> L
@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["Software family details"]</h3>
<hr />
@if (!_loaded)
{
<p align="center">@L["Loading..."]</p>
return;
}
<div>
<Field>
<FieldLabel>@L["Name"]</FieldLabel>
<Validation Validator="@ValidateName">
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Name">
<Feedback>
<ValidationError>@L["Please enter a valid name."]</ValidationError>
</Feedback>
</TextEdit>
</Validation>
</Field>
@if (_editing || _model.Introduced != null)
{
<Field>
<FieldLabel>@L["Introduced"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownIntroduced">@L["Unknown (introduction date)"]</Check>
}
@if (!_editing || !_unknownIntroduced)
{
<Validation Validator="@ValidateIntroduced">
<DateEdit TValue="DateTime?" ReadOnly="!_editing" @bind-Date="@_model.Introduced" >
<Feedback>
<ValidationError>@L["Please enter a valid introduction date."]</ValidationError>
</Feedback>
</DateEdit>
</Validation>
}
</Field>
}
@if (_editing || _model.ParentId != null)
{
<Field>
<FieldLabel>@L["Parent software family"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownParent">@L["Unknown or none (parent software family)"]</Check>
}
@if (!_editing ||
!_unknownParent)
{
<Select Disabled="!_editing" TValue="ulong?" @bind-SelectedValue="@_model.ParentId">
@foreach (var family in _softwareFamilies)
{
<SelectItem TValue="ulong?" Value="@family.Id">@family.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/software_families" class="btn btn-secondary">@L["Back to list"]</a>
</div>

View File

@@ -0,0 +1,141 @@
/******************************************************************************
// 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.Shared;
using Marechai.ViewModels;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
namespace Marechai.Pages.Admin.Details
{
public partial class SoftwareFamily
{
AuthenticationState _authState;
bool _creating;
bool _editing;
bool _loaded;
SoftwareFamilyViewModel _model;
List<SoftwareFamilyViewModel> _softwareFamilies;
bool _unknownIntroduced;
bool _unknownParent;
[Parameter]
public ulong Id { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(_loaded)
return;
_loaded = true;
_creating = NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant().
StartsWith("admin/software_families/create",
StringComparison.InvariantCulture);
if(Id <= 0 &&
!_creating)
return;
_softwareFamilies = await Service.GetAsync();
_model = _creating ? new SoftwareFamilyViewModel() : await Service.GetAsync(Id);
_authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
_editing = _creating || NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant().
StartsWith("admin/software_families/edit/",
StringComparison.InvariantCulture);
if(_editing)
SetCheckboxes();
StateHasChanged();
}
void SetCheckboxes()
{
_unknownParent = !_model.ParentId.HasValue;
_unknownIntroduced = !_model.Introduced.HasValue;
}
void OnEditClicked()
{
_editing = true;
SetCheckboxes();
StateHasChanged();
}
async void OnCancelClicked()
{
_editing = false;
if(_creating)
{
NavigationManager.ToBaseRelativePath("admin/software_families");
return;
}
_model = await Service.GetAsync(Id);
SetCheckboxes();
StateHasChanged();
}
async void OnSaveClicked()
{
if(_unknownParent)
_model.ParentId = null;
else if(_model.ParentId < 1)
return;
if(_unknownIntroduced)
_model.Introduced = null;
else if(_model.Introduced?.Date >= DateTime.UtcNow.Date)
return;
if(string.IsNullOrWhiteSpace(_model.Name))
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 ValidateName(ValidatorEventArgs e) =>
Validators.ValidateString(e, L["Name must be smaller than 256 characters."], 256);
void ValidateIntroduced(ValidatorEventArgs e) => Validators.ValidateDate(e);
}
}

View File

@@ -128,3 +128,11 @@
</li>
</ul>
</div>
<div class="content">
<h3>@L["Administrative pages for software"]</h3>
<ul>
<li>
<a href="/admin/software_families">@L["Software families"]</a>
</li>
</ul>
</div>

View File

@@ -0,0 +1,98 @@
@{
/******************************************************************************
// 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/software_families"
@using Marechai.Database.Models
@inherits OwningComponentBase<SoftwareFamiliesService>
@inject IStringLocalizer<SoftwareFamiliesService> L
@inject Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> UserManager
@inject AuthenticationStateProvider AuthenticationStateProvider
@attribute [Authorize(Roles = "UberAdmin, Admin")]
<h3>@L["Software families"]</h3>
@if (_softwareFamilies is null)
{
<p>@L["Loading..."]</p>
return;
}
<p>
<a class="btn btn-primary" href="/admin/software_families/create">@L["Create new"]</a>
</p>
<table class="table table-striped">
<thead>
<tr>
<th>
@L["Name"]
</th>
<th>
@L["Introduced"]
</th>
<th>
@L["Parent"]
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in _softwareFamilies)
{
<tr>
<td>
@item.Name
</td>
<td>
@($"{item.Introduced:d}")
</td>
<td>
@item.Parent
</td>
<td>
<a class="btn btn-primary" href="/admin/software_families/details/@item.Id">@L["Details"]</a>
<a class="btn btn-secondary" href="/admin/software_families/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 software family"]</ModalTitle>
<CloseButton Clicked="@HideModal"/>
</ModalHeader>
<ModalBody>
<Text>@string.Format(@L["Are you sure you want to delete the software family {0}?"], _currentSoftwareFamily?.Name)</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 SoftwareFamilies
{
SoftwareFamilyViewModel _currentSoftwareFamily;
bool _deleteInProgress;
Modal _frmDelete;
bool _loaded;
List<SoftwareFamilyViewModel> _softwareFamilies;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(_loaded)
return;
_softwareFamilies = await Service.GetAsync();
_loaded = true;
StateHasChanged();
}
void ShowModal(ulong itemId)
{
_currentSoftwareFamily = _softwareFamilies.FirstOrDefault(n => n.Id == itemId);
_frmDelete.Show();
}
void HideModal() => _frmDelete.Hide();
async void ConfirmDelete()
{
if(_currentSoftwareFamily is null)
return;
_deleteInProgress = true;
_softwareFamilies = null;
AuthenticationState authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
// Yield thread to let UI to update
await Task.Yield();
await Service.DeleteAsync(_currentSoftwareFamily.Id, (await UserManager.GetUserAsync(authState.User)).Id);
_softwareFamilies = 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) => _currentSoftwareFamily = null;
}
}

View File

@@ -38,4 +38,10 @@
<data name="Magazine issues" xml:space="preserve">
<value>Magazine issues</value>
</data>
<data name="Administrative pages for software" xml:space="preserve">
<value>Administrative pages for software</value>
</data>
<data name="Software families" xml:space="preserve">
<value />
</data>
</root>

View File

@@ -237,4 +237,10 @@
<data name="Magazine issues" xml:space="preserve">
<value>Números de revistas</value>
</data>
<data name="Administrative pages for software" xml:space="preserve">
<value>Páginas de administración para software</value>
</data>
<data name="Software families" xml:space="preserve">
<value>Familias de software</value>
</data>
</root>

View File

@@ -0,0 +1,77 @@
<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="Software families" xml:space="preserve">
<value>Software families</value>
</data>
<data name="Loading..." xml:space="preserve">
<value>Loading...</value>
</data>
<data name="Create new" xml:space="preserve">
<value>Create new</value>
</data>
<data name="Name" xml:space="preserve">
<value>Name</value>
</data>
<data name="Introduced" xml:space="preserve">
<value>Introduced</value>
</data>
<data name="Parent" xml:space="preserve">
<value>Parent</value>
</data>
<data name="Details" xml:space="preserve">
<value>Details</value>
</data>
<data name="Edit" xml:space="preserve">
<value>Edit</value>
</data>
<data name="Delete" xml:space="preserve">
<value>Delete</value>
</data>
<data name="Delete software family" xml:space="preserve">
<value>Delete software family</value>
</data>
<data name="Are you sure you want to delete the software family {0}?" xml:space="preserve">
<value>Are you sure you want to delete the software family {0}?</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="Software family details" xml:space="preserve">
<value>Software family details</value>
</data>
<data name="Please enter a valid name." xml:space="preserve">
<value>Please enter a valid name.</value>
</data>
<data name="Unknown (introduction date)" xml:space="preserve">
<value>Unknown</value>
</data>
<data name="Please enter a valid introduction date." xml:space="preserve">
<value>Please enter a valid introduction date.</value>
</data>
<data name="Parent software family" xml:space="preserve">
<value>Parent software family</value>
</data>
<data name="Unknown or none (parent software family)" xml:space="preserve">
<value>Unknown or none</value>
</data>
<data name="Save" xml:space="preserve">
<value>Save</value>
</data>
<data name="Back to list" xml:space="preserve">
<value>Back to list</value>
</data>
<data name="Name must be smaller than 256 characters." xml:space="preserve">
<value>Name must be smaller than 256 characters.</value>
</data>
</root>

View File

@@ -0,0 +1,184 @@
<?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="Software families" xml:space="preserve">
<value>Familias de software</value>
</data>
<data name="Loading..." xml:space="preserve">
<value>Cargando...</value>
</data>
<data name="Create new" xml:space="preserve">
<value>Crear nueva</value>
</data>
<data name="Name" xml:space="preserve">
<value>Nombre</value>
</data>
<data name="Introduced" xml:space="preserve">
<value>Introducida en</value>
</data>
<data name="Parent" xml:space="preserve">
<value>Predecesora</value>
</data>
<data name="Details" xml:space="preserve">
<value>Detalles</value>
</data>
<data name="Edit" xml:space="preserve">
<value>Editar</value>
</data>
<data name="Delete" xml:space="preserve">
<value>Eliminar</value>
</data>
<data name="Delete software family" xml:space="preserve">
<value>Eliminar familia de software</value>
</data>
<data name="Are you sure you want to delete the software family {0}?" xml:space="preserve">
<value>¿Estás seguro de querer eliminar la familia de software {0}?</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancelar</value>
</data>
<data name="Software family details" xml:space="preserve">
<value>Detalles de familia de software</value>
</data>
<data name="Please enter a valid name." xml:space="preserve">
<value>Por favor introduce un nombre válido.</value>
</data>
<data name="Unknown (introduction date)" xml:space="preserve">
<value>Desconocida</value>
</data>
<data name="Please enter a valid introduction date." xml:space="preserve">
<value>Por favor introduce una fecha de introducción válida.</value>
</data>
<data name="Parent software family" xml:space="preserve">
<value>Familia de software predecesora</value>
</data>
<data name="Unknown or none (parent software family)" xml:space="preserve">
<value>Desconocido o ninguno</value>
</data>
<data name="Save" xml:space="preserve">
<value>Guardar</value>
</data>
<data name="Back to list" xml:space="preserve">
<value>Volver a la lista</value>
</data>
<data name="Name must be smaller than 256 characters." xml:space="preserve">
<value>El nombre debe contener menos de 256 caracteres.</value>
</data>
</root>

View File

@@ -76,6 +76,7 @@ namespace Marechai.Services
services.AddScoped<MediaService>();
services.AddScoped<MagazinesService>();
services.AddScoped<MagazineIssuesService>();
services.AddScoped<SoftwareFamiliesService>();
}
}
}

View File

@@ -0,0 +1,102 @@
/******************************************************************************
// 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 SoftwareFamiliesService
{
readonly MarechaiContext _context;
public SoftwareFamiliesService(MarechaiContext context) => _context = context;
public async Task<List<SoftwareFamilyViewModel>> GetAsync() => await _context.
SoftwareFamilies.OrderBy(b => b.Name).
Select(b => new SoftwareFamilyViewModel
{
Id = b.Id,
Name = b.Name,
Parent = b.Parent.Name,
Introduced = b.Introduced,
ParentId = b.ParentId
}).ToListAsync();
public async Task<SoftwareFamilyViewModel> GetAsync(ulong id) =>
await _context.SoftwareFamilies.Where(b => b.Id == id).Select(b => new SoftwareFamilyViewModel
{
Id = b.Id,
Name = b.Name,
Parent = b.Parent.Name,
Introduced = b.Introduced,
ParentId = b.ParentId
}).FirstOrDefaultAsync();
public async Task UpdateAsync(SoftwareFamilyViewModel viewModel, string userId)
{
SoftwareFamily model = await _context.SoftwareFamilies.FindAsync(viewModel.Id);
if(model is null)
return;
model.Name = viewModel.Name;
model.ParentId = viewModel.ParentId;
model.Introduced = viewModel.Introduced;
await _context.SaveChangesWithUserAsync(userId);
}
public async Task<ulong> CreateAsync(SoftwareFamilyViewModel viewModel, string userId)
{
var model = new SoftwareFamily
{
Name = viewModel.Name,
ParentId = viewModel.ParentId,
Introduced = viewModel.Introduced
};
await _context.SoftwareFamilies.AddAsync(model);
await _context.SaveChangesWithUserAsync(userId);
return model.Id;
}
public async Task DeleteAsync(ulong id, string userId)
{
SoftwareFamily item = await _context.SoftwareFamilies.FindAsync(id);
if(item is null)
return;
_context.SoftwareFamilies.Remove(item);
await _context.SaveChangesWithUserAsync(userId);
}
}
}

View File

@@ -0,0 +1,37 @@
/******************************************************************************
// 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;
namespace Marechai.ViewModels
{
public class SoftwareFamilyViewModel : BaseViewModel<ulong>
{
public string Name { get; set; }
public DateTime? Introduced { get; set; }
public string Parent { get; set; }
public ulong? ParentId { get; set; }
}
}