diff --git a/Marechai/Pages/Admin/Magazines.razor b/Marechai/Pages/Admin/Magazines.razor
new file mode 100644
index 00000000..d4c0a67d
--- /dev/null
+++ b/Marechai/Pages/Admin/Magazines.razor
@@ -0,0 +1,110 @@
+@{
+/******************************************************************************
+// 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/magazines"
+@using Marechai.Database.Models
+@inherits OwningComponentBase
+@inject IStringLocalizer L
+@inject Microsoft.AspNetCore.Identity.UserManager UserManager
+@inject AuthenticationStateProvider AuthenticationStateProvider
+@attribute [Authorize(Roles = "UberAdmin, Admin")]
+@L["Magazines"]
+@if (_magazines is null)
+{
+ @L["Loading..."]
+
+ return;
+}
+
+ @L["Create new"]
+
+
+
+
+ |
+ @L["Title"]
+ |
+
+ @L["Native title"]
+ |
+
+ @L["First publication"]
+ |
+
+ @L["Country"]
+ |
+
+ @L["ISSN"]
+ |
+ |
+
+
+
+ @foreach (var item in _magazines)
+ {
+
+ |
+ @item.Title
+ |
+
+ @item.NativeTitle
+ |
+
+ @($"{item.FirstPublication:d}")
+ |
+
+ @item.Country
+ |
+
+ @item.Issn
+ |
+
+ @L["Details"]
+ @L["Edit"]
+
+ |
+
+ }
+
+
+
+
+
+
+
+ @L["Delete magazine"]
+
+
+
+ @string.Format(@L["Are you sure you want to delete the magazine {0}?"], _currentMagazine?.Title)
+
+
+
+
+
+
+
diff --git a/Marechai/Pages/Admin/Magazines.razor.cs b/Marechai/Pages/Admin/Magazines.razor.cs
new file mode 100644
index 00000000..bd7d27bb
--- /dev/null
+++ b/Marechai/Pages/Admin/Magazines.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 Magazines
+ {
+ MagazineViewModel _currentMagazine;
+ bool _deleteInProgress;
+ Modal _frmDelete;
+ bool _loaded;
+ List _magazines;
+
+ protected override async Task OnAfterRenderAsync(bool firstRender)
+ {
+ if(_loaded)
+ return;
+
+ _magazines = await Service.GetAsync();
+ _loaded = true;
+ StateHasChanged();
+ }
+
+ void ShowModal(long itemId)
+ {
+ _currentMagazine = _magazines.FirstOrDefault(n => n.Id == itemId);
+ _frmDelete.Show();
+ }
+
+ void HideModal() => _frmDelete.Hide();
+
+ async void ConfirmDelete()
+ {
+ if(_currentMagazine is null)
+ return;
+
+ _deleteInProgress = true;
+ _magazines = null;
+ AuthenticationState authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
+
+ // Yield thread to let UI to update
+ await Task.Yield();
+
+ await Service.DeleteAsync(_currentMagazine.Id, (await UserManager.GetUserAsync(authState.User)).Id);
+ _magazines = 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) => _currentMagazine = null;
+ }
+}
\ No newline at end of file
diff --git a/Marechai/Resources/Services/AdminService.en.resx b/Marechai/Resources/Services/AdminService.en.resx
index c1097dc7..7071bb6a 100644
--- a/Marechai/Resources/Services/AdminService.en.resx
+++ b/Marechai/Resources/Services/AdminService.en.resx
@@ -29,4 +29,10 @@
Administrative pages for media dumps
+
+ Magazines
+
+
+ Documents
+
\ No newline at end of file
diff --git a/Marechai/Resources/Services/AdminService.es.resx b/Marechai/Resources/Services/AdminService.es.resx
index 987f7ce6..233d4465 100644
--- a/Marechai/Resources/Services/AdminService.es.resx
+++ b/Marechai/Resources/Services/AdminService.es.resx
@@ -228,4 +228,10 @@
Páginas de administración de volcados
+
+ Revistas
+
+
+ Documentos
+
\ No newline at end of file
diff --git a/Marechai/Resources/Services/MagazinesService.en.resx b/Marechai/Resources/Services/MagazinesService.en.resx
new file mode 100644
index 00000000..9701f7af
--- /dev/null
+++ b/Marechai/Resources/Services/MagazinesService.en.resx
@@ -0,0 +1,104 @@
+
+
+ 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
+
+
+ Native title must be smaller than 256 characters.
+
+
+ Title must be smaller than 256 characters.
+
+
+ Back to list
+
+
+ Save
+
+
+ Please enter a valid ISSN.
+
+
+ Unknown
+
+
+ ISSN
+
+
+ Unknown
+
+
+ Country of publication
+
+
+ Please enter a valid first publication date.
+
+
+ Unknown
+
+
+ First publication
+
+
+ Please enter a valid native title.
+
+
+ Unknown
+
+
+ Native title, that is, title using native script (cyrillic, chinese, etc)
+
+
+ Please enter a valid title.
+
+
+ Title using latin script
+
+
+ Loading...
+
+
+ Magazine details
+
+
+ Cancel
+
+
+ Are you sure you want to delete the magazine {0}?
+
+
+ Delete magazine
+
+
+ Delete
+
+
+ Edit
+
+
+ Details
+
+
+ Country
+
+
+ Native title
+
+
+ Title
+
+
+ Create new
+
+
+ Magazines
+
+
\ No newline at end of file
diff --git a/Marechai/Resources/Services/MagazinesService.es.resx b/Marechai/Resources/Services/MagazinesService.es.resx
new file mode 100644
index 00000000..00cffea7
--- /dev/null
+++ b/Marechai/Resources/Services/MagazinesService.es.resx
@@ -0,0 +1,104 @@
+
+
+ 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
+
+
+ ¿Estás seguro de eliminar la revista {0}?
+
+
+ Volver a la lista
+
+
+ Cancelar
+
+
+ País
+
+
+ País de publicación
+
+
+ Crear nueva
+
+
+ Eliminar
+
+
+ Eliminar revista
+
+
+ Detalles
+
+
+ Editar
+
+
+ Primera publicación
+
+
+ ISSN
+
+
+ Cargando...
+
+
+ Detalles de revista
+
+
+ Revistas
+
+
+ Título nativo
+
+
+ El título nativo debe contener menos de 256 caracteres.
+
+
+ Título nativo, es decir, usando escritura nativa (cirílico, chino, etc)
+
+
+ Por favor introduce una fecha de primera publicación válida.
+
+
+ Por favor introduce un ISSN válido.
+
+
+ Por favor introduce un título nativo válido.
+
+
+ Por favor introduce un título válido.
+
+
+ Guardar
+
+
+ Título
+
+
+ El título debe contener menos de 256 caracteres.
+
+
+ Título usando escritura latina
+
+
+ Desconocido
+
+
+ Desconocida
+
+
+ Desconocido
+
+
+ Desconocido
+
+
\ No newline at end of file
diff --git a/Marechai/Services/MagazinesService.cs b/Marechai/Services/MagazinesService.cs
new file mode 100644
index 00000000..33678bda
--- /dev/null
+++ b/Marechai/Services/MagazinesService.cs
@@ -0,0 +1,119 @@
+/******************************************************************************
+// 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 MagazinesService
+ {
+ readonly MarechaiContext _context;
+
+ public MagazinesService(MarechaiContext context) => _context = context;
+
+ public async Task> GetAsync() => await _context.
+ Magazines.OrderBy(b => b.NativeTitle).
+ ThenBy(b => b.FirstPublication).
+ ThenBy(b => b.Title).
+ Select(b => new MagazineViewModel
+ {
+ Id = b.Id,
+ Title = b.Title,
+ NativeTitle = b.NativeTitle,
+ FirstPublication = b.FirstPublication,
+ Synopsis = b.Synopsis,
+ Issn = b.Issn,
+ CountryId = b.CountryId,
+ Country = b.Country.Name
+ }).ToListAsync();
+
+ public async Task GetAsync(long id) => await _context.Magazines.Where(b => b.Id == id).
+ Select(b => new MagazineViewModel
+ {
+ Id = b.Id,
+ Title = b.Title,
+ NativeTitle = b.NativeTitle,
+ FirstPublication = b.FirstPublication,
+ Synopsis = b.Synopsis,
+ Issn = b.Issn,
+ CountryId = b.CountryId,
+ Country = b.Country.Name
+ }).FirstOrDefaultAsync();
+
+ public async Task UpdateAsync(MagazineViewModel viewModel, string userId)
+ {
+ Magazine model = await _context.Magazines.FindAsync(viewModel.Id);
+
+ if(model is null)
+ return;
+
+ model.Title = viewModel.Title;
+ model.NativeTitle = viewModel.NativeTitle;
+ model.FirstPublication = viewModel.FirstPublication;
+ model.Synopsis = viewModel.Synopsis;
+ model.CountryId = viewModel.CountryId;
+ model.Issn = viewModel.Issn;
+ await _context.SaveChangesWithUserAsync(userId);
+ }
+
+ public async Task CreateAsync(MagazineViewModel viewModel, string userId)
+ {
+ var model = new Magazine
+ {
+ Title = viewModel.Title,
+ NativeTitle = viewModel.NativeTitle,
+ FirstPublication = viewModel.FirstPublication,
+ Synopsis = viewModel.Synopsis,
+ CountryId = viewModel.CountryId,
+ Issn = viewModel.Issn
+ };
+
+ await _context.Magazines.AddAsync(model);
+ await _context.SaveChangesWithUserAsync(userId);
+
+ return model.Id;
+ }
+
+ public async Task GetSynopsisTextAsync(int id) =>
+ (await _context.Magazines.FirstOrDefaultAsync(d => d.Id == id))?.Synopsis;
+
+ public async Task DeleteAsync(long id, string userId)
+ {
+ Magazine item = await _context.Magazines.FindAsync(id);
+
+ if(item is null)
+ return;
+
+ _context.Magazines.Remove(item);
+
+ await _context.SaveChangesWithUserAsync(userId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Marechai/Services/Register.cs b/Marechai/Services/Register.cs
index 2dd9592d..19365a1d 100644
--- a/Marechai/Services/Register.cs
+++ b/Marechai/Services/Register.cs
@@ -74,6 +74,7 @@ namespace Marechai.Services
services.AddScoped();
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
}
}
}
\ No newline at end of file
diff --git a/Marechai/Shared/Validators.cs b/Marechai/Shared/Validators.cs
index a2aa6ef7..74b84569 100644
--- a/Marechai/Shared/Validators.cs
+++ b/Marechai/Shared/Validators.cs
@@ -209,5 +209,45 @@ namespace Marechai.Shared
if(modulo == isbn[12] - 0x30)
e.Status = ValidationStatus.Success;
}
+
+ public static void ValidateIssn(ValidatorEventArgs e)
+ {
+ e.Status = ValidationStatus.Error;
+
+ if(!(e.Value is string issn))
+ return;
+
+ if(issn.Length != 8)
+ return;
+
+ for(int c = 0; c < 7; c++)
+ {
+ if(issn[c] < 0x30 ||
+ issn[c] > 0x39)
+ return;
+ }
+
+ if((issn[7] < 0x30 || issn[7] > 0x39) &&
+ issn[7] != 'x' &&
+ issn[7] != 'X')
+ return;
+
+ int sum = 0;
+ int modulo = 0;
+
+ for(int i = 0; i < 7; i++)
+ {
+ modulo += issn[i] - 0x30;
+ sum += modulo;
+ }
+
+ modulo = sum % 11;
+
+ if((issn[7] == 'x' || issn[7] == 'X') &&
+ modulo == 10)
+ e.Status = ValidationStatus.Success;
+ else if(modulo == issn[7] - 0x30)
+ e.Status = ValidationStatus.Success;
+ }
}
}
\ No newline at end of file
diff --git a/Marechai/ViewModels/MagazineViewModel.cs b/Marechai/ViewModels/MagazineViewModel.cs
new file mode 100644
index 00000000..ba12c04b
--- /dev/null
+++ b/Marechai/ViewModels/MagazineViewModel.cs
@@ -0,0 +1,35 @@
+/******************************************************************************
+// 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 MagazineViewModel : DocumentBaseViewModel
+ {
+ public string Issn { get; set; }
+ public DateTime? FirstPublication { get; set; }
+ }
+}
\ No newline at end of file