Add software version admin page.

This commit is contained in:
2020-08-08 21:36:37 +01:00
parent b118afce1e
commit 9b4c950557
15 changed files with 1061 additions and 1 deletions

View File

@@ -120,6 +120,7 @@ namespace Marechai.Database.Models
public virtual DbSet<MediaFile> MediaFiles { get; set; }
public virtual DbSet<Dump> Dumps { get; set; }
public virtual DbSet<SoftwareFamily> SoftwareFamilies { get; set; }
public virtual DbSet<SoftwareVersion> SoftwareVersions { get; set; }
public virtual DbSet<SoftwareVariant> SoftwareVariants { get; set; }
public virtual DbSet<StandaloneFile> StandaloneFiles { get; set; }
public virtual DbSet<MasteringText> MasteringTexts { get; set; }
@@ -1850,6 +1851,8 @@ namespace Marechai.Database.Models
modelBuilder.Entity<SoftwareVersion>(entity =>
{
entity.ToTable("SoftwareVersion");
entity.HasIndex(e => e.Name);
entity.HasIndex(e => e.Introduced);
entity.HasIndex(e => e.Codename);

View File

@@ -44,5 +44,9 @@ namespace Marechai.Database.Models
public virtual ICollection<CompaniesBySoftwareVersion> Companies { get; set; }
public virtual ICollection<PeopleBySoftwareVersion> People { get; set; }
public virtual ICollection<SoftwareVariant> Variants { get; set; }
public ulong FamilyId { get; set; }
public int? LicenseId { get; set; }
public ulong? PreviousId { get; set; }
}
}

View File

