diff --git a/Marechai.Database/Models/SoftwareFamily.cs b/Marechai.Database/Models/SoftwareFamily.cs index eb64a5d8..598afdc2 100644 --- a/Marechai.Database/Models/SoftwareFamily.cs +++ b/Marechai.Database/Models/SoftwareFamily.cs @@ -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 Children { get; set; } public virtual ICollection Companies { get; set; } diff --git a/Marechai/Marechai.csproj b/Marechai/Marechai.csproj index fbd872e3..7ca719cd 100644 --- a/Marechai/Marechai.csproj +++ b/Marechai/Marechai.csproj @@ -2,7 +2,7 @@ netcoreapp3.1 - 4.0.0.1810 + 4.0.0.1811 Canary Islands Computer Museum Copyright © 2003-2020 Natalia Portillo Canary Islands Computer Museum Website diff --git a/Marechai/Pages/Admin/Details/SoftwareFamily.razor b/Marechai/Pages/Admin/Details/SoftwareFamily.razor new file mode 100644 index 00000000..1175a9be --- /dev/null +++ b/Marechai/Pages/Admin/Details/SoftwareFamily.razor @@ -0,0 +1,116 @@ +@{ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2003-2020 Natalia Portillo +*******************************************************************************/ +} + +@page "/admin/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 +@inject IStringLocalizer L +@inject NavigationManager NavigationManager +@inject IWebHostEnvironment Host +@inject IJSRuntime JSRuntime +@inject Microsoft.AspNetCore.Identity.UserManager UserManager +@inject AuthenticationStateProvider AuthenticationStateProvider +@attribute [Authorize(Roles = "UberAdmin, Admin")] + + +

@L["Software family details"]

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

@L["Loading..."]

+ + return; +} + +
+ + @L["Name"] + + + + @L["Please enter a valid name."] + + + + + @if (_editing || _model.Introduced != null) + { + + @L["Introduced"] + @if (_editing) + { + @L["Unknown (introduction date)"] + } + @if (!_editing || !_unknownIntroduced) + { + + + + @L["Please enter a valid introduction date."] + + + + } + + } + @if (_editing || _model.ParentId != null) + { + + @L["Parent software family"] + @if (_editing) + { + @L["Unknown or none (parent software family)"] + } + @if (!_editing || + !_unknownParent) + { + + } + + } +
+
+ @if (!_editing) + { + + } + else + { + + + } + @L["Back to list"] +
diff --git a/Marechai/Pages/Admin/Details/SoftwareFamily.razor.cs b/Marechai/Pages/Admin/Details/SoftwareFamily.razor.cs new file mode 100644 index 00000000..98c36a36 --- /dev/null +++ b/Marechai/Pages/Admin/Details/SoftwareFamily.razor.cs @@ -0,0 +1,141 @@ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2003-2020 Natalia Portillo +*******************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Blazorise; +using Marechai.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 _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); + } +} \ No newline at end of file diff --git a/Marechai/Pages/Admin/Index.razor b/Marechai/Pages/Admin/Index.razor index 46122cb7..2523756e 100644 --- a/Marechai/Pages/Admin/Index.razor +++ b/Marechai/Pages/Admin/Index.razor @@ -128,3 +128,11 @@ +
+

@L["Administrative pages for software"]

+ +
diff --git a/Marechai/Pages/Admin/SoftwareFamilies.razor b/Marechai/Pages/Admin/SoftwareFamilies.razor new file mode 100644 index 00000000..ec84412d --- /dev/null +++ b/Marechai/Pages/Admin/SoftwareFamilies.razor @@ -0,0 +1,98 @@ +@{ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2003-2020 Natalia Portillo +*******************************************************************************/ +} + +@page "/admin/software_families" +@using Marechai.Database.Models +@inherits OwningComponentBase +@inject IStringLocalizer L +@inject Microsoft.AspNetCore.Identity.UserManager UserManager +@inject AuthenticationStateProvider AuthenticationStateProvider +@attribute [Authorize(Roles = "UberAdmin, Admin")] +

@L["Software families"]

+@if (_softwareFamilies is null) +{ +

@L["Loading..."]

+ + return; +} +

+ @L["Create new"] +

