From ce99d8a184a0eddeebe8a44877e3e8e21a055326 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 8 Aug 2020 14:30:04 +0100 Subject: [PATCH] Add magazines admin page. --- Marechai.sln.DotSettings | 1 + Marechai/Pages/Admin/Details/Magazine.razor | 159 +++++++++++++++++ .../Pages/Admin/Details/Magazine.razor.cs | 160 ++++++++++++++++++ Marechai/Pages/Admin/Index.razor | 6 + Marechai/Pages/Admin/Magazines.razor | 110 ++++++++++++ Marechai/Pages/Admin/Magazines.razor.cs | 88 ++++++++++ .../Resources/Services/AdminService.en.resx | 6 + .../Resources/Services/AdminService.es.resx | 6 + .../Services/MagazinesService.en.resx | 104 ++++++++++++ .../Services/MagazinesService.es.resx | 104 ++++++++++++ Marechai/Services/MagazinesService.cs | 119 +++++++++++++ Marechai/Services/Register.cs | 1 + Marechai/Shared/Validators.cs | 40 +++++ Marechai/ViewModels/MagazineViewModel.cs | 35 ++++ 14 files changed, 939 insertions(+) create mode 100644 Marechai/Pages/Admin/Details/Magazine.razor create mode 100644 Marechai/Pages/Admin/Details/Magazine.razor.cs create mode 100644 Marechai/Pages/Admin/Magazines.razor create mode 100644 Marechai/Pages/Admin/Magazines.razor.cs create mode 100644 Marechai/Resources/Services/MagazinesService.en.resx create mode 100644 Marechai/Resources/Services/MagazinesService.es.resx create mode 100644 Marechai/Services/MagazinesService.cs create mode 100644 Marechai/ViewModels/MagazineViewModel.cs diff --git a/Marechai.sln.DotSettings b/Marechai.sln.DotSettings index f5e885f9..47b384a5 100644 --- a/Marechai.sln.DotSettings +++ b/Marechai.sln.DotSettings @@ -4,6 +4,7 @@ True True True + True True True True diff --git a/Marechai/Pages/Admin/Details/Magazine.razor b/Marechai/Pages/Admin/Details/Magazine.razor new file mode 100644 index 00000000..8167a4f2 --- /dev/null +++ b/Marechai/Pages/Admin/Details/Magazine.razor @@ -0,0 +1,159 @@ +@{ +/****************************************************************************** +// 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/details/{Id:long}" +@page "/admin/magazines/edit/{Id:long}" +@page "/admin/magazines/create" +@using Marechai.Database +@using Marechai.Database.Models +@inherits OwningComponentBase +@inject IStringLocalizer L +@inject Iso31661NumericService CountriesService +@inject NavigationManager NavigationManager +@inject IWebHostEnvironment Host +@inject IJSRuntime JSRuntime +@inject Microsoft.AspNetCore.Identity.UserManager UserManager +@inject AuthenticationStateProvider AuthenticationStateProvider +@attribute [Authorize(Roles = "UberAdmin, Admin")] + + +

@L["Magazine details"]

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

@L["Loading..."]

+ + return; +} + +
+ + @L["Title using latin script"] + + + + @L["Please enter a valid title."] + + + + + @if (_editing || _model.NativeTitle != null) + { + + @L["Native title, that is, title using native script (cyrillic, chinese, etc)"] + @if (_editing) + { + @L["Unknown (native title)"] + } + @if (!_editing || + !_unknownNativeTitle) + { + + + + @L["Please enter a valid native title."] + + + + } + + } + @if (_editing || _model.FirstPublication != null) + { + + @L["First publication"] + @if (_editing) + { + @L["Unknown (first publication date)"] + } + @if (!_editing || !_unknownFirstPublication) + { + + + + @L["Please enter a valid first publication date."] + + + + } + + } + @if (_editing || _model.CountryId != null) + { + + @L["Country of publication"] + @if (_editing) + { + @L["Unknown (country of publication)"] + } + @if (!_editing || + !_unknownCountry) + { + + } + + } + @if (_editing || _model.Issn != null) + { + + @L["ISSN"] + @if (_editing) + { + @L["Unknown (ISSN)"] + } + @if (!_editing || + !_unknownIssn) + { + + + + @L["Please enter a valid ISSN."] + + + + } + + } +
+
+ @if (!_editing) + { + + } + else + { + + + } + @L["Back to list"] +
diff --git a/Marechai/Pages/Admin/Details/Magazine.razor.cs b/Marechai/Pages/Admin/Details/Magazine.razor.cs new file mode 100644 index 00000000..e1a269d7 --- /dev/null +++ b/Marechai/Pages/Admin/Details/Magazine.razor.cs @@ -0,0 +1,160 @@ +/****************************************************************************** +// 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.Database.Models; +using Marechai.Shared; +using Marechai.ViewModels; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Authorization; + +namespace Marechai.Pages.Admin.Details +{ + public partial class Magazine + { + AuthenticationState _authState; + List _countries; + bool _creating; + bool _editing; + bool _loaded; + MagazineViewModel _model; + bool _unknownCountry; + bool _unknownFirstPublication; + bool _unknownIssn; + bool _unknownNativeTitle; + + [Parameter] + public long Id { get; set; } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if(_loaded) + return; + + _loaded = true; + + _creating = NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant(). + StartsWith("admin/magazines/create", StringComparison.InvariantCulture); + + if(Id <= 0 && + !_creating) + return; + + _countries = await CountriesService.GetAsync(); + _model = _creating ? new MagazineViewModel() : await Service.GetAsync(Id); + _authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); + + _editing = _creating || NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant(). + StartsWith("admin/magazines/edit/", + StringComparison.InvariantCulture); + + if(_editing) + SetCheckboxes(); + + StateHasChanged(); + } + + void SetCheckboxes() + { + _unknownCountry = !_model.CountryId.HasValue; + _unknownNativeTitle = string.IsNullOrWhiteSpace(_model.NativeTitle); + _unknownFirstPublication = !_model.FirstPublication.HasValue; + _unknownIssn = string.IsNullOrWhiteSpace(_model.Issn); + } + + void OnEditClicked() + { + _editing = true; + SetCheckboxes(); + StateHasChanged(); + } + + async void OnCancelClicked() + { + _editing = false; + + if(_creating) + { + NavigationManager.ToBaseRelativePath("admin/magazines"); + + return; + } + + _model = await Service.GetAsync(Id); + SetCheckboxes(); + StateHasChanged(); + } + + async void OnSaveClicked() + { + if(_unknownNativeTitle) + _model.NativeTitle = null; + else if(string.IsNullOrWhiteSpace(_model.NativeTitle)) + return; + + if(_unknownCountry) + _model.CountryId = null; + else if(_model.CountryId < 0) + return; + + if(_unknownFirstPublication) + _model.FirstPublication = null; + else if(_model.FirstPublication?.Date >= DateTime.UtcNow.Date) + return; + + if(_unknownIssn) + _model.Issn = null; + else if(string.IsNullOrWhiteSpace(_model.Issn)) + return; + + if(string.IsNullOrWhiteSpace(_model.Title)) + return; + + if(_creating) + Id = await Service.CreateAsync(_model, (await UserManager.GetUserAsync(_authState.User)).Id); + else + await Service.UpdateAsync(_model, (await UserManager.GetUserAsync(_authState.User)).Id); + + _editing = false; + _creating = false; + _model = await Service.GetAsync(Id); + SetCheckboxes(); + StateHasChanged(); + } + + void ValidateTitle(ValidatorEventArgs e) => + Validators.ValidateString(e, L["Title must be smaller than 256 characters."], 256); + + void ValidateFirstPublication(ValidatorEventArgs e) => Validators.ValidateDate(e); + + void ValidateNativeTitle(ValidatorEventArgs e) => + Validators.ValidateString(e, L["Native title must be smaller than 256 characters."], 256); + + void ValidateIssn(ValidatorEventArgs e) => Validators.ValidateIssn(e); + } +} \ No newline at end of file diff --git a/Marechai/Pages/Admin/Index.razor b/Marechai/Pages/Admin/Index.razor index 972ce8ee..79bc977f 100644 --- a/Marechai/Pages/Admin/Index.razor +++ b/Marechai/Pages/Admin/Index.razor @@ -92,6 +92,12 @@
  • @L["Books"]
  • +
  • + @L["Documents"] +
  • +
  • + @L["Magazines"] +
  • 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"] +

    + + + + + + + + + + + + + @foreach (var item in _magazines) + { + + + + + + + + + } + +
    + @L["Title"] + + @L["Native title"] + + @L["First publication"] + + @L["Country"] + + @L["ISSN"] +
    + @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