@@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<Version>4.0.0.1811</Version>
<Version>4.0.0.1816</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,189 @@
@{
/******************************************************************************
// 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_versions/details/{Id:ulong}"
@page "/admin/software_versions/edit/{Id:ulong}"
@page "/admin/software_versions/create"
@using Marechai.Database
@using Marechai.Database.Models
@inherits OwningComponentBase<SoftwareVersionsService>
@inject IStringLocalizer<SoftwareVersionsService> L
@inject SoftwareFamiliesService SoftwareFamiliesService
@inject LicensesService LicensesService
@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 version details"]</h3>
<hr />
@if (!_loaded)
{
<p align="center">@L["Loading..."]</p>
return;
}
<div>
<Field>
<FieldLabel>@L["Software family"]</FieldLabel>
<Select Disabled="!_editing" TValue="ulong" @bind-SelectedValue="@_model.FamilyId">
@foreach (var family in _softwareFamilies)
{
<SelectItem TValue="ulong" Value="@family.Id">@family.Name</SelectItem>
}
</Select>
</Field>
<Field>
<FieldLabel>@L["Version"]</FieldLabel>
<Validation Validator="@ValidateVersion">
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Version">
<Feedback>
<ValidationError>@L["Please enter a valid version."]</ValidationError>
</Feedback>
</TextEdit>
</Validation>
</Field>
@if (_editing || _model.Name != null)
{
<Field>
<FieldLabel>@L["Name, if different from family name"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownName">@L["Unknown (name)"]</Check>
}
@if (!_editing ||
!_unknownName)
{
<Validation Validator="@ValidateName">
<TextEdit Disabled="!_editing" @bind-Text="@_model.Name">
<Feedback>
<ValidationError>@L["Please enter a valid name."]</ValidationError>
</Feedback>
</TextEdit>
</Validation>
}
</Field>
}
@if (_editing || _model.Codename != null)
{
<Field>
<FieldLabel>@L["Codename"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownCodename">@L["Unknown (codename)"]</Check>
}
@if (!_editing ||
!_unknownCodename)
{
<Validation Validator="@ValidateCodename">
<TextEdit Disabled="!_editing" @bind-Text="@_model.Codename">
<Feedback>
<ValidationError>@L["Please enter a valid codename."]</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.LicenseId != null)
{
<Field>
<FieldLabel>@L["License"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownLicense">@L["Unknown (license)"]</Check>
}
@if (!_editing ||
!_unknownLicense)
{
<Select Disabled="!_editing" TValue="int?" @bind-SelectedValue="@_model.LicenseId">
@foreach (var license in _licenses)
{
<SelectItem TValue="int?" Value="@license.Id">@license.Name</SelectItem>
}
</Select>
}
</Field>
}
@if (_editing || _model.PreviousId != null)
{
<Field>
<FieldLabel>@L["Previous"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownPrevious">@L["Unknown or none (previous version)"]</Check>
}
@if (!_editing ||
!_unknownPrevious)
{
<Select Disabled="!_editing" TValue="ulong?" @bind-SelectedValue="@_model.PreviousId">
@foreach (var version in _softwareVersions)
{
<SelectItem TValue="ulong?" Value="@version.Id">@version.Name ?? @version.Version</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_versions" class="btn btn-secondary">@L["Back to list"]</a>
</div>

View File

@@ -0,0 +1,173 @@
/******************************************************************************
// 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 SoftwareVersion
{
AuthenticationState _authState;
bool _creating;
bool _editing;
List<Database.Models.License> _licenses;
bool _loaded;
SoftwareVersionViewModel _model;
List<SoftwareFamilyViewModel> _softwareFamilies;
List<SoftwareVersionViewModel> _softwareVersions;
bool _unknownCodename;
bool _unknownIntroduced;
bool _unknownLicense;
bool _unknownName;
bool _unknownPrevious;
[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_versions/create",
StringComparison.InvariantCulture);
if(Id <= 0 &&
!_creating)
return;
_softwareVersions = await Service.GetAsync();
_softwareFamilies = await SoftwareFamiliesService.GetAsync();
_licenses = await LicensesService.GetAsync();
_model = _creating ? new SoftwareVersionViewModel() : await Service.GetAsync(Id);
_authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
_editing = _creating || NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant().
StartsWith("admin/software_versions/edit/",
StringComparison.InvariantCulture);
if(_editing)
SetCheckboxes();
StateHasChanged();
}
void SetCheckboxes()
{
_unknownName = string.IsNullOrWhiteSpace(_model.Name);
_unknownCodename = string.IsNullOrWhiteSpace(_model.Codename);
_unknownLicense = !_model.LicenseId.HasValue;
_unknownIntroduced = !_model.Introduced.HasValue;
_unknownPrevious = !_model.PreviousId.HasValue;
}
void OnEditClicked()
{
_editing = true;
SetCheckboxes();
StateHasChanged();
}
async void OnCancelClicked()
{
_editing = false;
if(_creating)
{
NavigationManager.ToBaseRelativePath("admin/software_versions");
return;
}
_model = await Service.GetAsync(Id);
SetCheckboxes();
StateHasChanged();
}
async void OnSaveClicked()
{
if(_unknownName)
_model.Name = null;
else if(string.IsNullOrWhiteSpace(_model.Name))
return;
if(_unknownCodename)
_model.Codename = null;
else if(string.IsNullOrWhiteSpace(_model.Codename))
return;
if(_unknownLicense)
_model.LicenseId = null;
else if(_model.LicenseId < 1)
return;
if(_unknownPrevious)
_model.PreviousId = null;
else if(_model.PreviousId < 1)
return;
if(_unknownIntroduced)
_model.Introduced = null;
else if(_model.Introduced?.Date >= DateTime.UtcNow.Date)
return;
if(string.IsNullOrWhiteSpace(_model.Version))
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 ValidateCodename(ValidatorEventArgs e) =>
Validators.ValidateString(e, L["Codename must be smaller than 256 characters."], 256);
void ValidateVersion(ValidatorEventArgs e) =>
Validators.ValidateString(e, L["Version must be smaller than 256 characters."], 256);
void ValidateIntroduced(ValidatorEventArgs e) => Validators.ValidateDate(e);
}
}

View File

@@ -134,5 +134,8 @@
<li>
<a href="/admin/software_families">@L["Software families"]</a>
</li>
<li>
<a href="/admin/software_versions">@L["Software versions"]</a>
</li>
</ul>
</div>

View File

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

View File

@@ -44,4 +44,7 @@
<data name="Software families" xml:space="preserve">
<value />
</data>
<data name="Software versions" xml:space="preserve">
<value>Software versions</value>
</data>
</root>

View File

@@ -243,4 +243,7 @@
<data name="Software families" xml:space="preserve">
<value>Familias de software</value>
</data>
<data name="Software versions" xml:space="preserve">
<value>Versiones de software</value>
</data>
</root>

View File

@@ -0,0 +1,104 @@
<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 versions" xml:space="preserve">
<value>Software versions</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="Family" xml:space="preserve">
<value>Family</value>
</data>
<data name="Version" xml:space="preserve">
<value>Version</value>
</data>
<data name="Name" xml:space="preserve">
<value>Name</value>
</data>
<data name="Codename" xml:space="preserve">
<value>Codename</value>
</data>
<data name="Introduced" xml:space="preserve">
<value>Introduced</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 version" xml:space="preserve">
<value>Delete software version</value>
</data>
<data name="Are you sure you want to delete the software version {0}?" xml:space="preserve">
<value>Are you sure you want to delete the software version {0}?</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="Software version details" xml:space="preserve">
<value>Software version details</value>
</data>
<data name="Software family" xml:space="preserve">
<value>Software family</value>
</data>
<data name="Please enter a valid version." xml:space="preserve">
<value>Please enter a valid version.</value>
</data>
<data name="Name, if different from family name" xml:space="preserve">
<value>Name, if different from family name</value>
</data>
<data name="Unknown (name)" xml:space="preserve">
<value>Unknown</value>
</data>
<data name="Please enter a valid name." xml:space="preserve">
<value>Please enter a valid name.</value>
</data>
<data name="Unknown (codename)" xml:space="preserve">
<value>Unknown</value>
</data>
<data name="Please enter a valid codename." xml:space="preserve">
<value>Please enter a valid codename.</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="License" xml:space="preserve">
<value>License</value>
</data>
<data name="Unknown (license)" xml:space="preserve">
<value>Unknown</value>
</data>
<data name="Previous" xml:space="preserve">
<value>Previous</value>
</data>
<data name="Unknown or none (previous version)" 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>
</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="Software versions" xml:space="preserve">
<value>Versiones 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="Family" xml:space="preserve">
<value>Familia</value>
</data>
<data name="Version" xml:space="preserve">
<value>Versión</value>
</data>
<data name="Name" xml:space="preserve">
<value>Nombre</value>
</data>
<data name="Codename" xml:space="preserve">
<value>Nombre en clave</value>
</data>
<data name="Introduced" xml:space="preserve">
<value>Introducida</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 version" xml:space="preserve">
<value>Eliminar versión de software</value>
</data>
<data name="Are you sure you want to delete the software version {0}?" xml:space="preserve">
<value>¿Estás seguro de eliminar la versión de software {0}?</value>
</data>
<data name="Cancel" xml:space="preserve">
<value>Cancelar</value>
</data>
<data name="Software version details" xml:space="preserve">
<value>Detalles de versión de software</value>
</data>
<data name="Software family" xml:space="preserve">
<value>Familia de software</value>
</data>
<data name="Please enter a valid version." xml:space="preserve">
<value>Por favor introduce una versión válida.</value>
</data>
<data name="Name, if different from family name" xml:space="preserve">
<value>Nombre, si es diferente del nombre de la familia</value>
</data>
<data name="Unknown (name)" xml:space="preserve">
<value>Desconocido</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 (codename)" xml:space="preserve">
<value>Desconocido</value>
</data>
<data name="Please enter a valid codename." xml:space="preserve">
<value>Por favor introduce un nombre en clave 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="License" xml:space="preserve">
<value>Licencia</value>
</data>
<data name="Unknown (license)" xml:space="preserve">
<value>Desconocida</value>
</data>
<data name="Previous" xml:space="preserve">
<value>Anterior</value>
</data>
<data name="Unknown or none (previous version)" xml:space="preserve">
<value>Desconocida o ninguna</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>
</root>

View File

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

View File

@@ -0,0 +1,125 @@
/******************************************************************************
// 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 SoftwareVersionsService
{
readonly MarechaiContext _context;
public SoftwareVersionsService(MarechaiContext context) => _context = context;
public async Task<List<SoftwareVersionViewModel>> GetAsync() => await _context.
SoftwareVersions.
OrderBy(b => b.Family.Name).
ThenBy(b => b.Version).
ThenBy(b => b.Introduced).
Select(b => new SoftwareVersionViewModel
{
Id = b.Id,
Family = b.Family.Name,
Name = b.Name,
Codename = b.Codename,
Version = b.Version,
Introduced = b.Introduced,
Previous = b.Previous.Name,
License = b.License.Name,
FamilyId = b.FamilyId,
LicenseId = b.LicenseId,
PreviousId = b.PreviousId
}).ToListAsync();
public async Task<SoftwareVersionViewModel> GetAsync(ulong id) =>
await _context.SoftwareVersions.Where(b => b.Id == id).Select(b => new SoftwareVersionViewModel
{
Id = b.Id,
Family = b.Family.Name,
Name = b.Name,
Codename = b.Codename,
Version = b.Version,
Introduced = b.Introduced,
Previous = b.Previous.Name,
License = b.License.Name,
FamilyId = b.FamilyId,
LicenseId = b.LicenseId,
PreviousId = b.PreviousId
}).FirstOrDefaultAsync();
public async Task UpdateAsync(SoftwareVersionViewModel viewModel, string userId)
{
SoftwareVersion model = await _context.SoftwareVersions.FindAsync(viewModel.Id);
if(model is null)
return;
model.Name = viewModel.Name;
model.Codename = viewModel.Codename;
model.Version = viewModel.Version;
model.Introduced = viewModel.Introduced;
model.FamilyId = viewModel.FamilyId;
model.LicenseId = viewModel.LicenseId;
model.PreviousId = viewModel.PreviousId;
await _context.SaveChangesWithUserAsync(userId);
}
public async Task<ulong> CreateAsync(SoftwareVersionViewModel viewModel, string userId)
{
var model = new SoftwareVersion
{
Name = viewModel.Name,
Codename = viewModel.Codename,
Version = viewModel.Version,
Introduced = viewModel.Introduced,
FamilyId = viewModel.FamilyId,
LicenseId = viewModel.LicenseId,
PreviousId = viewModel.PreviousId
};
await _context.SoftwareVersions.AddAsync(model);
await _context.SaveChangesWithUserAsync(userId);
return model.Id;
}
public async Task DeleteAsync(ulong id, string userId)
{
SoftwareVersion item = await _context.SoftwareVersions.FindAsync(id);
if(item is null)
return;
_context.SoftwareVersions.Remove(item);
await _context.SaveChangesWithUserAsync(userId);
}
}
}

View File

@@ -0,0 +1,43 @@
/******************************************************************************
// 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 SoftwareVersionViewModel : BaseViewModel<ulong>
{
public string Family { get; set; }
public string Name { get; set; }
public string Codename { get; set; }
public string Version { get; set; }
public DateTime? Introduced { get; set; }
public string Previous { get; set; }
public string License { get; set; }
public ulong FamilyId { get; set; }
public int? LicenseId { get; set; }
public ulong? PreviousId { get; set; }
}
}