+ + + + + + + + + + + @foreach (var item in _softwareFamilies) + { + + + + + + + } + +
+ @L["Name"] + + @L["Introduced"] + + @L["Parent"] +
+ @item.Name + + @($"{item.Introduced:d}") + + @item.Parent + + @L["Details"] + @L["Edit"] + +
+ + + + + + @L["Delete software family"] + + + + @string.Format(@L["Are you sure you want to delete the software family {0}?"], _currentSoftwareFamily?.Name) + + + + + + + diff --git a/Marechai/Pages/Admin/SoftwareFamilies.razor.cs b/Marechai/Pages/Admin/SoftwareFamilies.razor.cs new file mode 100644 index 00000000..8ca66ed7 --- /dev/null +++ b/Marechai/Pages/Admin/SoftwareFamilies.razor.cs @@ -0,0 +1,88 @@ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2003-2020 Natalia Portillo +*******************************************************************************/ + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Blazorise; +using Marechai.ViewModels; +using Microsoft.AspNetCore.Components.Authorization; + +namespace Marechai.Pages.Admin +{ + public partial class SoftwareFamilies + { + SoftwareFamilyViewModel _currentSoftwareFamily; + bool _deleteInProgress; + Modal _frmDelete; + bool _loaded; + List _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; + } +} \ No newline at end of file diff --git a/Marechai/Resources/Services/AdminService.en.resx b/Marechai/Resources/Services/AdminService.en.resx index 3dc4c31d..c8e8a8c5 100644 --- a/Marechai/Resources/Services/AdminService.en.resx +++ b/Marechai/Resources/Services/AdminService.en.resx @@ -38,4 +38,10 @@ Magazine issues + + Administrative pages for software + + + + \ No newline at end of file diff --git a/Marechai/Resources/Services/AdminService.es.resx b/Marechai/Resources/Services/AdminService.es.resx index 1c68a604..84c7a136 100644 --- a/Marechai/Resources/Services/AdminService.es.resx +++ b/Marechai/Resources/Services/AdminService.es.resx @@ -237,4 +237,10 @@ Números de revistas + + Páginas de administración para software + + + Familias de software + \ No newline at end of file diff --git a/Marechai/Resources/Services/SoftwareFamiliesService.en.resx b/Marechai/Resources/Services/SoftwareFamiliesService.en.resx new file mode 100644 index 00000000..1a38a338 --- /dev/null +++ b/Marechai/Resources/Services/SoftwareFamiliesService.en.resx @@ -0,0 +1,77 @@ + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Software families + + + Loading... + + + Create new + + + Name + + + Introduced + + + Parent + + + Details + + + Edit + + + Delete + + + Delete software family + + + Are you sure you want to delete the software family {0}? + + + Cancel + + + Software family details + + + Please enter a valid name. + + + Unknown + + + Please enter a valid introduction date. + + + Parent software family + + + Unknown or none + + + Save + + + Back to list + + + Name must be smaller than 256 characters. + + \ No newline at end of file diff --git a/Marechai/Resources/Services/SoftwareFamiliesService.es.resx b/Marechai/Resources/Services/SoftwareFamiliesService.es.resx new file mode 100644 index 00000000..907b470a --- /dev/null +++ b/Marechai/Resources/Services/SoftwareFamiliesService.es.resx @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Familias de software + + + Cargando... + + + Crear nueva + + + Nombre + + + Introducida en + + + Predecesora + + + Detalles + + + Editar + + + Eliminar + + + Eliminar familia de software + + + ¿Estás seguro de querer eliminar la familia de software {0}? + + + Cancelar + + + Detalles de familia de software + + + Por favor introduce un nombre válido. + + + Desconocida + + + Por favor introduce una fecha de introducción válida. + + + Familia de software predecesora + + + Desconocido o ninguno + + + Guardar + + + Volver a la lista + + + El nombre debe contener menos de 256 caracteres. + + \ No newline at end of file diff --git a/Marechai/Services/Register.cs b/Marechai/Services/Register.cs index d8523822..f901f67a 100644 --- a/Marechai/Services/Register.cs +++ b/Marechai/Services/Register.cs @@ -76,6 +76,7 @@ namespace Marechai.Services services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } } } \ No newline at end of file diff --git a/Marechai/Services/SoftwareFamiliesService.cs b/Marechai/Services/SoftwareFamiliesService.cs new file mode 100644 index 00000000..3b769ebb --- /dev/null +++ b/Marechai/Services/SoftwareFamiliesService.cs @@ -0,0 +1,102 @@ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2003-2020 Natalia Portillo +*******************************************************************************/ + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Marechai.Database.Models; +using Marechai.ViewModels; +using Microsoft.EntityFrameworkCore; + +namespace Marechai.Services +{ + public class SoftwareFamiliesService + { + readonly MarechaiContext _context; + + public SoftwareFamiliesService(MarechaiContext context) => _context = context; + + public async Task> 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 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 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); + } + } +} \ No newline at end of file diff --git a/Marechai/ViewModels/SoftwareFamilyViewModel.cs b/Marechai/ViewModels/SoftwareFamilyViewModel.cs new file mode 100644 index 00000000..0943d187 --- /dev/null +++ b/Marechai/ViewModels/SoftwareFamilyViewModel.cs @@ -0,0 +1,37 @@ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2003-2020 Natalia Portillo +*******************************************************************************/ + +using System; + +namespace Marechai.ViewModels +{ + public class SoftwareFamilyViewModel : BaseViewModel + { + public string Name { get; set; } + public DateTime? Introduced { get; set; } + public string Parent { get; set; } + public ulong? ParentId { get; set; } + } +} \ No newline at end of file