diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..61e9067 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.txt +.env \ No newline at end of file diff --git a/backend/.gitignore b/backend/.gitignore index 176da77..f03e819 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -5,6 +5,7 @@ appsettings.Development.json appsettings.json +*.txt efbundle # dotenv files diff --git a/backend/Controllers/CityController.cs b/backend/Controllers/CityController.cs new file mode 100644 index 0000000..164df51 --- /dev/null +++ b/backend/Controllers/CityController.cs @@ -0,0 +1,108 @@ +using Microsoft.AspNetCore.Mvc; +using Mappa.Services; +using Mappa.Dtos; +using Mappa.Entities; +using Microsoft.AspNetCore.Authorization; + +namespace Mappa.Controllers; + +[ApiController] +[Route("[controller]")] +public class CityController : ControllerBase +{ + private readonly IComplexEntityService + _service; + + public CityController(IComplexEntityService service) + { + _service = service; + } + + [HttpGet] + public async Task GetAll() + { + var items = await _service.GetAllAsync(); + return Ok(items); + } + + [HttpGet("{id}")] + public async Task GetById(int id) + { + try + { + var item = await _service.GetByIdAsync(id); + return Ok(item); + } + catch (ArgumentException ex) when (ex.Message.Contains($"Entity with ID {id} not found.")) + { + return NotFound(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpPost] + public async Task Create([FromBody] CityCreateRequest request) + { + try + { + var item = await _service.CreateAsync(request); + return CreatedAtAction(nameof(GetById), new { id = item.Id }, item); + } + catch (ArgumentException ex) + { + return Conflict(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpPut("{id}")] + public async Task Update(int id, [FromBody] CityUpdateRequest request) + { + try + { + var item = await _service.UpdateAsync(id, request); + return Ok(item); + } + catch (ArgumentException ex) + { + return NotFound(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpDelete("{id}")] + public async Task Delete(int id) + { + try + { + var result = await _service.DeleteAsync(id); + if (!result) + return NotFound(new {Message = $"Item with {id} not found"}); + + return NoContent(); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + +} \ No newline at end of file diff --git a/backend/Controllers/EntityController.cs b/backend/Controllers/EntityController.cs index b9483c5..d7fda2f 100644 --- a/backend/Controllers/EntityController.cs +++ b/backend/Controllers/EntityController.cs @@ -88,13 +88,12 @@ public async Task Delete(int id) { try { - await _service.DeleteAsync(id); + var result = await _service.DeleteAsync(id); + if (!result) + return NotFound(new {Message = $"Item with ${id} not found"}); + return NoContent(); } - catch (ArgumentException ex) when (ex.Message.Contains($"Entity with ID {id} not found.")) - { - return NotFound(new { Message = ex.Message }); - } catch (Exception ex) { // Log the exception (optional) diff --git a/backend/Controllers/OrdinaryPersonController.cs b/backend/Controllers/OrdinaryPersonController.cs new file mode 100644 index 0000000..e0684d6 --- /dev/null +++ b/backend/Controllers/OrdinaryPersonController.cs @@ -0,0 +1,108 @@ +using Microsoft.AspNetCore.Mvc; +using Mappa.Services; +using Mappa.Dtos; +using Mappa.Entities; +using Microsoft.AspNetCore.Authorization; + +namespace Mappa.Controllers; + +[ApiController] +[Route("[controller]")] +public class OrdinaryPersonController : ControllerBase +{ + private readonly IComplexEntityService + _service; + + public OrdinaryPersonController(IComplexEntityService service) + { + _service = service; + } + + [HttpGet] + public async Task GetAll() + { + var items = await _service.GetAllAsync(); + return Ok(items); + } + + [HttpGet("{id}")] + public async Task GetById(int id) + { + try + { + var item = await _service.GetByIdAsync(id); + return Ok(item); + } + catch (ArgumentException ex) when (ex.Message.Contains($"Entity with ID {id} not found.")) + { + return NotFound(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpPost] + public async Task Create([FromBody] OrdinaryPersonCreateRequest request) + { + try + { + var item = await _service.CreateAsync(request); + return CreatedAtAction(nameof(GetById), new { id = item.Id }, item); + } + catch (ArgumentException ex) + { + return Conflict(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpPut("{id}")] + public async Task Update(int id, [FromBody] OrdinaryPersonUpdateRequest request) + { + try + { + var item = await _service.UpdateAsync(id, request); + return Ok(item); + } + catch (ArgumentException ex) + { + return NotFound(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpDelete("{id}")] + public async Task Delete(int id) + { + try + { + var result = await _service.DeleteAsync(id); + if (!result) + return NotFound(new {Message = $"Item with {id} not found"}); + + return NoContent(); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + +} \ No newline at end of file diff --git a/backend/Controllers/SecondarySourceController.cs b/backend/Controllers/SecondarySourceController.cs new file mode 100644 index 0000000..7e0302c --- /dev/null +++ b/backend/Controllers/SecondarySourceController.cs @@ -0,0 +1,107 @@ +using Microsoft.AspNetCore.Mvc; +using Mappa.Services; +using Mappa.Dtos; +using Mappa.Entities; +using Microsoft.AspNetCore.Authorization; + +namespace Mappa.Controllers; + +[ApiController] +[Route("[controller]")] +public class SecondarySourceController : ControllerBase +{ + private readonly IComplexEntityService + _service; + + public SecondarySourceController(IComplexEntityService service) + { + _service = service; + } + + [HttpGet] + public async Task GetAll() + { + var items = await _service.GetAllAsync(); + return Ok(items); + } + + [HttpGet("{id}")] + public async Task GetById(int id) + { + try + { + var item = await _service.GetByIdAsync(id); + return Ok(item); + } + catch (ArgumentException ex) when (ex.Message.Contains($"Entity with ID {id} not found.")) + { + return NotFound(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpPost] + public async Task Create([FromBody] SecondarySourceCreateRequest request) + { + try + { + var item = await _service.CreateAsync(request); + return CreatedAtAction(nameof(GetById), new { id = item.Id }, item); + } + catch (ArgumentException ex) + { + return Conflict(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpPut("{id}")] + public async Task Update(int id, [FromBody] SecondarySourceUpdateRequest request) + { + try + { + var item = await _service.UpdateAsync(id, request); + return Ok(item); + } + catch (ArgumentException ex) + { + return NotFound(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpDelete("{id}")] + public async Task Delete(int id) + { + try + { + var result = await _service.DeleteAsync(id); + if (!result) + return NotFound(new {Message = $"Item with {id} not found"}); + + return NoContent(); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + +} \ No newline at end of file diff --git a/backend/Controllers/UnordinaryPersonController.cs b/backend/Controllers/UnordinaryPersonController.cs new file mode 100644 index 0000000..2d93db8 --- /dev/null +++ b/backend/Controllers/UnordinaryPersonController.cs @@ -0,0 +1,107 @@ +using Microsoft.AspNetCore.Mvc; +using Mappa.Services; +using Mappa.Dtos; +using Mappa.Entities; +using Microsoft.AspNetCore.Authorization; + +namespace Mappa.Controllers; + +[ApiController] +[Route("[controller]")] +public class UnordinaryPersonController : ControllerBase +{ + private readonly IComplexEntityService + _service; + + public UnordinaryPersonController(IComplexEntityService service) + { + _service = service; + } + + [HttpGet] + public async Task GetAll() + { + var items = await _service.GetAllAsync(); + return Ok(items); + } + + [HttpGet("{id}")] + public async Task GetById(int id) + { + try + { + var item = await _service.GetByIdAsync(id); + return Ok(item); + } + catch (ArgumentException ex) when (ex.Message.Contains($"Entity with ID {id} not found.")) + { + return NotFound(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpPost] + public async Task Create([FromBody] UnordinaryPersonCreateRequest request) + { + try + { + var item = await _service.CreateAsync(request); + return CreatedAtAction(nameof(GetById), new { id = item.Id }, item); + } + catch (ArgumentException ex) + { + return Conflict(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpPut("{id}")] + public async Task Update(int id, [FromBody] UnordinaryPersonUpdateRequest request) + { + try + { + var item = await _service.UpdateAsync(id, request); + return Ok(item); + } + catch (ArgumentException ex) + { + return NotFound(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpDelete("{id}")] + public async Task Delete(int id) + { + try + { + var result = await _service.DeleteAsync(id); + if (!result) + return NotFound(new {Message = $"Item with {id} not found"}); + + return NoContent(); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + +} \ No newline at end of file diff --git a/backend/Controllers/WrittenSourceController.cs b/backend/Controllers/WrittenSourceController.cs new file mode 100644 index 0000000..18b79ef --- /dev/null +++ b/backend/Controllers/WrittenSourceController.cs @@ -0,0 +1,107 @@ +using Microsoft.AspNetCore.Mvc; +using Mappa.Services; +using Mappa.Dtos; +using Mappa.Entities; +using Microsoft.AspNetCore.Authorization; + +namespace Mappa.Controllers; + +[ApiController] +[Route("[controller]")] +public class WrittenSourceController : ControllerBase +{ + private readonly IComplexEntityService + _service; + + public WrittenSourceController(IComplexEntityService service) + { + _service = service; + } + + [HttpGet] + public async Task GetAll() + { + var items = await _service.GetAllAsync(); + return Ok(items); + } + + [HttpGet("{id}")] + public async Task GetById(int id) + { + try + { + var item = await _service.GetByIdAsync(id); + return Ok(item); + } + catch (ArgumentException ex) when (ex.Message.Contains($"Entity with ID {id} not found.")) + { + return NotFound(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpPost] + public async Task Create([FromBody] WrittenSourceCreateRequest request) + { + try + { + var item = await _service.CreateAsync(request); + return CreatedAtAction(nameof(GetById), new { id = item.Id }, item); + } + catch (ArgumentException ex) + { + return Conflict(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpPut("{id}")] + public async Task Update(int id, [FromBody] WrittenSourceUpdateRequest request) + { + try + { + var item = await _service.UpdateAsync(id, request); + return Ok(item); + } + catch (ArgumentException ex) + { + return NotFound(new { Message = ex.Message }); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + + [Authorize] + [HttpDelete("{id}")] + public async Task Delete(int id) + { + try + { + var result = await _service.DeleteAsync(id); + if (!result) + return NotFound(new {Message = $"Item with {id} not found"}); + + return NoContent(); + } + catch (Exception ex) + { + // Log the exception (optional) + return StatusCode(500, new { Message = "An unexpected error occurred.", Details = ex.Message }); + } + } + +} \ No newline at end of file diff --git a/backend/Db/AppDbContext.cs b/backend/Db/AppDbContext.cs index 9ccd823..f6e281a 100644 --- a/backend/Db/AppDbContext.cs +++ b/backend/Db/AppDbContext.cs @@ -7,13 +7,14 @@ namespace Mappa.Db; public class AppDbContext : IdentityDbContext { + public DbSet Cities { get; set; } public DbSet Ethnicities { get; set; } public DbSet Genders { get; set; } public DbSet Genres { get; set; } public DbSet Languages { get; set; } public DbSet OrdinaryPersons { get; set; } public DbSet Professions { get; set; } - public DbSet Relations { get; set; } + // public DbSet Relations { get; set; } public DbSet Religions { get; set; } public DbSet SecondarySources { get; set; } public DbSet Types { get; set; } @@ -35,9 +36,7 @@ protected override void OnModelCreating(ModelBuilder builder) e => e.HasOne().WithMany().HasForeignKey(e => e.PersonIdA), e => e.HasOne().WithMany().HasForeignKey(e => e.PersonIdB) ); - builder.Entity() - .HasMany(e => e.InteractionsWithUnordinary) - .WithMany(e => e.InteractionsWithOrdinary); + builder.Entity() .HasMany(e => e.InteractionsWithUnordinaryA) .WithMany(e => e.InteractionsWithUnordinaryB) diff --git a/backend/Dockerfile b/backend/Dockerfile index 00b6a23..1a1eb81 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,14 +1,20 @@ FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /source +ARG DATABASE_CONNECTION_STRING +# ENV DATABASE_CONNECTION_STRING=${DATABASE_CONNECTION_STRING} + # copy csproj and restore as distinct layers COPY *.sln . COPY *.csproj ./ RUN dotnet restore +# install dotnet ef +RUN dotnet tool install --version 8.0.11 --create-manifest-if-needed dotnet-ef # copy everything else and build app COPY . ./ WORKDIR /source/ +RUN dotnet ef database update --connection "$DATABASE_CONNECTION_STRING" RUN dotnet publish -c release -o /app # final stage/image diff --git a/backend/Dtos/CityDto.cs b/backend/Dtos/CityDto.cs new file mode 100644 index 0000000..d01d8bc --- /dev/null +++ b/backend/Dtos/CityDto.cs @@ -0,0 +1,37 @@ +using System.ComponentModel.DataAnnotations; + +namespace Mappa.Dtos; + +public class CityBaseDto +{ + public int Id { get; set; } + public string AsciiName { get; set; } +} + +public class CityGeneralDto : CityBaseDto +{ +} + +public class CityDetailDto : CityGeneralDto +{ + public string? GeoNamesId {get; set;} + public List? AlternateNames {get; set;} + public string? CountryCode {get; set;} +} + +public class CityCreateRequest +{ + [Required] + public string AsciiName { get; set; } + public string? GeoNamesId { get; set; } + public List? AlternateNames { get; set; } + public string? CountryCode { get; set; } +} + +public class CityUpdateRequest +{ + public string? AsciiName { get; set; } + public string? GeoNamesId { get; set; } + public List? AlternateNames { get; set; } + public string? CountryCode { get; set; } +} diff --git a/backend/Dtos/OrdinaryPersonDto.cs b/backend/Dtos/OrdinaryPersonDto.cs new file mode 100644 index 0000000..511fcd2 --- /dev/null +++ b/backend/Dtos/OrdinaryPersonDto.cs @@ -0,0 +1,103 @@ +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks.Dataflow; +using Mappa.Entities; +using Microsoft.OpenApi.Expressions; + +namespace Mappa.Dtos; + +public class OrdinaryPersonBaseDto +{ + public int Id { get; set; } + public string Name { get; set; } +} + +public class OrdinaryPersonGeneralDto : OrdinaryPersonBaseDto +{ + public ReligionDto? Religion {get; set;} + public EthnicityDto? Ethnicity {get; set;} + public ProfessionDto? Profession {get; set;} + public CityBaseDto? Location {get; set;} + public List? Sources {get; set;} + public GenderDto? Gender {get; set;} +} + +public class OrdinaryPersonDetailDto : OrdinaryPersonGeneralDto +{ + public string? AlternateName {get; set;} + public List? BirthYear {get; set;} + public List? DeathYear {get; set;} + public int? ProbableBirthYear {get; set;} + public int? ProbableDeathYear {get; set;} + public string? Description {get; set;} + public List? FormerReligion {get; set;} + public string? ReligionExplanation{get; set;} + public string? ProfessionExplanation{get; set;} + public string? InterestingFeature{get; set;} + public string? InteractionWithOrdinaryExplanation{get; set;} + public string? InteractionWithUnordinaryExplanation{get; set;} + public string? Biography{get; set;} + public string? DepictionInTheSource{get; set;} + public string? ExplanationOfEthnicity{get; set;} + public List? InteractionsWithOrdinaryA{get; set;} + public List? InteractionsWithUnordinary{get; set;} + public CityBaseDto? BackgroundCity {get; set;} +} + +public class OrdinaryPersonCreateRequest +{ + [Required] + public string Name { get; set; } + public string? Religion {get; set;} + public string? Ethnicity {get; set;} + public string? Profession {get; set;} + public string? Location {get; set;} + public List? Sources {get; set;} + public string? Gender {get; set;} + public string? AlternateName {get; set;} + public List? BirthYear {get; set;} + public List? DeathYear {get; set;} + public int? ProbableBirthYear {get; set;} + public int? ProbableDeathYear {get; set;} + public string? Description {get; set;} + public List? FormerReligion {get; set;} + public string? ReligionExplanation{get; set;} + public string? ProfessionExplanation{get; set;} + public string? InterestingFeature{get; set;} + public string? InteractionWithOrdinaryExplanation{get; set;} + public string? InteractionWithUnordinaryExplanation{get; set;} + public string? Biography{get; set;} + public string? DepictionInTheSource{get; set;} + public string? ExplanationOfEthnicity{get; set;} + public List? InteractionsWithOrdinaryA{get; set;} + public List? InteractionsWithUnordinary{get; set;} + public string? BackgroundCity {get; set;} +} + +public class OrdinaryPersonUpdateRequest +{ + public string? Name { get; set; } + public string? Religion {get; set;} + public string? Ethnicity {get; set;} + public string? Profession {get; set;} + public string? Location {get; set;} + public List? Sources {get; set;} + public string? Gender {get; set;} + public string? AlternateName {get; set;} + public List? BirthYear {get; set;} + public List? DeathYear {get; set;} + public int? ProbableBirthYear {get; set;} + public int? ProbableDeathYear {get; set;} + public string? Description {get; set;} + public List? FormerReligion {get; set;} + public string? ReligionExplanation{get; set;} + public string? ProfessionExplanation{get; set;} + public string? InterestingFeature{get; set;} + public string? InteractionWithOrdinaryExplanation{get; set;} + public string? InteractionWithUnordinaryExplanation{get; set;} + public string? Biography{get; set;} + public string? DepictionInTheSource{get; set;} + public string? ExplanationOfEthnicity{get; set;} + public List? InteractionsWithOrdinaryA{get; set;} + public List? InteractionsWithUnordinary{get; set;} + public string? BackgroundCity {get; set;} +} diff --git a/backend/Dtos/SecondarySourceDto.cs b/backend/Dtos/SecondarySourceDto.cs new file mode 100644 index 0000000..82394f0 --- /dev/null +++ b/backend/Dtos/SecondarySourceDto.cs @@ -0,0 +1,60 @@ +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks.Dataflow; +using Mappa.Entities; +using Microsoft.OpenApi.Expressions; + +namespace Mappa.Dtos; + +public class SecondarySourceBaseDto +{ + public int Id {get; set;} + public List? AlternateNames {get; set;} + +} + +public class SecondarySourceGeneralDto : SecondarySourceBaseDto +{ + public string? Author {get; set;} + public int? YearWritten {get; set;} + public string? University {get; set;} + public TypeDto? Type {get; set;} +} + +public class SecondarySourceDetailDto : SecondarySourceGeneralDto +{ + public string? Topic {get; set;} + public string? BibliographyInformation {get; set;} + public string? OtherInformation {get; set;} + public LanguageDto? Language {get; set;} + public List? TranslatedLanguages {get; set;} +} + +// Field-classes are received as string, but they are stored in the db as classes +public class SecondarySourceCreateRequest +{ + [Required] + public List? AlternateNames {get; set;} + public string? Author {get; set;} + public int? YearWritten {get; set;} + public string? University {get; set;} + public string? Type {get; set;} + public string? Topic {get; set;} + public string? BibliographyInformation {get; set;} + public string? OtherInformation {get; set;} + public string? Language {get; set;} + public List? TranslatedLanguages {get; set;} +} + +public class SecondarySourceUpdateRequest +{ + public List? AlternateNames {get; set;} + public string? Author {get; set;} + public int? YearWritten {get; set;} + public string? University {get; set;} + public string? Type {get; set;} + public string? Topic {get; set;} + public string? BibliographyInformation {get; set;} + public string? OtherInformation {get; set;} + public string? Language {get; set;} + public List? TranslatedLanguages {get; set;} +} diff --git a/backend/Dtos/UnordinaryPersonDto.cs b/backend/Dtos/UnordinaryPersonDto.cs new file mode 100644 index 0000000..f919b1e --- /dev/null +++ b/backend/Dtos/UnordinaryPersonDto.cs @@ -0,0 +1,81 @@ +using System.ComponentModel.DataAnnotations; +using Mappa.Entities; + +namespace Mappa.Dtos; + +public class UnordinaryPersonBaseDto +{ + public int Id { get; set; } + public string Name { get; set; } +} + +public class UnordinaryPersonGeneralDto : UnordinaryPersonBaseDto +{ + public ReligionDto? Religion {get; set;} + public EthnicityDto? Ethnicity {get; set;} + public List? DeathYear {get; set;} + public CityBaseDto? DeathPlace {get; set;} + public List? InteractionsWithOrdinary {get; set;} + +} + +public class UnordinaryPersonDetailDto : UnordinaryPersonGeneralDto +{ + public string? AlternateName {get; set;} + public List? BirthYear {get; set;} + public int? ProbableBirthYear {get; set;} + public int? ProbableDeathYear {get; set;} + public string? Description {get; set;} + public List? FormerReligion {get; set;} + public ProfessionDto? Profession {get; set;} + public GenderDto? Gender {get; set;} + public CityBaseDto? BirthPlace {get; set;} + public List? InteractionsWithUnordinaryA {get; set;} + public List? InteractionsWithUnordinaryB {get; set;} + public List? Sources {get; set;} +} + +// Simple entities will be denoted by their Names. +// Complex entities with their ids +public class UnordinaryPersonCreateRequest +{ + [Required] + public string Name { get; set; } + public string? Religion {get; set;} + public string? Ethnicity {get; set;} + public List? DeathYear {get; set;} + public string? DeathPlace {get; set;} + public List? InteractionsWithOrdinary {get; set;} + public string? AlternateName {get; set;} + public List? BirthYear {get; set;} + public int? ProbableBirthYear {get; set;} + public int? ProbableDeathYear {get; set;} + public string? Description {get; set;} + public List? FormerReligion {get; set;} + public string? Profession {get; set;} + public string? Gender {get; set;} + public string? BirthPlace {get; set;} + public List? InteractionsWithUnordinaryA {get; set;} + public List? Sources {get; set;} +} + +public class UnordinaryPersonUpdateRequest +{ + public string? Name { get; set; } + public string? Religion {get; set;} + public string? Ethnicity {get; set;} + public List? DeathYear {get; set;} + public string? DeathPlace {get; set;} + public List? InteractionsWithOrdinary {get; set;} + public string? AlternateName {get; set;} + public List? BirthYear {get; set;} + public int? ProbableBirthYear {get; set;} + public int? ProbableDeathYear {get; set;} + public string? Description {get; set;} + public List? FormerReligion {get; set;} + public string? Profession {get; set;} + public string? Gender {get; set;} + public string? BirthPlace {get; set;} + public List? InteractionsWithUnordinaryA {get; set;} + public List? Sources {get; set;} +} diff --git a/backend/Dtos/WrittenSourceDto.cs b/backend/Dtos/WrittenSourceDto.cs new file mode 100644 index 0000000..9551c9b --- /dev/null +++ b/backend/Dtos/WrittenSourceDto.cs @@ -0,0 +1,72 @@ +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks.Dataflow; +using Mappa.Entities; +using Microsoft.OpenApi.Expressions; + +namespace Mappa.Dtos; + +public class WrittenSourceBaseDto +{ + public int Id {get; set;} + public List? AlternateNames {get; set;} + +} + +public class WrittenSourceGeneralDto : WrittenSourceBaseDto +{ + public string? Author {get; set;} + public List? YearWritten {get; set;} + public GenreDto? Genre {get; set;} + public LanguageDto? Language {get; set;} +} + +public class WrittenSourceDetailDto : WrittenSourceGeneralDto +{ + public List? KnownCopies {get; set;} + public List? SurvivedCopies {get; set;} + public string? LibraryInformation {get; set;} + public string? OtherInformation {get; set;} + public string? RemarkableWorksOnTheBook {get; set;} + public string? Image {get; set;} + public List? TranslatedLanguages {get; set;} + public List? CitiesMentioningTheSources {get; set;} + public List? CitiesWhereSourcesAreWritten {get; set;} +} + +public class WrittenSourceCreateRequest +{ + [Required] + public List? AlternateNames {get; set;} + public string? Author {get; set;} + public List? YearWritten {get; set;} + public string? Genre {get; set;} + public string? Language {get; set;} + public List? KnownCopies {get; set;} + public List? SurvivedCopies {get; set;} + public string? LibraryInformation {get; set;} + public string? OtherInformation {get; set;} + public string? RemarkableWorksOnTheBook {get; set;} + public string? Image {get; set;} + public List? TranslatedLanguages {get; set;} + public List? CitiesMentioningTheSources {get; set;} + public List? CitiesWhereSourcesAreWritten {get; set;} + +} + +public class WrittenSourceUpdateRequest +{ + public List? AlternateNames {get; set;} + public string? Author {get; set;} + public List? YearWritten {get; set;} + public string? Genre {get; set;} + public string? Language {get; set;} + public List? KnownCopies {get; set;} + public List? SurvivedCopies {get; set;} + public string? LibraryInformation {get; set;} + public string? OtherInformation {get; set;} + public string? RemarkableWorksOnTheBook {get; set;} + public string? Image {get; set;} + public List? TranslatedLanguages {get; set;} + public List? CitiesMentioningTheSources {get; set;} + public List? CitiesWhereSourcesAreWritten {get; set;} +} diff --git a/backend/Entities/City.cs b/backend/Entities/City.cs new file mode 100644 index 0000000..450311d --- /dev/null +++ b/backend/Entities/City.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Diagnostics.CodeAnalysis; +using Microsoft.AspNetCore.Identity; + +namespace Mappa.Entities; + +public class City +{ + [Key] + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public int Id {get; set;} + [Required] + public string AsciiName {get; set;} + public string? GeoNamesId {get; set;} + public List? AlternateNames {get; set;} + public string? CountryCode {get; set;} +} \ No newline at end of file diff --git a/backend/Entities/OrdinaryPerson.cs b/backend/Entities/OrdinaryPerson.cs index fdaf5f8..34183d0 100644 --- a/backend/Entities/OrdinaryPerson.cs +++ b/backend/Entities/OrdinaryPerson.cs @@ -12,13 +12,16 @@ public class OrdinaryPerson : Person public string? Biography{get; set;} public string? DepictionInTheSource{get; set;} public string? ExplanationOfEthnicity{get; set;} - public Relation? Relation{get; set;} + // public Relation? Relation{get; set;} [Required] - public List InteractionsWithOrdinaryA{get; set;} + public List? InteractionsWithOrdinaryA{get; set;} [Required] - public List InteractionsWithOrdinaryB{get; set;} + public List? InteractionsWithOrdinaryB{get; set;} [Required] - public List InteractionsWithUnordinary{get; set;} + public List? InteractionsWithUnordinary{get; set;} + public City? Location {get; set;} + public City? BackgroundCity {get; set;} + } public class IntraOrdinary diff --git a/backend/Entities/Person.cs b/backend/Entities/Person.cs index 5e394da..bacb68f 100644 --- a/backend/Entities/Person.cs +++ b/backend/Entities/Person.cs @@ -13,14 +13,15 @@ public abstract class Person [Required] public string Name {get; set;} public string? AlternateName {get; set;} - public string? Depiction {get; set;} - public DateOnly? BirthYear {get; set;} - public DateOnly? DeathYear {get; set;} + public List? BirthYear {get; set;} + public List? DeathYear {get; set;} + public int? ProbableBirthYear {get; set;} + public int? ProbableDeathYear {get; set;} public string? Description {get; set;} public Ethnicity? Ethnicity {get; set;} public Religion? Religion {get; set;} - public Religion? FormerReligion {get; set;} + public List? FormerReligion {get; set;} public Profession? Profession {get; set;} public Gender? Gender {get; set;} - + public List? Sources {get; set;} } \ No newline at end of file diff --git a/backend/Entities/SecondarySource.cs b/backend/Entities/SecondarySource.cs index d7d982a..8b4b7c0 100644 --- a/backend/Entities/SecondarySource.cs +++ b/backend/Entities/SecondarySource.cs @@ -11,19 +11,14 @@ public class SecondarySource [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id {get; set;} [Required] - public string[] AlternateNames {get; set;} + public List? AlternateNames {get; set;} public string? Author {get; set;} public string? Topic {get; set;} - public DateOnly? YearWritten {get; set;} + public int? YearWritten {get; set;} public string? University {get; set;} public string? BibliographyInformation {get; set;} public string? OtherInformation {get; set;} - [Required] - public Type Type {get; set;} - [Required] - public Language Language {get; set;} - [Required] - public List TranslatedLanguages {get; set;} - - + public Type? Type {get; set;} + public Language? Language {get; set;} + public List? TranslatedLanguages {get; set;} } \ No newline at end of file diff --git a/backend/Entities/UnordinaryPerson.cs b/backend/Entities/UnordinaryPerson.cs index ea8a319..a7383e1 100644 --- a/backend/Entities/UnordinaryPerson.cs +++ b/backend/Entities/UnordinaryPerson.cs @@ -7,11 +7,14 @@ namespace Mappa.Entities; public class UnordinaryPerson : Person { [Required] - public List InteractionsWithOrdinary{get; set;} + public List? InteractionsWithOrdinary{get; set;} [Required] - public List InteractionsWithUnordinaryA{get; set;} + public List? InteractionsWithUnordinaryA{get; set;} [Required] - public List InteractionsWithUnordinaryB{get; set;} + public List? InteractionsWithUnordinaryB{get; set;} + public City? BirthPlace {get; set;} + public City? DeathPlace {get; set;} + } public class IntraUnordinary diff --git a/backend/Entities/WrittenSource.cs b/backend/Entities/WrittenSource.cs index 89f1b51..9e0f46f 100644 --- a/backend/Entities/WrittenSource.cs +++ b/backend/Entities/WrittenSource.cs @@ -11,24 +11,19 @@ public class WrittenSource [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id {get; set;} [Required] - public string[] AlternateNames {get; set;} + public List? AlternateNames {get; set;} public string? Author {get; set;} - public DateOnly? YearWritten {get; set;} - [Required] - public string[] KnownCopies {get; set;} - [Required] - public string[] SurvivedCopies {get; set;} + public List? YearWritten {get; set;} + public List? KnownCopies {get; set;} + public List? SurvivedCopies {get; set;} public string? LibraryInformation {get; set;} public string? OtherInformation {get; set;} public string? RemarkableWorksOnTheBook {get; set;} public string? Image {get; set;} - public bool Patronage {get; set;} - [Required] - public Genre Genre {get; set;} - [Required] - public Language Language {get; set;} - [Required] - public List TranslatedLanguages {get; set;} - + public Genre? Genre {get; set;} + public Language? Language {get; set;} + public List? TranslatedLanguages {get; set;} + public List? CitiesMentioningTheSources {get; set;} + public List? CitiesWhereSourcesAreWritten {get; set;} } \ No newline at end of file diff --git a/backend/Helpers/MappingProfile.cs b/backend/Helpers/MappingProfile.cs new file mode 100644 index 0000000..87b6601 --- /dev/null +++ b/backend/Helpers/MappingProfile.cs @@ -0,0 +1,39 @@ +using AutoMapper; +using Mappa.Entities; +using Mappa.Dtos; +using System.Threading.Tasks.Dataflow; + +namespace Mappa.Helpers; + +public class MappingProfile : Profile +{ + public MappingProfile() + { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); + // CreateMap() + // .ForMember(dest => dest.Genre, opt => opt.MapFrom(src => src.Genre != null ? new GenreDto { Id = src.Genre.Id, Name = src.Genre.Name } : null)) + // .ForMember(dest => dest.Language, opt => opt.MapFrom(src => src.Language != null ? new LanguageDto { Id = src.Language.Id, Name = src.Language.Name } : null)); + + // CreateMap() + // .ForMember(dest => dest.Genre, opt => opt.MapFrom(src => src.Genre != null ? new GenreDto { Id = src.Genre.Id, Name = src.Genre.Name } : null)) + // .ForMember(dest => dest.Language, opt => opt.MapFrom(src => src.Language != null ? new LanguageDto { Id = src.Language.Id, Name = src.Language.Name } : null)) + // .ForMember(dest => dest.TranslatedLanguages, opt => opt.MapFrom(src => src.TranslatedLanguages.Select(tl => new LanguageDto { Id = tl.Id, Name = tl.Name }).ToList())) + // .ForMember(dest => dest.CitiesMentioningTheSources, opt => opt.MapFrom(src => src.CitiesMentioningTheSources.Select(cmts => new CityBaseDto { Id = cmts.Id, Name = cmts.Name }).ToList())) + // .ForMember(dest => dest.CitiesWhereSourcesAreWritten, opt => opt.MapFrom(src => src.CitiesWhereSourcesAreWritten.Select(cwsaw => new CityBaseDto { Id = cwsaw.Id, Name = cwsaw.Name }).ToList())); + + // CreateMap(); + // CreateMap(); + + } +} diff --git a/backend/Migrations/20250131180400_SourcesPersonsCity.Designer.cs b/backend/Migrations/20250131180400_SourcesPersonsCity.Designer.cs new file mode 100644 index 0000000..da59ed6 --- /dev/null +++ b/backend/Migrations/20250131180400_SourcesPersonsCity.Designer.cs @@ -0,0 +1,980 @@ +// +using System; +using System.Collections.Generic; +using Mappa.Db; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace mappa.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20250131180400_SourcesPersonsCity")] + partial class SourcesPersonsCity + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Mappa.Entities.City", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("AlternateNames") + .HasColumnType("text[]"); + + b.Property("AsciiName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CountryCode") + .HasColumnType("text"); + + b.Property("GeoNamesId") + .HasColumnType("text"); + + b.Property("WrittenSourceId") + .HasColumnType("integer"); + + b.Property("WrittenSourceId1") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WrittenSourceId"); + + b.HasIndex("WrittenSourceId1"); + + b.ToTable("Cities"); + }); + + modelBuilder.Entity("Mappa.Entities.Ethnicity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Ethnicities"); + }); + + modelBuilder.Entity("Mappa.Entities.Gender", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Genders"); + }); + + modelBuilder.Entity("Mappa.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Genres"); + }); + + modelBuilder.Entity("Mappa.Entities.IntraOrdinary", b => + { + b.Property("PersonIdA") + .HasColumnType("integer"); + + b.Property("PersonIdB") + .HasColumnType("integer"); + + b.HasKey("PersonIdA", "PersonIdB"); + + b.HasIndex("PersonIdB"); + + b.ToTable("IntraOrdinary"); + }); + + modelBuilder.Entity("Mappa.Entities.IntraUnordinary", b => + { + b.Property("PersonIdA") + .HasColumnType("integer"); + + b.Property("PersonIdB") + .HasColumnType("integer"); + + b.HasKey("PersonIdA", "PersonIdB"); + + b.HasIndex("PersonIdB"); + + b.ToTable("IntraUnordinary"); + }); + + modelBuilder.Entity("Mappa.Entities.Language", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SecondarySourceId") + .HasColumnType("integer"); + + b.Property("WrittenSourceId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SecondarySourceId"); + + b.HasIndex("WrittenSourceId"); + + b.ToTable("Languages"); + }); + + modelBuilder.Entity("Mappa.Entities.OrdinaryPerson", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AlternateName") + .HasColumnType("text"); + + b.Property("BackgroundCityId") + .HasColumnType("integer"); + + b.Property("Biography") + .HasColumnType("text"); + + b.Property>("BirthYear") + .HasColumnType("integer[]"); + + b.Property>("DeathYear") + .HasColumnType("integer[]"); + + b.Property("DepictionInTheSource") + .HasColumnType("text"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EthnicityId") + .HasColumnType("integer"); + + b.Property("ExplanationOfEthnicity") + .HasColumnType("text"); + + b.Property("GenderId") + .HasColumnType("integer"); + + b.Property("InteractionWithOrdinaryExplanation") + .HasColumnType("text"); + + b.Property("InteractionWithUnordinaryExplanation") + .HasColumnType("text"); + + b.Property("InterestingFeature") + .HasColumnType("text"); + + b.Property("LocationId") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProbableBirthYear") + .HasColumnType("integer"); + + b.Property("ProbableDeathYear") + .HasColumnType("integer"); + + b.Property("ProfessionExplanation") + .HasColumnType("text"); + + b.Property("ProfessionId") + .HasColumnType("integer"); + + b.Property("ReligionExplanation") + .HasColumnType("text"); + + b.Property("ReligionId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("BackgroundCityId"); + + b.HasIndex("EthnicityId"); + + b.HasIndex("GenderId"); + + b.HasIndex("LocationId"); + + b.HasIndex("ProfessionId"); + + b.HasIndex("ReligionId"); + + b.ToTable("OrdinaryPersons"); + }); + + modelBuilder.Entity("Mappa.Entities.Profession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Professions"); + }); + + modelBuilder.Entity("Mappa.Entities.Religion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrdinaryPersonId") + .HasColumnType("integer"); + + b.Property("UnordinaryPersonId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrdinaryPersonId"); + + b.HasIndex("UnordinaryPersonId"); + + b.ToTable("Religions"); + }); + + modelBuilder.Entity("Mappa.Entities.SecondarySource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("AlternateNames") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("Author") + .HasColumnType("text"); + + b.Property("BibliographyInformation") + .HasColumnType("text"); + + b.Property("LanguageId") + .HasColumnType("integer"); + + b.Property("OtherInformation") + .HasColumnType("text"); + + b.Property("Topic") + .HasColumnType("text"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.Property("University") + .HasColumnType("text"); + + b.Property("YearWritten") + .HasColumnType("date"); + + b.HasKey("Id"); + + b.HasIndex("LanguageId"); + + b.HasIndex("TypeId"); + + b.ToTable("SecondarySources"); + }); + + modelBuilder.Entity("Mappa.Entities.Type", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Types"); + }); + + modelBuilder.Entity("Mappa.Entities.UnordinaryPerson", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AlternateName") + .HasColumnType("text"); + + b.Property("BirthPlaceId") + .HasColumnType("integer"); + + b.Property>("BirthYear") + .HasColumnType("integer[]"); + + b.Property("DeathPlaceId") + .HasColumnType("integer"); + + b.Property>("DeathYear") + .HasColumnType("integer[]"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EthnicityId") + .HasColumnType("integer"); + + b.Property("GenderId") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProbableBirthYear") + .HasColumnType("integer"); + + b.Property("ProbableDeathYear") + .HasColumnType("integer"); + + b.Property("ProfessionId") + .HasColumnType("integer"); + + b.Property("ReligionId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("BirthPlaceId"); + + b.HasIndex("DeathPlaceId"); + + b.HasIndex("EthnicityId"); + + b.HasIndex("GenderId"); + + b.HasIndex("ProfessionId"); + + b.HasIndex("ReligionId"); + + b.ToTable("UnordinaryPersons"); + }); + + modelBuilder.Entity("Mappa.Entities.User", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Mappa.Entities.WrittenSource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("AlternateNames") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("Author") + .HasColumnType("text"); + + b.Property("GenreId") + .HasColumnType("integer"); + + b.Property("Image") + .HasColumnType("text"); + + b.Property>("KnownCopies") + .HasColumnType("text[]"); + + b.Property("LanguageId") + .HasColumnType("integer"); + + b.Property("LibraryInformation") + .HasColumnType("text"); + + b.Property("OrdinaryPersonId") + .HasColumnType("integer"); + + b.Property("OtherInformation") + .HasColumnType("text"); + + b.Property("RemarkableWorksOnTheBook") + .HasColumnType("text"); + + b.Property>("SurvivedCopies") + .HasColumnType("text[]"); + + b.Property("UnordinaryPersonId") + .HasColumnType("integer"); + + b.Property>("YearWritten") + .HasColumnType("integer[]"); + + b.HasKey("Id"); + + b.HasIndex("GenreId"); + + b.HasIndex("LanguageId"); + + b.HasIndex("OrdinaryPersonId"); + + b.HasIndex("UnordinaryPersonId"); + + b.ToTable("WrittenSources"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("OrdinaryPersonUnordinaryPerson", b => + { + b.Property("InteractionsWithOrdinaryId") + .HasColumnType("integer"); + + b.Property("InteractionsWithUnordinaryId") + .HasColumnType("integer"); + + b.HasKey("InteractionsWithOrdinaryId", "InteractionsWithUnordinaryId"); + + b.HasIndex("InteractionsWithUnordinaryId"); + + b.ToTable("OrdinaryPersonUnordinaryPerson"); + }); + + modelBuilder.Entity("Mappa.Entities.City", b => + { + b.HasOne("Mappa.Entities.WrittenSource", null) + .WithMany("CitiesMentioningTheSources") + .HasForeignKey("WrittenSourceId"); + + b.HasOne("Mappa.Entities.WrittenSource", null) + .WithMany("CitiesWhereSourcesAreWritten") + .HasForeignKey("WrittenSourceId1"); + }); + + modelBuilder.Entity("Mappa.Entities.IntraOrdinary", b => + { + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany() + .HasForeignKey("PersonIdA") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany() + .HasForeignKey("PersonIdB") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Mappa.Entities.IntraUnordinary", b => + { + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany() + .HasForeignKey("PersonIdA") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany() + .HasForeignKey("PersonIdB") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Mappa.Entities.Language", b => + { + b.HasOne("Mappa.Entities.SecondarySource", null) + .WithMany("TranslatedLanguages") + .HasForeignKey("SecondarySourceId"); + + b.HasOne("Mappa.Entities.WrittenSource", null) + .WithMany("TranslatedLanguages") + .HasForeignKey("WrittenSourceId"); + }); + + modelBuilder.Entity("Mappa.Entities.OrdinaryPerson", b => + { + b.HasOne("Mappa.Entities.City", "BackgroundCity") + .WithMany() + .HasForeignKey("BackgroundCityId"); + + b.HasOne("Mappa.Entities.Ethnicity", "Ethnicity") + .WithMany() + .HasForeignKey("EthnicityId"); + + b.HasOne("Mappa.Entities.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId"); + + b.HasOne("Mappa.Entities.City", "Location") + .WithMany() + .HasForeignKey("LocationId"); + + b.HasOne("Mappa.Entities.Profession", "Profession") + .WithMany() + .HasForeignKey("ProfessionId"); + + b.HasOne("Mappa.Entities.Religion", "Religion") + .WithMany() + .HasForeignKey("ReligionId"); + + b.Navigation("BackgroundCity"); + + b.Navigation("Ethnicity"); + + b.Navigation("Gender"); + + b.Navigation("Location"); + + b.Navigation("Profession"); + + b.Navigation("Religion"); + }); + + modelBuilder.Entity("Mappa.Entities.Religion", b => + { + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany("FormerReligion") + .HasForeignKey("OrdinaryPersonId"); + + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany("FormerReligion") + .HasForeignKey("UnordinaryPersonId"); + }); + + modelBuilder.Entity("Mappa.Entities.SecondarySource", b => + { + b.HasOne("Mappa.Entities.Language", "Language") + .WithMany() + .HasForeignKey("LanguageId"); + + b.HasOne("Mappa.Entities.Type", "Type") + .WithMany() + .HasForeignKey("TypeId"); + + b.Navigation("Language"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Mappa.Entities.UnordinaryPerson", b => + { + b.HasOne("Mappa.Entities.City", "BirthPlace") + .WithMany() + .HasForeignKey("BirthPlaceId"); + + b.HasOne("Mappa.Entities.City", "DeathPlace") + .WithMany() + .HasForeignKey("DeathPlaceId"); + + b.HasOne("Mappa.Entities.Ethnicity", "Ethnicity") + .WithMany() + .HasForeignKey("EthnicityId"); + + b.HasOne("Mappa.Entities.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId"); + + b.HasOne("Mappa.Entities.Profession", "Profession") + .WithMany() + .HasForeignKey("ProfessionId"); + + b.HasOne("Mappa.Entities.Religion", "Religion") + .WithMany() + .HasForeignKey("ReligionId"); + + b.Navigation("BirthPlace"); + + b.Navigation("DeathPlace"); + + b.Navigation("Ethnicity"); + + b.Navigation("Gender"); + + b.Navigation("Profession"); + + b.Navigation("Religion"); + }); + + modelBuilder.Entity("Mappa.Entities.WrittenSource", b => + { + b.HasOne("Mappa.Entities.Genre", "Genre") + .WithMany() + .HasForeignKey("GenreId"); + + b.HasOne("Mappa.Entities.Language", "Language") + .WithMany() + .HasForeignKey("LanguageId"); + + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany("Sources") + .HasForeignKey("OrdinaryPersonId"); + + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany("Sources") + .HasForeignKey("UnordinaryPersonId"); + + b.Navigation("Genre"); + + b.Navigation("Language"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Mappa.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Mappa.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mappa.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Mappa.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("OrdinaryPersonUnordinaryPerson", b => + { + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany() + .HasForeignKey("InteractionsWithOrdinaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany() + .HasForeignKey("InteractionsWithUnordinaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Mappa.Entities.OrdinaryPerson", b => + { + b.Navigation("FormerReligion"); + + b.Navigation("Sources"); + }); + + modelBuilder.Entity("Mappa.Entities.SecondarySource", b => + { + b.Navigation("TranslatedLanguages"); + }); + + modelBuilder.Entity("Mappa.Entities.UnordinaryPerson", b => + { + b.Navigation("FormerReligion"); + + b.Navigation("Sources"); + }); + + modelBuilder.Entity("Mappa.Entities.WrittenSource", b => + { + b.Navigation("CitiesMentioningTheSources"); + + b.Navigation("CitiesWhereSourcesAreWritten"); + + b.Navigation("TranslatedLanguages"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/Migrations/20250131180400_SourcesPersonsCity.cs b/backend/Migrations/20250131180400_SourcesPersonsCity.cs new file mode 100644 index 0000000..74dc44f --- /dev/null +++ b/backend/Migrations/20250131180400_SourcesPersonsCity.cs @@ -0,0 +1,839 @@ +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace mappa.Migrations +{ + /// + public partial class SourcesPersonsCity : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_OrdinaryPersons_Relations_RelationId", + table: "OrdinaryPersons"); + + migrationBuilder.DropForeignKey( + name: "FK_OrdinaryPersons_Religions_FormerReligionId", + table: "OrdinaryPersons"); + + migrationBuilder.DropForeignKey( + name: "FK_SecondarySources_Languages_LanguageId", + table: "SecondarySources"); + + migrationBuilder.DropForeignKey( + name: "FK_SecondarySources_Types_TypeId", + table: "SecondarySources"); + + migrationBuilder.DropForeignKey( + name: "FK_UnordinaryPersons_Religions_FormerReligionId", + table: "UnordinaryPersons"); + + migrationBuilder.DropForeignKey( + name: "FK_WrittenSources_Genres_GenreId", + table: "WrittenSources"); + + migrationBuilder.DropForeignKey( + name: "FK_WrittenSources_Languages_LanguageId", + table: "WrittenSources"); + + migrationBuilder.DropTable( + name: "Relations"); + + migrationBuilder.DropIndex( + name: "IX_UnordinaryPersons_FormerReligionId", + table: "UnordinaryPersons"); + + migrationBuilder.DropIndex( + name: "IX_OrdinaryPersons_FormerReligionId", + table: "OrdinaryPersons"); + + migrationBuilder.DropIndex( + name: "IX_OrdinaryPersons_RelationId", + table: "OrdinaryPersons"); + + migrationBuilder.DropColumn( + name: "Patronage", + table: "WrittenSources"); + + migrationBuilder.DropColumn( + name: "Depiction", + table: "UnordinaryPersons"); + + migrationBuilder.DropColumn( + name: "Depiction", + table: "OrdinaryPersons"); + + migrationBuilder.DropColumn( + name: "YearWritten", + table: "WrittenSources"); + + migrationBuilder.DropColumn( + name: "BirthYear", + table: "UnordinaryPersons"); + + migrationBuilder.DropColumn( + name: "BirthYear", + table: "OrdinaryPersons"); + + migrationBuilder.DropColumn( + name: "DeathYear", + table: "UnordinaryPersons"); + + migrationBuilder.DropColumn( + name: "DeathYear", + table: "OrdinaryPersons"); + + migrationBuilder.RenameColumn( + name: "FormerReligionId", + table: "UnordinaryPersons", + newName: "ProbableDeathYear"); + + migrationBuilder.RenameColumn( + name: "RelationId", + table: "OrdinaryPersons", + newName: "ProbableDeathYear"); + + migrationBuilder.RenameColumn( + name: "FormerReligionId", + table: "OrdinaryPersons", + newName: "ProbableBirthYear"); + + // migrationBuilder.AlterColumn>( + // name: "YearWritten", + // table: "WrittenSources", + // type: "integer[]", + // nullable: true, + // oldClrType: typeof(DateOnly), + // oldType: "date", + // oldNullable: true); + + migrationBuilder.AlterColumn>( + name: "SurvivedCopies", + table: "WrittenSources", + type: "text[]", + nullable: true, + oldClrType: typeof(string[]), + oldType: "text[]"); + + migrationBuilder.AlterColumn( + name: "LanguageId", + table: "WrittenSources", + type: "integer", + nullable: true, + oldClrType: typeof(int), + oldType: "integer"); + + migrationBuilder.AlterColumn>( + name: "KnownCopies", + table: "WrittenSources", + type: "text[]", + nullable: true, + oldClrType: typeof(string[]), + oldType: "text[]"); + + migrationBuilder.AlterColumn( + name: "GenreId", + table: "WrittenSources", + type: "integer", + nullable: true, + oldClrType: typeof(int), + oldType: "integer"); + + migrationBuilder.AddColumn>( + name: "YearWritten", + table: "WrittenSources", + type: "integer[]", + nullable: true); + + migrationBuilder.AddColumn( + name: "OrdinaryPersonId", + table: "WrittenSources", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "UnordinaryPersonId", + table: "WrittenSources", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn>( + name: "BirthYear", + table: "UnordinaryPersons", + type: "integer[]", + nullable: true); + + // migrationBuilder.AlterColumn>( + // name: "DeathYear", + // table: "UnordinaryPersons", + // type: "integer[]", + // nullable: true, + // oldClrType: typeof(DateOnly), + // oldType: "date", + // oldNullable: true); + + // migrationBuilder.AlterColumn>( + // name: "BirthYear", + // table: "UnordinaryPersons", + // type: "integer[]", + // nullable: true, + // oldClrType: typeof(DateOnly), + // oldType: "date", + // oldNullable: true); + + migrationBuilder.AddColumn( + name: "BirthPlaceId", + table: "UnordinaryPersons", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "DeathPlaceId", + table: "UnordinaryPersons", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "ProbableBirthYear", + table: "UnordinaryPersons", + type: "integer", + nullable: true); + + migrationBuilder.AlterColumn( + name: "TypeId", + table: "SecondarySources", + type: "integer", + nullable: true, + oldClrType: typeof(int), + oldType: "integer"); + + migrationBuilder.AlterColumn( + name: "LanguageId", + table: "SecondarySources", + type: "integer", + nullable: true, + oldClrType: typeof(int), + oldType: "integer"); + + migrationBuilder.AddColumn( + name: "OrdinaryPersonId", + table: "Religions", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "UnordinaryPersonId", + table: "Religions", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn>( + name: "DeathYear", + table: "UnordinaryPersons", + type: "integer[]", + nullable: true); + + migrationBuilder.AddColumn>( + name: "DeathYear", + table: "OrdinaryPersons", + type: "integer[]", + nullable: true); + + // migrationBuilder.AlterColumn>( + // name: "DeathYear", + // table: "OrdinaryPersons", + // type: "integer[]", + // nullable: true, + // oldClrType: typeof(DateOnly), + // oldType: "date", + // oldNullable: true); + + // migrationBuilder.AlterColumn>( + // name: "BirthYear", + // table: "OrdinaryPersons", + // type: "integer[]", + // nullable: true, + // oldClrType: typeof(DateOnly), + // oldType: "date", + // oldNullable: true); + + migrationBuilder.AddColumn>( + name: "BirthYear", + table: "OrdinaryPersons", + type: "integer[]", + nullable: true); + + migrationBuilder.AddColumn( + name: "BackgroundCityId", + table: "OrdinaryPersons", + type: "integer", + nullable: true); + + migrationBuilder.AddColumn( + name: "LocationId", + table: "OrdinaryPersons", + type: "integer", + nullable: true); + + migrationBuilder.CreateTable( + name: "Cities", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + AsciiName = table.Column(type: "text", nullable: false), + GeoNamesId = table.Column(type: "text", nullable: true), + AlternateNames = table.Column>(type: "text[]", nullable: true), + CountryCode = table.Column(type: "text", nullable: true), + WrittenSourceId = table.Column(type: "integer", nullable: true), + WrittenSourceId1 = table.Column(type: "integer", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Cities", x => x.Id); + table.ForeignKey( + name: "FK_Cities_WrittenSources_WrittenSourceId", + column: x => x.WrittenSourceId, + principalTable: "WrittenSources", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_Cities_WrittenSources_WrittenSourceId1", + column: x => x.WrittenSourceId1, + principalTable: "WrittenSources", + principalColumn: "Id"); + }); + + migrationBuilder.CreateIndex( + name: "IX_WrittenSources_OrdinaryPersonId", + table: "WrittenSources", + column: "OrdinaryPersonId"); + + migrationBuilder.CreateIndex( + name: "IX_WrittenSources_UnordinaryPersonId", + table: "WrittenSources", + column: "UnordinaryPersonId"); + + migrationBuilder.CreateIndex( + name: "IX_UnordinaryPersons_BirthPlaceId", + table: "UnordinaryPersons", + column: "BirthPlaceId"); + + migrationBuilder.CreateIndex( + name: "IX_UnordinaryPersons_DeathPlaceId", + table: "UnordinaryPersons", + column: "DeathPlaceId"); + + migrationBuilder.CreateIndex( + name: "IX_Religions_OrdinaryPersonId", + table: "Religions", + column: "OrdinaryPersonId"); + + migrationBuilder.CreateIndex( + name: "IX_Religions_UnordinaryPersonId", + table: "Religions", + column: "UnordinaryPersonId"); + + migrationBuilder.CreateIndex( + name: "IX_OrdinaryPersons_BackgroundCityId", + table: "OrdinaryPersons", + column: "BackgroundCityId"); + + migrationBuilder.CreateIndex( + name: "IX_OrdinaryPersons_LocationId", + table: "OrdinaryPersons", + column: "LocationId"); + + migrationBuilder.CreateIndex( + name: "IX_Cities_WrittenSourceId", + table: "Cities", + column: "WrittenSourceId"); + + migrationBuilder.CreateIndex( + name: "IX_Cities_WrittenSourceId1", + table: "Cities", + column: "WrittenSourceId1"); + + migrationBuilder.AddForeignKey( + name: "FK_OrdinaryPersons_Cities_BackgroundCityId", + table: "OrdinaryPersons", + column: "BackgroundCityId", + principalTable: "Cities", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_OrdinaryPersons_Cities_LocationId", + table: "OrdinaryPersons", + column: "LocationId", + principalTable: "Cities", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Religions_OrdinaryPersons_OrdinaryPersonId", + table: "Religions", + column: "OrdinaryPersonId", + principalTable: "OrdinaryPersons", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_Religions_UnordinaryPersons_UnordinaryPersonId", + table: "Religions", + column: "UnordinaryPersonId", + principalTable: "UnordinaryPersons", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_SecondarySources_Languages_LanguageId", + table: "SecondarySources", + column: "LanguageId", + principalTable: "Languages", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_SecondarySources_Types_TypeId", + table: "SecondarySources", + column: "TypeId", + principalTable: "Types", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_UnordinaryPersons_Cities_BirthPlaceId", + table: "UnordinaryPersons", + column: "BirthPlaceId", + principalTable: "Cities", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_UnordinaryPersons_Cities_DeathPlaceId", + table: "UnordinaryPersons", + column: "DeathPlaceId", + principalTable: "Cities", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_WrittenSources_Genres_GenreId", + table: "WrittenSources", + column: "GenreId", + principalTable: "Genres", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_WrittenSources_Languages_LanguageId", + table: "WrittenSources", + column: "LanguageId", + principalTable: "Languages", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_WrittenSources_OrdinaryPersons_OrdinaryPersonId", + table: "WrittenSources", + column: "OrdinaryPersonId", + principalTable: "OrdinaryPersons", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_WrittenSources_UnordinaryPersons_UnordinaryPersonId", + table: "WrittenSources", + column: "UnordinaryPersonId", + principalTable: "UnordinaryPersons", + principalColumn: "Id"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropForeignKey( + name: "FK_OrdinaryPersons_Cities_BackgroundCityId", + table: "OrdinaryPersons"); + + migrationBuilder.DropForeignKey( + name: "FK_OrdinaryPersons_Cities_LocationId", + table: "OrdinaryPersons"); + + migrationBuilder.DropForeignKey( + name: "FK_Religions_OrdinaryPersons_OrdinaryPersonId", + table: "Religions"); + + migrationBuilder.DropForeignKey( + name: "FK_Religions_UnordinaryPersons_UnordinaryPersonId", + table: "Religions"); + + migrationBuilder.DropForeignKey( + name: "FK_SecondarySources_Languages_LanguageId", + table: "SecondarySources"); + + migrationBuilder.DropForeignKey( + name: "FK_SecondarySources_Types_TypeId", + table: "SecondarySources"); + + migrationBuilder.DropForeignKey( + name: "FK_UnordinaryPersons_Cities_BirthPlaceId", + table: "UnordinaryPersons"); + + migrationBuilder.DropForeignKey( + name: "FK_UnordinaryPersons_Cities_DeathPlaceId", + table: "UnordinaryPersons"); + + migrationBuilder.DropForeignKey( + name: "FK_WrittenSources_Genres_GenreId", + table: "WrittenSources"); + + migrationBuilder.DropForeignKey( + name: "FK_WrittenSources_Languages_LanguageId", + table: "WrittenSources"); + + migrationBuilder.DropForeignKey( + name: "FK_WrittenSources_OrdinaryPersons_OrdinaryPersonId", + table: "WrittenSources"); + + migrationBuilder.DropForeignKey( + name: "FK_WrittenSources_UnordinaryPersons_UnordinaryPersonId", + table: "WrittenSources"); + + migrationBuilder.DropTable( + name: "Cities"); + + migrationBuilder.DropIndex( + name: "IX_WrittenSources_OrdinaryPersonId", + table: "WrittenSources"); + + migrationBuilder.DropIndex( + name: "IX_WrittenSources_UnordinaryPersonId", + table: "WrittenSources"); + + migrationBuilder.DropIndex( + name: "IX_UnordinaryPersons_BirthPlaceId", + table: "UnordinaryPersons"); + + migrationBuilder.DropIndex( + name: "IX_UnordinaryPersons_DeathPlaceId", + table: "UnordinaryPersons"); + + migrationBuilder.DropIndex( + name: "IX_Religions_OrdinaryPersonId", + table: "Religions"); + + migrationBuilder.DropIndex( + name: "IX_Religions_UnordinaryPersonId", + table: "Religions"); + + migrationBuilder.DropIndex( + name: "IX_OrdinaryPersons_BackgroundCityId", + table: "OrdinaryPersons"); + + migrationBuilder.DropIndex( + name: "IX_OrdinaryPersons_LocationId", + table: "OrdinaryPersons"); + + migrationBuilder.DropColumn( + name: "OrdinaryPersonId", + table: "WrittenSources"); + + migrationBuilder.DropColumn( + name: "UnordinaryPersonId", + table: "WrittenSources"); + + migrationBuilder.DropColumn( + name: "BirthPlaceId", + table: "UnordinaryPersons"); + + migrationBuilder.DropColumn( + name: "DeathPlaceId", + table: "UnordinaryPersons"); + + migrationBuilder.DropColumn( + name: "ProbableBirthYear", + table: "UnordinaryPersons"); + + migrationBuilder.DropColumn( + name: "OrdinaryPersonId", + table: "Religions"); + + migrationBuilder.DropColumn( + name: "UnordinaryPersonId", + table: "Religions"); + + migrationBuilder.DropColumn( + name: "BackgroundCityId", + table: "OrdinaryPersons"); + + migrationBuilder.DropColumn( + name: "LocationId", + table: "OrdinaryPersons"); + + migrationBuilder.DropColumn( + name: "YearWritten", + table: "WrittenSources"); + + migrationBuilder.DropColumn( + name: "BirthYear", + table: "UnordinaryPersons"); + + migrationBuilder.DropColumn( + name: "BirthYear", + table: "OrdinaryPersons"); + + migrationBuilder.DropColumn( + name: "DeathYear", + table: "UnordinaryPersons"); + + migrationBuilder.DropColumn( + name: "DeathYear", + table: "OrdinaryPersons"); + + migrationBuilder.RenameColumn( + name: "ProbableDeathYear", + table: "UnordinaryPersons", + newName: "FormerReligionId"); + + migrationBuilder.RenameColumn( + name: "ProbableDeathYear", + table: "OrdinaryPersons", + newName: "RelationId"); + + migrationBuilder.RenameColumn( + name: "ProbableBirthYear", + table: "OrdinaryPersons", + newName: "FormerReligionId"); + + // migrationBuilder.AlterColumn( + // name: "YearWritten", + // table: "WrittenSources", + // type: "date", + // nullable: true, + // oldClrType: typeof(List), + // oldType: "integer[]", + // oldNullable: true); + + migrationBuilder.AlterColumn( + name: "SurvivedCopies", + table: "WrittenSources", + type: "text[]", + nullable: false, + defaultValue: new string[0], + oldClrType: typeof(List), + oldType: "text[]", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "LanguageId", + table: "WrittenSources", + type: "integer", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "integer", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "KnownCopies", + table: "WrittenSources", + type: "text[]", + nullable: false, + defaultValue: new string[0], + oldClrType: typeof(List), + oldType: "text[]", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "GenreId", + table: "WrittenSources", + type: "integer", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "integer", + oldNullable: true); + + migrationBuilder.AddColumn>( + name: "YearWritten", + table: "WrittenSources", + type: "date", + nullable: true); + + migrationBuilder.AddColumn( + name: "Patronage", + table: "WrittenSources", + type: "boolean", + nullable: false, + defaultValue: false); + + // migrationBuilder.AlterColumn( + // name: "DeathYear", + // table: "UnordinaryPersons", + // type: "date", + // nullable: true, + // oldClrType: typeof(List), + // oldType: "integer[]", + // oldNullable: true); + + // migrationBuilder.AlterColumn( + // name: "BirthYear", + // table: "UnordinaryPersons", + // type: "date", + // nullable: true, + // oldClrType: typeof(List), + // oldType: "integer[]", + // oldNullable: true); + + migrationBuilder.AddColumn( + name: "DeathYear", + table: "UnordinaryPersons", + type: "date", + nullable: true); + + migrationBuilder.AddColumn( + name: "DeathYear", + table: "OrdinaryPersons", + type: "date", + nullable: true); + + migrationBuilder.AddColumn( + name: "BirthYear", + table: "UnordinaryPersons", + type: "date", + nullable: true); + + migrationBuilder.AddColumn( + name: "Depiction", + table: "UnordinaryPersons", + type: "text", + nullable: true); + + migrationBuilder.AlterColumn( + name: "TypeId", + table: "SecondarySources", + type: "integer", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "integer", + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "LanguageId", + table: "SecondarySources", + type: "integer", + nullable: false, + defaultValue: 0, + oldClrType: typeof(int), + oldType: "integer", + oldNullable: true); + + // migrationBuilder.AlterColumn( + // name: "DeathYear", + // table: "OrdinaryPersons", + // type: "date", + // nullable: true, + // oldClrType: typeof(List), + // oldType: "integer[]", + // oldNullable: true); + + // migrationBuilder.AlterColumn( + // name: "BirthYear", + // table: "OrdinaryPersons", + // type: "date", + // nullable: true, + // oldClrType: typeof(List), + // oldType: "integer[]", + // oldNullable: true); + + migrationBuilder.AddColumn( + name: "BirthYear", + table: "OrdinaryPersons", + type: "date", + nullable: true); + + migrationBuilder.AddColumn( + name: "Depiction", + table: "OrdinaryPersons", + type: "text", + nullable: true); + + migrationBuilder.CreateTable( + name: "Relations", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Name = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Relations", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_UnordinaryPersons_FormerReligionId", + table: "UnordinaryPersons", + column: "FormerReligionId"); + + migrationBuilder.CreateIndex( + name: "IX_OrdinaryPersons_FormerReligionId", + table: "OrdinaryPersons", + column: "FormerReligionId"); + + migrationBuilder.CreateIndex( + name: "IX_OrdinaryPersons_RelationId", + table: "OrdinaryPersons", + column: "RelationId"); + + migrationBuilder.AddForeignKey( + name: "FK_OrdinaryPersons_Relations_RelationId", + table: "OrdinaryPersons", + column: "RelationId", + principalTable: "Relations", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_OrdinaryPersons_Religions_FormerReligionId", + table: "OrdinaryPersons", + column: "FormerReligionId", + principalTable: "Religions", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_SecondarySources_Languages_LanguageId", + table: "SecondarySources", + column: "LanguageId", + principalTable: "Languages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_SecondarySources_Types_TypeId", + table: "SecondarySources", + column: "TypeId", + principalTable: "Types", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_UnordinaryPersons_Religions_FormerReligionId", + table: "UnordinaryPersons", + column: "FormerReligionId", + principalTable: "Religions", + principalColumn: "Id"); + + migrationBuilder.AddForeignKey( + name: "FK_WrittenSources_Genres_GenreId", + table: "WrittenSources", + column: "GenreId", + principalTable: "Genres", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + + migrationBuilder.AddForeignKey( + name: "FK_WrittenSources_Languages_LanguageId", + table: "WrittenSources", + column: "LanguageId", + principalTable: "Languages", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + } + } +} diff --git a/backend/Migrations/20250207154128_DateToInt.Designer.cs b/backend/Migrations/20250207154128_DateToInt.Designer.cs new file mode 100644 index 0000000..b42faf5 --- /dev/null +++ b/backend/Migrations/20250207154128_DateToInt.Designer.cs @@ -0,0 +1,980 @@ +// +using System; +using System.Collections.Generic; +using Mappa.Db; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace mappa.Migrations +{ + [DbContext(typeof(AppDbContext))] + [Migration("20250207154128_DateToInt")] + partial class DateToInt + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Mappa.Entities.City", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("AlternateNames") + .HasColumnType("text[]"); + + b.Property("AsciiName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CountryCode") + .HasColumnType("text"); + + b.Property("GeoNamesId") + .HasColumnType("text"); + + b.Property("WrittenSourceId") + .HasColumnType("integer"); + + b.Property("WrittenSourceId1") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WrittenSourceId"); + + b.HasIndex("WrittenSourceId1"); + + b.ToTable("Cities"); + }); + + modelBuilder.Entity("Mappa.Entities.Ethnicity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Ethnicities"); + }); + + modelBuilder.Entity("Mappa.Entities.Gender", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Genders"); + }); + + modelBuilder.Entity("Mappa.Entities.Genre", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Genres"); + }); + + modelBuilder.Entity("Mappa.Entities.IntraOrdinary", b => + { + b.Property("PersonIdA") + .HasColumnType("integer"); + + b.Property("PersonIdB") + .HasColumnType("integer"); + + b.HasKey("PersonIdA", "PersonIdB"); + + b.HasIndex("PersonIdB"); + + b.ToTable("IntraOrdinary"); + }); + + modelBuilder.Entity("Mappa.Entities.IntraUnordinary", b => + { + b.Property("PersonIdA") + .HasColumnType("integer"); + + b.Property("PersonIdB") + .HasColumnType("integer"); + + b.HasKey("PersonIdA", "PersonIdB"); + + b.HasIndex("PersonIdB"); + + b.ToTable("IntraUnordinary"); + }); + + modelBuilder.Entity("Mappa.Entities.Language", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("SecondarySourceId") + .HasColumnType("integer"); + + b.Property("WrittenSourceId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("SecondarySourceId"); + + b.HasIndex("WrittenSourceId"); + + b.ToTable("Languages"); + }); + + modelBuilder.Entity("Mappa.Entities.OrdinaryPerson", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AlternateName") + .HasColumnType("text"); + + b.Property("BackgroundCityId") + .HasColumnType("integer"); + + b.Property("Biography") + .HasColumnType("text"); + + b.Property>("BirthYear") + .HasColumnType("integer[]"); + + b.Property>("DeathYear") + .HasColumnType("integer[]"); + + b.Property("DepictionInTheSource") + .HasColumnType("text"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EthnicityId") + .HasColumnType("integer"); + + b.Property("ExplanationOfEthnicity") + .HasColumnType("text"); + + b.Property("GenderId") + .HasColumnType("integer"); + + b.Property("InteractionWithOrdinaryExplanation") + .HasColumnType("text"); + + b.Property("InteractionWithUnordinaryExplanation") + .HasColumnType("text"); + + b.Property("InterestingFeature") + .HasColumnType("text"); + + b.Property("LocationId") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProbableBirthYear") + .HasColumnType("integer"); + + b.Property("ProbableDeathYear") + .HasColumnType("integer"); + + b.Property("ProfessionExplanation") + .HasColumnType("text"); + + b.Property("ProfessionId") + .HasColumnType("integer"); + + b.Property("ReligionExplanation") + .HasColumnType("text"); + + b.Property("ReligionId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("BackgroundCityId"); + + b.HasIndex("EthnicityId"); + + b.HasIndex("GenderId"); + + b.HasIndex("LocationId"); + + b.HasIndex("ProfessionId"); + + b.HasIndex("ReligionId"); + + b.ToTable("OrdinaryPersons"); + }); + + modelBuilder.Entity("Mappa.Entities.Profession", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Professions"); + }); + + modelBuilder.Entity("Mappa.Entities.Religion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("OrdinaryPersonId") + .HasColumnType("integer"); + + b.Property("UnordinaryPersonId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("OrdinaryPersonId"); + + b.HasIndex("UnordinaryPersonId"); + + b.ToTable("Religions"); + }); + + modelBuilder.Entity("Mappa.Entities.SecondarySource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("AlternateNames") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("Author") + .HasColumnType("text"); + + b.Property("BibliographyInformation") + .HasColumnType("text"); + + b.Property("LanguageId") + .HasColumnType("integer"); + + b.Property("OtherInformation") + .HasColumnType("text"); + + b.Property("Topic") + .HasColumnType("text"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.Property("University") + .HasColumnType("text"); + + b.Property("YearWritten") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("LanguageId"); + + b.HasIndex("TypeId"); + + b.ToTable("SecondarySources"); + }); + + modelBuilder.Entity("Mappa.Entities.Type", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Types"); + }); + + modelBuilder.Entity("Mappa.Entities.UnordinaryPerson", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AlternateName") + .HasColumnType("text"); + + b.Property("BirthPlaceId") + .HasColumnType("integer"); + + b.Property>("BirthYear") + .HasColumnType("integer[]"); + + b.Property("DeathPlaceId") + .HasColumnType("integer"); + + b.Property>("DeathYear") + .HasColumnType("integer[]"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("EthnicityId") + .HasColumnType("integer"); + + b.Property("GenderId") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProbableBirthYear") + .HasColumnType("integer"); + + b.Property("ProbableDeathYear") + .HasColumnType("integer"); + + b.Property("ProfessionId") + .HasColumnType("integer"); + + b.Property("ReligionId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("BirthPlaceId"); + + b.HasIndex("DeathPlaceId"); + + b.HasIndex("EthnicityId"); + + b.HasIndex("GenderId"); + + b.HasIndex("ProfessionId"); + + b.HasIndex("ReligionId"); + + b.ToTable("UnordinaryPersons"); + }); + + modelBuilder.Entity("Mappa.Entities.User", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Mappa.Entities.WrittenSource", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("AlternateNames") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("Author") + .HasColumnType("text"); + + b.Property("GenreId") + .HasColumnType("integer"); + + b.Property("Image") + .HasColumnType("text"); + + b.Property>("KnownCopies") + .HasColumnType("text[]"); + + b.Property("LanguageId") + .HasColumnType("integer"); + + b.Property("LibraryInformation") + .HasColumnType("text"); + + b.Property("OrdinaryPersonId") + .HasColumnType("integer"); + + b.Property("OtherInformation") + .HasColumnType("text"); + + b.Property("RemarkableWorksOnTheBook") + .HasColumnType("text"); + + b.Property>("SurvivedCopies") + .HasColumnType("text[]"); + + b.Property("UnordinaryPersonId") + .HasColumnType("integer"); + + b.Property>("YearWritten") + .HasColumnType("integer[]"); + + b.HasKey("Id"); + + b.HasIndex("GenreId"); + + b.HasIndex("LanguageId"); + + b.HasIndex("OrdinaryPersonId"); + + b.HasIndex("UnordinaryPersonId"); + + b.ToTable("WrittenSources"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("OrdinaryPersonUnordinaryPerson", b => + { + b.Property("InteractionsWithOrdinaryId") + .HasColumnType("integer"); + + b.Property("InteractionsWithUnordinaryId") + .HasColumnType("integer"); + + b.HasKey("InteractionsWithOrdinaryId", "InteractionsWithUnordinaryId"); + + b.HasIndex("InteractionsWithUnordinaryId"); + + b.ToTable("OrdinaryPersonUnordinaryPerson"); + }); + + modelBuilder.Entity("Mappa.Entities.City", b => + { + b.HasOne("Mappa.Entities.WrittenSource", null) + .WithMany("CitiesMentioningTheSources") + .HasForeignKey("WrittenSourceId"); + + b.HasOne("Mappa.Entities.WrittenSource", null) + .WithMany("CitiesWhereSourcesAreWritten") + .HasForeignKey("WrittenSourceId1"); + }); + + modelBuilder.Entity("Mappa.Entities.IntraOrdinary", b => + { + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany() + .HasForeignKey("PersonIdA") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany() + .HasForeignKey("PersonIdB") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Mappa.Entities.IntraUnordinary", b => + { + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany() + .HasForeignKey("PersonIdA") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany() + .HasForeignKey("PersonIdB") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Mappa.Entities.Language", b => + { + b.HasOne("Mappa.Entities.SecondarySource", null) + .WithMany("TranslatedLanguages") + .HasForeignKey("SecondarySourceId"); + + b.HasOne("Mappa.Entities.WrittenSource", null) + .WithMany("TranslatedLanguages") + .HasForeignKey("WrittenSourceId"); + }); + + modelBuilder.Entity("Mappa.Entities.OrdinaryPerson", b => + { + b.HasOne("Mappa.Entities.City", "BackgroundCity") + .WithMany() + .HasForeignKey("BackgroundCityId"); + + b.HasOne("Mappa.Entities.Ethnicity", "Ethnicity") + .WithMany() + .HasForeignKey("EthnicityId"); + + b.HasOne("Mappa.Entities.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId"); + + b.HasOne("Mappa.Entities.City", "Location") + .WithMany() + .HasForeignKey("LocationId"); + + b.HasOne("Mappa.Entities.Profession", "Profession") + .WithMany() + .HasForeignKey("ProfessionId"); + + b.HasOne("Mappa.Entities.Religion", "Religion") + .WithMany() + .HasForeignKey("ReligionId"); + + b.Navigation("BackgroundCity"); + + b.Navigation("Ethnicity"); + + b.Navigation("Gender"); + + b.Navigation("Location"); + + b.Navigation("Profession"); + + b.Navigation("Religion"); + }); + + modelBuilder.Entity("Mappa.Entities.Religion", b => + { + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany("FormerReligion") + .HasForeignKey("OrdinaryPersonId"); + + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany("FormerReligion") + .HasForeignKey("UnordinaryPersonId"); + }); + + modelBuilder.Entity("Mappa.Entities.SecondarySource", b => + { + b.HasOne("Mappa.Entities.Language", "Language") + .WithMany() + .HasForeignKey("LanguageId"); + + b.HasOne("Mappa.Entities.Type", "Type") + .WithMany() + .HasForeignKey("TypeId"); + + b.Navigation("Language"); + + b.Navigation("Type"); + }); + + modelBuilder.Entity("Mappa.Entities.UnordinaryPerson", b => + { + b.HasOne("Mappa.Entities.City", "BirthPlace") + .WithMany() + .HasForeignKey("BirthPlaceId"); + + b.HasOne("Mappa.Entities.City", "DeathPlace") + .WithMany() + .HasForeignKey("DeathPlaceId"); + + b.HasOne("Mappa.Entities.Ethnicity", "Ethnicity") + .WithMany() + .HasForeignKey("EthnicityId"); + + b.HasOne("Mappa.Entities.Gender", "Gender") + .WithMany() + .HasForeignKey("GenderId"); + + b.HasOne("Mappa.Entities.Profession", "Profession") + .WithMany() + .HasForeignKey("ProfessionId"); + + b.HasOne("Mappa.Entities.Religion", "Religion") + .WithMany() + .HasForeignKey("ReligionId"); + + b.Navigation("BirthPlace"); + + b.Navigation("DeathPlace"); + + b.Navigation("Ethnicity"); + + b.Navigation("Gender"); + + b.Navigation("Profession"); + + b.Navigation("Religion"); + }); + + modelBuilder.Entity("Mappa.Entities.WrittenSource", b => + { + b.HasOne("Mappa.Entities.Genre", "Genre") + .WithMany() + .HasForeignKey("GenreId"); + + b.HasOne("Mappa.Entities.Language", "Language") + .WithMany() + .HasForeignKey("LanguageId"); + + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany("Sources") + .HasForeignKey("OrdinaryPersonId"); + + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany("Sources") + .HasForeignKey("UnordinaryPersonId"); + + b.Navigation("Genre"); + + b.Navigation("Language"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Mappa.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Mappa.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mappa.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Mappa.Entities.User", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("OrdinaryPersonUnordinaryPerson", b => + { + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany() + .HasForeignKey("InteractionsWithOrdinaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany() + .HasForeignKey("InteractionsWithUnordinaryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Mappa.Entities.OrdinaryPerson", b => + { + b.Navigation("FormerReligion"); + + b.Navigation("Sources"); + }); + + modelBuilder.Entity("Mappa.Entities.SecondarySource", b => + { + b.Navigation("TranslatedLanguages"); + }); + + modelBuilder.Entity("Mappa.Entities.UnordinaryPerson", b => + { + b.Navigation("FormerReligion"); + + b.Navigation("Sources"); + }); + + modelBuilder.Entity("Mappa.Entities.WrittenSource", b => + { + b.Navigation("CitiesMentioningTheSources"); + + b.Navigation("CitiesWhereSourcesAreWritten"); + + b.Navigation("TranslatedLanguages"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/Migrations/20250207154128_DateToInt.cs b/backend/Migrations/20250207154128_DateToInt.cs new file mode 100644 index 0000000..b9e431a --- /dev/null +++ b/backend/Migrations/20250207154128_DateToInt.cs @@ -0,0 +1,39 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace mappa.Migrations +{ + /// + public partial class DateToInt : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "YearWritten", + table: "SecondarySources"); + + migrationBuilder.AddColumn( + name: "YearWritten", + table: "SecondarySources", + type: "integer", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "YearWritten", + table: "SecondarySources"); + + migrationBuilder.AddColumn( + name: "YearWritten", + table: "SecondarySources", + type: "date", + nullable: true); + } + } +} diff --git a/backend/Migrations/AppDbContextModelSnapshot.cs b/backend/Migrations/AppDbContextModelSnapshot.cs index e98e5ef..8f96f2f 100644 --- a/backend/Migrations/AppDbContextModelSnapshot.cs +++ b/backend/Migrations/AppDbContextModelSnapshot.cs @@ -1,5 +1,6 @@ // using System; +using System.Collections.Generic; using Mappa.Db; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -22,6 +23,42 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + modelBuilder.Entity("Mappa.Entities.City", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("AlternateNames") + .HasColumnType("text[]"); + + b.Property("AsciiName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CountryCode") + .HasColumnType("text"); + + b.Property("GeoNamesId") + .HasColumnType("text"); + + b.Property("WrittenSourceId") + .HasColumnType("integer"); + + b.Property("WrittenSourceId1") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WrittenSourceId"); + + b.HasIndex("WrittenSourceId1"); + + b.ToTable("Cities"); + }); + modelBuilder.Entity("Mappa.Entities.Ethnicity", b => { b.Property("Id") @@ -141,17 +178,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("AlternateName") .HasColumnType("text"); + b.Property("BackgroundCityId") + .HasColumnType("integer"); + b.Property("Biography") .HasColumnType("text"); - b.Property("BirthYear") - .HasColumnType("date"); + b.Property>("BirthYear") + .HasColumnType("integer[]"); - b.Property("DeathYear") - .HasColumnType("date"); - - b.Property("Depiction") - .HasColumnType("text"); + b.Property>("DeathYear") + .HasColumnType("integer[]"); b.Property("DepictionInTheSource") .HasColumnType("text"); @@ -165,9 +202,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("ExplanationOfEthnicity") .HasColumnType("text"); - b.Property("FormerReligionId") - .HasColumnType("integer"); - b.Property("GenderId") .HasColumnType("integer"); @@ -180,19 +214,25 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("InterestingFeature") .HasColumnType("text"); + b.Property("LocationId") + .HasColumnType("integer"); + b.Property("Name") .IsRequired() .HasColumnType("text"); + b.Property("ProbableBirthYear") + .HasColumnType("integer"); + + b.Property("ProbableDeathYear") + .HasColumnType("integer"); + b.Property("ProfessionExplanation") .HasColumnType("text"); b.Property("ProfessionId") .HasColumnType("integer"); - b.Property("RelationId") - .HasColumnType("integer"); - b.Property("ReligionExplanation") .HasColumnType("text"); @@ -201,15 +241,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("EthnicityId"); + b.HasIndex("BackgroundCityId"); - b.HasIndex("FormerReligionId"); + b.HasIndex("EthnicityId"); b.HasIndex("GenderId"); - b.HasIndex("ProfessionId"); + b.HasIndex("LocationId"); - b.HasIndex("RelationId"); + b.HasIndex("ProfessionId"); b.HasIndex("ReligionId"); @@ -233,7 +273,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Professions"); }); - modelBuilder.Entity("Mappa.Entities.Relation", b => + modelBuilder.Entity("Mappa.Entities.Religion", b => { b.Property("Id") .ValueGeneratedOnAdd() @@ -245,24 +285,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("text"); - b.HasKey("Id"); - - b.ToTable("Relations"); - }); + b.Property("OrdinaryPersonId") + .HasColumnType("integer"); - modelBuilder.Entity("Mappa.Entities.Religion", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() + b.Property("UnordinaryPersonId") .HasColumnType("integer"); - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + b.HasKey("Id"); - b.Property("Name") - .IsRequired() - .HasColumnType("text"); + b.HasIndex("OrdinaryPersonId"); - b.HasKey("Id"); + b.HasIndex("UnordinaryPersonId"); b.ToTable("Religions"); }); @@ -275,7 +308,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("AlternateNames") + b.Property>("AlternateNames") .IsRequired() .HasColumnType("text[]"); @@ -285,7 +318,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("BibliographyInformation") .HasColumnType("text"); - b.Property("LanguageId") + b.Property("LanguageId") .HasColumnType("integer"); b.Property("OtherInformation") @@ -294,14 +327,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Topic") .HasColumnType("text"); - b.Property("TypeId") + b.Property("TypeId") .HasColumnType("integer"); b.Property("University") .HasColumnType("text"); - b.Property("YearWritten") - .HasColumnType("date"); + b.Property("YearWritten") + .HasColumnType("integer"); b.HasKey("Id"); @@ -340,14 +373,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("AlternateName") .HasColumnType("text"); - b.Property("BirthYear") - .HasColumnType("date"); + b.Property("BirthPlaceId") + .HasColumnType("integer"); - b.Property("DeathYear") - .HasColumnType("date"); + b.Property>("BirthYear") + .HasColumnType("integer[]"); - b.Property("Depiction") - .HasColumnType("text"); + b.Property("DeathPlaceId") + .HasColumnType("integer"); + + b.Property>("DeathYear") + .HasColumnType("integer[]"); b.Property("Description") .HasColumnType("text"); @@ -355,9 +391,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("EthnicityId") .HasColumnType("integer"); - b.Property("FormerReligionId") - .HasColumnType("integer"); - b.Property("GenderId") .HasColumnType("integer"); @@ -365,6 +398,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired() .HasColumnType("text"); + b.Property("ProbableBirthYear") + .HasColumnType("integer"); + + b.Property("ProbableDeathYear") + .HasColumnType("integer"); + b.Property("ProfessionId") .HasColumnType("integer"); @@ -373,9 +412,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); - b.HasIndex("EthnicityId"); + b.HasIndex("BirthPlaceId"); + + b.HasIndex("DeathPlaceId"); - b.HasIndex("FormerReligionId"); + b.HasIndex("EthnicityId"); b.HasIndex("GenderId"); @@ -458,44 +499,45 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("AlternateNames") + b.Property>("AlternateNames") .IsRequired() .HasColumnType("text[]"); b.Property("Author") .HasColumnType("text"); - b.Property("GenreId") + b.Property("GenreId") .HasColumnType("integer"); b.Property("Image") .HasColumnType("text"); - b.Property("KnownCopies") - .IsRequired() + b.Property>("KnownCopies") .HasColumnType("text[]"); - b.Property("LanguageId") + b.Property("LanguageId") .HasColumnType("integer"); b.Property("LibraryInformation") .HasColumnType("text"); + b.Property("OrdinaryPersonId") + .HasColumnType("integer"); + b.Property("OtherInformation") .HasColumnType("text"); - b.Property("Patronage") - .HasColumnType("boolean"); - b.Property("RemarkableWorksOnTheBook") .HasColumnType("text"); - b.Property("SurvivedCopies") - .IsRequired() + b.Property>("SurvivedCopies") .HasColumnType("text[]"); - b.Property("YearWritten") - .HasColumnType("date"); + b.Property("UnordinaryPersonId") + .HasColumnType("integer"); + + b.Property>("YearWritten") + .HasColumnType("integer[]"); b.HasKey("Id"); @@ -503,6 +545,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("LanguageId"); + b.HasIndex("OrdinaryPersonId"); + + b.HasIndex("UnordinaryPersonId"); + b.ToTable("WrittenSources"); }); @@ -653,6 +699,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("OrdinaryPersonUnordinaryPerson"); }); + modelBuilder.Entity("Mappa.Entities.City", b => + { + b.HasOne("Mappa.Entities.WrittenSource", null) + .WithMany("CitiesMentioningTheSources") + .HasForeignKey("WrittenSourceId"); + + b.HasOne("Mappa.Entities.WrittenSource", null) + .WithMany("CitiesWhereSourcesAreWritten") + .HasForeignKey("WrittenSourceId1"); + }); + modelBuilder.Entity("Mappa.Entities.IntraOrdinary", b => { b.HasOne("Mappa.Entities.OrdinaryPerson", null) @@ -696,56 +753,63 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Mappa.Entities.OrdinaryPerson", b => { - b.HasOne("Mappa.Entities.Ethnicity", "Ethnicity") + b.HasOne("Mappa.Entities.City", "BackgroundCity") .WithMany() - .HasForeignKey("EthnicityId"); + .HasForeignKey("BackgroundCityId"); - b.HasOne("Mappa.Entities.Religion", "FormerReligion") + b.HasOne("Mappa.Entities.Ethnicity", "Ethnicity") .WithMany() - .HasForeignKey("FormerReligionId"); + .HasForeignKey("EthnicityId"); b.HasOne("Mappa.Entities.Gender", "Gender") .WithMany() .HasForeignKey("GenderId"); - b.HasOne("Mappa.Entities.Profession", "Profession") + b.HasOne("Mappa.Entities.City", "Location") .WithMany() - .HasForeignKey("ProfessionId"); + .HasForeignKey("LocationId"); - b.HasOne("Mappa.Entities.Relation", "Relation") + b.HasOne("Mappa.Entities.Profession", "Profession") .WithMany() - .HasForeignKey("RelationId"); + .HasForeignKey("ProfessionId"); b.HasOne("Mappa.Entities.Religion", "Religion") .WithMany() .HasForeignKey("ReligionId"); - b.Navigation("Ethnicity"); + b.Navigation("BackgroundCity"); - b.Navigation("FormerReligion"); + b.Navigation("Ethnicity"); b.Navigation("Gender"); - b.Navigation("Profession"); + b.Navigation("Location"); - b.Navigation("Relation"); + b.Navigation("Profession"); b.Navigation("Religion"); }); + modelBuilder.Entity("Mappa.Entities.Religion", b => + { + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany("FormerReligion") + .HasForeignKey("OrdinaryPersonId"); + + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany("FormerReligion") + .HasForeignKey("UnordinaryPersonId"); + }); + modelBuilder.Entity("Mappa.Entities.SecondarySource", b => { b.HasOne("Mappa.Entities.Language", "Language") .WithMany() - .HasForeignKey("LanguageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .HasForeignKey("LanguageId"); b.HasOne("Mappa.Entities.Type", "Type") .WithMany() - .HasForeignKey("TypeId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .HasForeignKey("TypeId"); b.Navigation("Language"); @@ -754,13 +818,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("Mappa.Entities.UnordinaryPerson", b => { - b.HasOne("Mappa.Entities.Ethnicity", "Ethnicity") + b.HasOne("Mappa.Entities.City", "BirthPlace") .WithMany() - .HasForeignKey("EthnicityId"); + .HasForeignKey("BirthPlaceId"); - b.HasOne("Mappa.Entities.Religion", "FormerReligion") + b.HasOne("Mappa.Entities.City", "DeathPlace") .WithMany() - .HasForeignKey("FormerReligionId"); + .HasForeignKey("DeathPlaceId"); + + b.HasOne("Mappa.Entities.Ethnicity", "Ethnicity") + .WithMany() + .HasForeignKey("EthnicityId"); b.HasOne("Mappa.Entities.Gender", "Gender") .WithMany() @@ -774,9 +842,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) .WithMany() .HasForeignKey("ReligionId"); - b.Navigation("Ethnicity"); + b.Navigation("BirthPlace"); - b.Navigation("FormerReligion"); + b.Navigation("DeathPlace"); + + b.Navigation("Ethnicity"); b.Navigation("Gender"); @@ -789,15 +859,19 @@ protected override void BuildModel(ModelBuilder modelBuilder) { b.HasOne("Mappa.Entities.Genre", "Genre") .WithMany() - .HasForeignKey("GenreId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .HasForeignKey("GenreId"); b.HasOne("Mappa.Entities.Language", "Language") .WithMany() - .HasForeignKey("LanguageId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); + .HasForeignKey("LanguageId"); + + b.HasOne("Mappa.Entities.OrdinaryPerson", null) + .WithMany("Sources") + .HasForeignKey("OrdinaryPersonId"); + + b.HasOne("Mappa.Entities.UnordinaryPerson", null) + .WithMany("Sources") + .HasForeignKey("UnordinaryPersonId"); b.Navigation("Genre"); @@ -870,13 +944,31 @@ protected override void BuildModel(ModelBuilder modelBuilder) .IsRequired(); }); + modelBuilder.Entity("Mappa.Entities.OrdinaryPerson", b => + { + b.Navigation("FormerReligion"); + + b.Navigation("Sources"); + }); + modelBuilder.Entity("Mappa.Entities.SecondarySource", b => { b.Navigation("TranslatedLanguages"); }); + modelBuilder.Entity("Mappa.Entities.UnordinaryPerson", b => + { + b.Navigation("FormerReligion"); + + b.Navigation("Sources"); + }); + modelBuilder.Entity("Mappa.Entities.WrittenSource", b => { + b.Navigation("CitiesMentioningTheSources"); + + b.Navigation("CitiesWhereSourcesAreWritten"); + b.Navigation("TranslatedLanguages"); }); #pragma warning restore 612, 618 diff --git a/backend/Program.cs b/backend/Program.cs index 4b57865..8785782 100644 --- a/backend/Program.cs +++ b/backend/Program.cs @@ -1,6 +1,7 @@ using System.Text; using Mappa.Db; using Mappa.Entities; +using Mappa.Helpers; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; @@ -8,6 +9,7 @@ using Microsoft.OpenApi.Models; using Mappa.Services; using Mappa.Dtos; +using Microsoft.IdentityModel.Logging; var builder = WebApplication.CreateBuilder(args); var configuration = builder.Configuration; @@ -57,7 +59,7 @@ { ValidateIssuer = true, ValidateAudience = true, - // ValidAudience = audience, + ValidAudience = audience, ValidIssuer = issuer, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)), ValidateLifetime = true, @@ -74,6 +76,11 @@ builder.Services.AddScoped, ProfessionService>(); builder.Services.AddScoped, ReligionService>(); builder.Services.AddScoped, TypeService>(); +builder.Services.AddScoped, CityService>(); +builder.Services.AddScoped, WrittenSourceService>(); +builder.Services.AddScoped, SecondarySourceService>(); +builder.Services.AddScoped, OrdinaryPersonService>(); +builder.Services.AddScoped, UnordinaryPersonService>(); builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle @@ -122,12 +129,15 @@ }); }); +builder.Services.AddAutoMapper(typeof(MappingProfile)); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { + IdentityModelEventSource.ShowPII = true; + IdentityModelEventSource.LogCompleteSecurityArtifact = true; app.UseSwagger(); app.UseSwaggerUI(c => { @@ -140,6 +150,10 @@ { var dbContext = scope.ServiceProvider.GetRequiredService(); dbContext.Database.EnsureCreated(); + // if (dbContext.Database.GetPendingMigrations().Any()) + // { + // dbContext.Database.Migrate(); + // } } app.UseHttpsRedirection(); diff --git a/backend/Services/AuthenticationService.cs b/backend/Services/AuthenticationService.cs index f3288c0..0ffed7e 100644 --- a/backend/Services/AuthenticationService.cs +++ b/backend/Services/AuthenticationService.cs @@ -77,7 +77,7 @@ private JwtSecurityToken GetToken(IEnumerable authClaims) var token = new JwtSecurityToken( issuer: _configuration["JWT:ValidIssuer"], - // audience: _configuration["JWT:ValidAudience"], + audience: _configuration["JWT:ValidAudience"], expires: DateTime.UtcNow.AddHours(Convert.ToDouble(_configuration["JWT:TokenExpirationInHours"])), claims: authClaims, signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)); diff --git a/backend/Services/CityService.cs b/backend/Services/CityService.cs new file mode 100644 index 0000000..f5d8d12 --- /dev/null +++ b/backend/Services/CityService.cs @@ -0,0 +1,126 @@ +using Mappa.Db; +using Mappa.Dtos; +using Mappa.Entities; +using Microsoft.EntityFrameworkCore; +using AutoMapper; +using Microsoft.IdentityModel.Tokens; +using System.ComponentModel.DataAnnotations; + +namespace Mappa.Services; + +public class CityService : IComplexEntityService +{ + private readonly AppDbContext _dbContext; + private readonly IMapper _mapper; + + public CityService(AppDbContext dbContext, IMapper mapper) + { + _dbContext = dbContext; + _mapper = mapper; + } + + public async Task> GetAllAsync() + { + return await _dbContext.Set() + .Select(e => new CityGeneralDto + { + Id = e.Id, + AsciiName = e.AsciiName, + }) + .ToListAsync(); + } + + public async Task GetByIdAsync(int id) + { + var entity = await _dbContext.Set() + .FirstOrDefaultAsync(ws => ws.Id == id); + + if (entity == null) + throw new ArgumentException($"Entity with ID {id} not found."); + + return new CityDetailDto + { + Id = entity.Id, + AsciiName = entity.AsciiName, + GeoNamesId = entity.GeoNamesId, + AlternateNames = entity.AlternateNames, + CountryCode = entity.CountryCode, + }; + } + + public async Task CreateAsync(CityCreateRequest request) + { + bool exists = await _dbContext.Set().AnyAsync(c => + EF.Property(c, "AsciiName") == request.AsciiName); + + if (exists) + { + throw new ArgumentException($"An entity with the name '{request.AsciiName}' already exists."); + } + + var city = new City + { + AsciiName = request.AsciiName, + GeoNamesId = request.GeoNamesId, + AlternateNames = request.AlternateNames, + CountryCode = request.CountryCode, + }; + + _dbContext.Set().Add(city); + await _dbContext.SaveChangesAsync(); + + return new CityDetailDto + { + Id = city.Id, + AsciiName = city.AsciiName, + GeoNamesId = city.GeoNamesId, + AlternateNames = city.AlternateNames, + CountryCode = city.CountryCode, + }; + } + + public async Task UpdateAsync(int id, CityUpdateRequest request) + { + var city = await _dbContext.Set() + .FirstOrDefaultAsync(ws => ws.Id == id); + + if (city == null) + throw new ArgumentException($"Entity with ID {id} not found."); + + if (request.AsciiName != null) + city.AsciiName = request.AsciiName; + + if (request.GeoNamesId != null) + city.GeoNamesId = request.GeoNamesId; + + if (request.AlternateNames != null) + city.AlternateNames = request.AlternateNames; + + if (request.CountryCode != null) + city.CountryCode = request.CountryCode; + + await _dbContext.SaveChangesAsync(); + + return new CityDetailDto + { + Id = city.Id, + AsciiName = city.AsciiName, + GeoNamesId = city.GeoNamesId, + AlternateNames = city.AlternateNames, + CountryCode = city.CountryCode, + }; + } + + public async Task DeleteAsync(int id) + { + var city = await _dbContext.Set().FindAsync(id); + if (city == null) + return false; + + _dbContext.Set().Remove(city); + await _dbContext.SaveChangesAsync(); + return true; + } +} diff --git a/backend/Services/EntityService.cs b/backend/Services/EntityService.cs index 86cc0c0..e10226a 100644 --- a/backend/Services/EntityService.cs +++ b/backend/Services/EntityService.cs @@ -81,13 +81,14 @@ public async Task UpdateAsync(int id, UpdateRequest request) }; } - public async Task DeleteAsync(int id) + public async Task DeleteAsync(int id) { var entity = await _dbContext.Set().FindAsync(id); if (entity == null) - throw new ArgumentException($"Entity with ID {id} not found."); + return false; _dbContext.Set().Remove(entity); await _dbContext.SaveChangesAsync(); + return true; } } diff --git a/backend/Services/Interfaces/IComplexEntityService.cs b/backend/Services/Interfaces/IComplexEntityService.cs new file mode 100644 index 0000000..2e9537c --- /dev/null +++ b/backend/Services/Interfaces/IComplexEntityService.cs @@ -0,0 +1,12 @@ +using Mappa.Dtos; + +namespace Mappa.Services; + +public interface IComplexEntityService +{ + Task> GetAllAsync(); + Task GetByIdAsync(int id); + Task CreateAsync(TCreateRequest request); + Task UpdateAsync(int id, TUpdateRequest request); + Task DeleteAsync(int id); +} diff --git a/backend/Services/Interfaces/IEntityService.cs b/backend/Services/Interfaces/IEntityService.cs index d356498..4bbc8af 100644 --- a/backend/Services/Interfaces/IEntityService.cs +++ b/backend/Services/Interfaces/IEntityService.cs @@ -4,9 +4,9 @@ namespace Mappa.Services; public interface IEntityService { - Task> GetAllAsync(); + Task> GetAllAsync(); Task GetByIdAsync(int id); Task CreateAsync(CreateRequest request); Task UpdateAsync(int id, UpdateRequest request); - Task DeleteAsync(int id); + Task DeleteAsync(int id); } diff --git a/backend/Services/OrdinaryPersonService.cs b/backend/Services/OrdinaryPersonService.cs new file mode 100644 index 0000000..94c26a6 --- /dev/null +++ b/backend/Services/OrdinaryPersonService.cs @@ -0,0 +1,463 @@ +using Mappa.Db; +using Mappa.Dtos; +using Mappa.Entities; +using Microsoft.EntityFrameworkCore; +using AutoMapper; +using Microsoft.IdentityModel.Tokens; +using System.ComponentModel.DataAnnotations; + +namespace Mappa.Services; + +public class OrdinaryPersonService : IComplexEntityService +{ + private readonly AppDbContext _dbContext; + private readonly IMapper _mapper; + + public OrdinaryPersonService(AppDbContext dbContext, IMapper mapper) + { + _dbContext = dbContext; + _mapper = mapper; + } + + public async Task> GetAllAsync() + { + return await _dbContext.Set() + .Include(ws => ws.Religion) + .Include(ws => ws.Ethnicity) + .Include(ws => ws.Profession) + .Include(ws => ws.Location) + .Include(ws => ws.Sources) + .Include(ws => ws.Gender) + .Select(e => new OrdinaryPersonGeneralDto + { + Id = e.Id, + Name = e.Name, + Religion = _mapper.Map(e.Religion), + Ethnicity = _mapper.Map(e.Ethnicity), + Profession = _mapper.Map(e.Profession), + Location = _mapper.Map(e.Location), + Sources = _mapper.Map>(e.Sources), + Gender = _mapper.Map(e.Gender), + }) + .ToListAsync(); + } + + public async Task GetByIdAsync(int id) + { + var entity = await _dbContext.Set() + .Include(ws => ws.Religion) + .Include(ws => ws.Ethnicity) + .Include(ws => ws.Profession) + .Include(ws => ws.Location) + .Include(ws => ws.Sources) + .Include(ws => ws.Gender) + .Include(ws => ws.FormerReligion) + .Include(ws => ws.InteractionsWithOrdinaryA) + .Include(ws => ws.InteractionsWithUnordinary) + .Include(ws => ws.Sources) + .FirstOrDefaultAsync(ws => ws.Id == id); + + if (entity == null) + throw new ArgumentException($"Entity with ID {id} not found."); + + return new OrdinaryPersonDetailDto + { + + Id = entity.Id, + Name = entity.Name, + Religion = _mapper.Map(entity.Religion), + Ethnicity = _mapper.Map(entity.Ethnicity), + Profession = _mapper.Map(entity.Profession), + Location = _mapper.Map(entity.Location), + Sources = _mapper.Map>(entity.Sources), + Gender = _mapper.Map(entity.Gender), + AlternateName = entity.AlternateName, + BirthYear = entity.BirthYear, + DeathYear = entity.DeathYear, + ProbableBirthYear = entity.ProbableBirthYear, + ProbableDeathYear = entity.ProbableDeathYear, + Description = entity.Description, + FormerReligion = _mapper.Map>(entity.FormerReligion), + ReligionExplanation = entity.ReligionExplanation, + ProfessionExplanation = entity.ProfessionExplanation, + InterestingFeature = entity.InterestingFeature, + InteractionWithOrdinaryExplanation = entity.InteractionWithOrdinaryExplanation, + InteractionWithUnordinaryExplanation = entity.InteractionWithUnordinaryExplanation, + Biography = entity.Biography, + DepictionInTheSource = entity.DepictionInTheSource, + ExplanationOfEthnicity = entity.ExplanationOfEthnicity, + InteractionsWithOrdinaryA = _mapper.Map>(entity.InteractionsWithOrdinaryA), + InteractionsWithUnordinary = _mapper.Map>(entity.InteractionsWithUnordinary), + BackgroundCity = _mapper.Map(entity.BackgroundCity), + }; + } + + public async Task CreateAsync(OrdinaryPersonCreateRequest request) + { + var ordinaryPerson = new OrdinaryPerson + { + Name = request.Name, + AlternateName = request.AlternateName, + BirthYear = request.BirthYear, + DeathYear = request.DeathYear, + ProbableBirthYear = request.ProbableBirthYear, + ProbableDeathYear = request.ProbableDeathYear, + Description = request.Description, + ReligionExplanation = request.ReligionExplanation, + ProfessionExplanation = request.ProfessionExplanation, + InterestingFeature = request.InterestingFeature, + InteractionWithOrdinaryExplanation = request.InteractionWithOrdinaryExplanation, + InteractionWithUnordinaryExplanation = request.InteractionWithUnordinaryExplanation, + Biography = request.Biography, + DepictionInTheSource = request.DepictionInTheSource, + ExplanationOfEthnicity = request.ExplanationOfEthnicity, + }; + + // Check if Religion exists + if(request.Religion != null) + { + var religion = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Religion); + if (religion == null) + throw new ArgumentException($"Religion with name {request.Religion} not found."); + ordinaryPerson.Religion = religion; + } + + // Check if Ethnicity exists + if(request.Ethnicity != null) + { + var ethnicity = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Ethnicity); + if (ethnicity == null) + throw new ArgumentException($"Ethnicity with name {request.Ethnicity} not found."); + ordinaryPerson.Ethnicity = ethnicity; + } + + // Check if Profession exists + if(request.Profession != null) + { + var profession = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Profession); + if (profession == null) + throw new ArgumentException($"Profession with name {request.Profession} not found."); + ordinaryPerson.Profession = profession; + } + + // Check if Location exists + if(request.Location != null) + { + var location = await _dbContext.Set().FirstOrDefaultAsync(e => e.AsciiName == request.Location); + if (location == null) + throw new ArgumentException($"Location with name {request.Location} not found."); + ordinaryPerson.Location = location; + } + + // Check if Sources elements exists + if (request.Sources != null) + { + var sources = await _dbContext.Set() + .Where(c => request.Sources.Contains(c.Id)) + .ToListAsync(); + + if (sources.Count != request.Sources.Count) + throw new ArgumentException("One or more provided Sources are invalid."); + ordinaryPerson.Sources = sources; + } + + // Check if Gender exists + if(request.Gender != null) + { + var gender = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Gender); + if (gender == null) + throw new ArgumentException($"Gender with name {request.Gender} not found."); + ordinaryPerson.Gender = gender; + } + + // Check if FormerReligion elements exists + if (request.FormerReligion != null) + { + var formerReligion = await _dbContext.Set() + .Where(c => request.FormerReligion.Contains(c.Name)) + .ToListAsync(); + + if (formerReligion.Count != request.FormerReligion.Count) + throw new ArgumentException("One or more provided Formerreligion are invalid."); + ordinaryPerson.FormerReligion = formerReligion; + } + + // Check if InteractionsWithOrdinaryA elements exists + if (request.InteractionsWithOrdinaryA != null) + { + var interactionsWithOrdinaryA = await _dbContext.Set() + .Where(c => request.InteractionsWithOrdinaryA.Contains(c.Id)) + .ToListAsync(); + + if (interactionsWithOrdinaryA.Count != request.InteractionsWithOrdinaryA.Count) + throw new ArgumentException("One or more provided InteractionsWithOrdinaryA are invalid."); + ordinaryPerson.InteractionsWithOrdinaryA = interactionsWithOrdinaryA; + } + + // Check if InteractionsWithUnordinary elements exists + if (request.InteractionsWithUnordinary != null) + { + var interactionsWithUnordinary = await _dbContext.Set() + .Where(c => request.InteractionsWithUnordinary.Contains(c.Id)) + .ToListAsync(); + + if (interactionsWithUnordinary.Count != request.InteractionsWithUnordinary.Count) + throw new ArgumentException("One or more provided InteractionsWithUnordinary are invalid."); + ordinaryPerson.InteractionsWithUnordinary = interactionsWithUnordinary; + } + + // Check if BackgroundCity exists + if(request.BackgroundCity != null) + { + var backgroundCity = await _dbContext.Set().FirstOrDefaultAsync(e => e.AsciiName == request.BackgroundCity); + if (backgroundCity == null) + throw new ArgumentException($"BackgroundCity with name {request.BackgroundCity} not found."); + ordinaryPerson.BackgroundCity = backgroundCity; + } + + _dbContext.Set().Add(ordinaryPerson); + await _dbContext.SaveChangesAsync(); + + return new OrdinaryPersonDetailDto + { + Name = ordinaryPerson.Name, + Religion = _mapper.Map(ordinaryPerson.Religion), + Ethnicity = _mapper.Map(ordinaryPerson.Ethnicity), + Profession = _mapper.Map(ordinaryPerson.Profession), + Location = _mapper.Map(ordinaryPerson.Location), + Sources = _mapper.Map>(ordinaryPerson.Sources), + Gender = _mapper.Map(ordinaryPerson.Gender), + AlternateName = ordinaryPerson.AlternateName, + BirthYear = ordinaryPerson.BirthYear, + DeathYear = ordinaryPerson.DeathYear, + ProbableBirthYear = ordinaryPerson.ProbableBirthYear, + ProbableDeathYear = ordinaryPerson.ProbableDeathYear, + Description = ordinaryPerson.Description, + FormerReligion = _mapper.Map>(ordinaryPerson.FormerReligion), + ReligionExplanation = ordinaryPerson.ReligionExplanation, + ProfessionExplanation = ordinaryPerson.ProfessionExplanation, + InterestingFeature = ordinaryPerson.InterestingFeature, + InteractionWithOrdinaryExplanation = ordinaryPerson.InteractionWithOrdinaryExplanation, + InteractionWithUnordinaryExplanation = ordinaryPerson.InteractionWithUnordinaryExplanation, + Biography = ordinaryPerson.Biography, + DepictionInTheSource = ordinaryPerson.DepictionInTheSource, + ExplanationOfEthnicity = ordinaryPerson.ExplanationOfEthnicity, + InteractionsWithOrdinaryA = _mapper.Map>(ordinaryPerson.InteractionsWithOrdinaryA), + InteractionsWithUnordinary = _mapper.Map>(ordinaryPerson.InteractionsWithUnordinary), + BackgroundCity = _mapper.Map(ordinaryPerson.BackgroundCity), + }; + } + + public async Task UpdateAsync(int id, OrdinaryPersonUpdateRequest request) + { + var ordinaryPerson = await _dbContext.Set() + .Include(ws => ws.Religion) + .Include(ws => ws.Ethnicity) + .Include(ws => ws.Profession) + .Include(ws => ws.Location) + .Include(ws => ws.Sources) + .Include(ws => ws.Gender) + .Include(ws => ws.FormerReligion) + .Include(ws => ws.InteractionsWithOrdinaryA) + .Include(ws => ws.InteractionsWithUnordinary) + .Include(ws => ws.Sources) + .FirstOrDefaultAsync(ws => ws.Id == id); + + if (ordinaryPerson == null) + throw new ArgumentException($"Entity with ID {id} not found."); + + // Religion update only if a valid religion name is provided + if (request.Religion != null) + { + var religion = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Religion); + if (religion == null) + throw new ArgumentException($"Religion with name {request.Religion} not found."); + ordinaryPerson.Religion = religion; + } + + // Ethnicity update only if a valid ethnicity name is provided + if (request.Ethnicity != null) + { + var ethnicity = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Ethnicity); + if (ethnicity == null) + throw new ArgumentException($"Ethnicity with name {request.Ethnicity} not found."); + ordinaryPerson.Ethnicity = ethnicity; + } + + // Profession update only if a valid profession name is provided + if (request.Profession != null) + { + var profession = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Profession); + if (profession == null) + throw new ArgumentException($"Profession with name {request.Profession} not found."); + ordinaryPerson.Profession = profession; + } + + // Location update only if a valid city is provided + if (request.Location != null) + { + var location = await _dbContext.Set().FirstOrDefaultAsync(e => e.AsciiName == request.Location); + if (location == null) + throw new ArgumentException($"Location with name {request.Location} not found."); + ordinaryPerson.Location = location; + } + + // Update Sources + if (request.Sources != null) + { + var sources = await _dbContext.Set() + .Where(l => request.Sources.Contains(l.Id)) + .ToListAsync(); + + if (sources.Count != request.Sources.Count) + throw new ArgumentException("One or more provided Written Source are invalid."); + + ordinaryPerson.Sources = sources; + } + + // Gender update only if a valid gender name is provided + if (request.Gender != null) + { + var gender = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Gender); + if (gender == null) + throw new ArgumentException($"Gender with name {request.Gender} not found."); + ordinaryPerson.Gender = gender; + } + + if (request.AlternateName != null) + ordinaryPerson.AlternateName = request.AlternateName; + + if ((request.BirthYear!= null) && (request.BirthYear.Count > 0)) + ordinaryPerson.BirthYear = request.BirthYear; + + // Only update fields if they are not null + if ((request.DeathYear != null) && (request.DeathYear.Count > 0)) + ordinaryPerson.DeathYear = request.DeathYear; + + // Only update fields if they are provided in the request + if (request.ProbableBirthYear != null) + ordinaryPerson.ProbableBirthYear = request.ProbableBirthYear; + + if (request.ProbableDeathYear != null) + ordinaryPerson.ProbableDeathYear = request.ProbableDeathYear; + + if (request.Description != null) + ordinaryPerson.Description = request.Description; + + // Update FormerReligion + if (request.FormerReligion != null) + { + var formerReligion = await _dbContext.Set() + .Where(l => request.FormerReligion.Contains(l.Name)) + .ToListAsync(); + + if (formerReligion.Count != request.FormerReligion.Count) + throw new ArgumentException("One or more provided Former Religion are invalid."); + + ordinaryPerson.FormerReligion = formerReligion; + } + + if (request.ReligionExplanation != null) + ordinaryPerson.ReligionExplanation = request.ReligionExplanation; + + if (request.ProfessionExplanation != null) + ordinaryPerson.ProfessionExplanation = request.ProfessionExplanation; + + if (request.InterestingFeature != null) + ordinaryPerson.InterestingFeature = request.InterestingFeature; + + if (request.InteractionWithOrdinaryExplanation != null) + ordinaryPerson.InteractionWithOrdinaryExplanation = request.InteractionWithOrdinaryExplanation; + + if (request.InteractionWithUnordinaryExplanation != null) + ordinaryPerson.InteractionWithUnordinaryExplanation = request.InteractionWithUnordinaryExplanation; + + if (request.Biography != null) + ordinaryPerson.Biography = request.Biography; + + if (request.DepictionInTheSource != null) + ordinaryPerson.DepictionInTheSource = request.DepictionInTheSource; + + if (request.ExplanationOfEthnicity != null) + ordinaryPerson.ExplanationOfEthnicity = request.ExplanationOfEthnicity; + + // Update InteractionsWithOrdinaryA + if (request.InteractionsWithOrdinaryA != null) + { + var InteractionsWithOrdinaryA = await _dbContext.Set() + .Where(l => request.InteractionsWithOrdinaryA.Contains(l.Id)) + .ToListAsync(); + + if (InteractionsWithOrdinaryA.Count != request.InteractionsWithOrdinaryA.Count) + throw new ArgumentException("One or more provided Ordinary Person are invalid."); + + ordinaryPerson.InteractionsWithOrdinaryA = InteractionsWithOrdinaryA; + } + + // Update InteractionsWithUnordinary + if (request.InteractionsWithUnordinary != null) + { + var InteractionsWithUnordinary = await _dbContext.Set() + .Where(l => request.InteractionsWithUnordinary.Contains(l.Id)) + .ToListAsync(); + + if (InteractionsWithUnordinary.Count != request.InteractionsWithUnordinary.Count) + throw new ArgumentException("One or more provided Unordinary Person are invalid."); + + ordinaryPerson.InteractionsWithUnordinary = InteractionsWithUnordinary; + } + + // BackgroundCity update only if a valid ID is provided + if (request.BackgroundCity != null) + { + var backgroundCity = await _dbContext.Set().FirstOrDefaultAsync(e => e.AsciiName == request.BackgroundCity); + if (backgroundCity == null) + throw new ArgumentException($"BackgroundCity with name {request.BackgroundCity} not found."); + ordinaryPerson.BackgroundCity = backgroundCity; + } + + await _dbContext.SaveChangesAsync(); + + return new OrdinaryPersonDetailDto + { + Name = ordinaryPerson.Name, + Religion = _mapper.Map(ordinaryPerson.Religion), + Ethnicity = _mapper.Map(ordinaryPerson.Ethnicity), + Profession = _mapper.Map(ordinaryPerson.Profession), + Location = _mapper.Map(ordinaryPerson.Location), + Sources = _mapper.Map>(ordinaryPerson.Sources), + Gender = _mapper.Map(ordinaryPerson.Gender), + AlternateName = ordinaryPerson.AlternateName, + BirthYear = ordinaryPerson.BirthYear, + DeathYear = ordinaryPerson.DeathYear, + ProbableBirthYear = ordinaryPerson.ProbableBirthYear, + ProbableDeathYear = ordinaryPerson.ProbableDeathYear, + Description = ordinaryPerson.Description, + FormerReligion = _mapper.Map>(ordinaryPerson.FormerReligion), + ReligionExplanation = ordinaryPerson.ReligionExplanation, + ProfessionExplanation = ordinaryPerson.ProfessionExplanation, + InterestingFeature = ordinaryPerson.InterestingFeature, + InteractionWithOrdinaryExplanation = ordinaryPerson.InteractionWithOrdinaryExplanation, + InteractionWithUnordinaryExplanation = ordinaryPerson.InteractionWithUnordinaryExplanation, + Biography = ordinaryPerson.Biography, + DepictionInTheSource = ordinaryPerson.DepictionInTheSource, + ExplanationOfEthnicity = ordinaryPerson.ExplanationOfEthnicity, + InteractionsWithOrdinaryA = _mapper.Map>(ordinaryPerson.InteractionsWithOrdinaryA), + InteractionsWithUnordinary = _mapper.Map>(ordinaryPerson.InteractionsWithUnordinary), + BackgroundCity = _mapper.Map(ordinaryPerson.BackgroundCity), + }; + } + + public async Task DeleteAsync(int id) + { + var ordinaryPerson = await _dbContext.Set().FindAsync(id); + if (ordinaryPerson == null) + return false; + + _dbContext.Set().Remove(ordinaryPerson); + await _dbContext.SaveChangesAsync(); + return true; + } +} diff --git a/backend/Services/SecondarySourceService.cs b/backend/Services/SecondarySourceService.cs new file mode 100644 index 0000000..090179f --- /dev/null +++ b/backend/Services/SecondarySourceService.cs @@ -0,0 +1,230 @@ +using Mappa.Db; +using Mappa.Dtos; +using Mappa.Entities; +using Microsoft.EntityFrameworkCore; +using AutoMapper; +using Microsoft.IdentityModel.Tokens; + +namespace Mappa.Services; + +public class SecondarySourceService : IComplexEntityService +{ + private readonly AppDbContext _dbContext; + private readonly IMapper _mapper; + + public SecondarySourceService(AppDbContext dbContext, IMapper mapper) + { + _dbContext = dbContext; + _mapper = mapper; + } + + public async Task> GetAllAsync() + { + return await _dbContext.Set() + .Include(ss => ss.Type ) + .Select(e => new SecondarySourceGeneralDto + { + Id = e.Id, + AlternateNames = e.AlternateNames, + Author = e.Author, + YearWritten = e.YearWritten, + University = e.University, + Type = _mapper.Map(e.Type) + }) + .ToListAsync(); + } + + public async Task GetByIdAsync(int id) + { + var entity = await _dbContext.Set() + .Include(ss => ss.Type) + .Include(ss => ss.Language) + .Include(ss => ss.TranslatedLanguages) + .FirstOrDefaultAsync(ss => ss.Id == id); + + if (entity == null) + throw new ArgumentException($"Entity with ID {id} not found."); + + return new SecondarySourceDetailDto + { + Id = entity.Id, + AlternateNames = entity.AlternateNames, + Author = entity.Author, + YearWritten = entity.YearWritten, + University = entity.University, + Type = _mapper.Map(entity.Type), + Topic = entity.Topic, + BibliographyInformation = entity.BibliographyInformation, + OtherInformation = entity.OtherInformation, + Language = _mapper.Map(entity.Language), + TranslatedLanguages = _mapper.Map>(entity.TranslatedLanguages), + }; + } + + public async Task CreateAsync(SecondarySourceCreateRequest request) + { + if ((request.AlternateNames != null) && (request.AlternateNames.Count == 0) ) + throw new ArgumentException("Alternate names is not provided"); + + bool exists = await _dbContext.Set() + .AnyAsync(ws => ws.AlternateNames.Any(name => request.AlternateNames.Contains(name))); + + if (exists) + throw new ArgumentException("A secondary source with one or more of the provided alternate names already exists."); + + var entity = new SecondarySource + { + AlternateNames = request.AlternateNames, + Author = request.Author, + YearWritten = request.YearWritten, + University = request.University, + Topic = request.Topic, + BibliographyInformation = request.BibliographyInformation, + OtherInformation = request.OtherInformation + }; + + // Check if Type exists + if(request.Type != null) + { + Entities.Type? type = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Type); + if (type == null) + throw new ArgumentException($"Type with name {request.Type} not found."); + entity.Type = type; + } + + // Check if Language exists + if(request.Language != null) + { + Language? language = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Language); + if (language == null) + throw new ArgumentException($"Language with name {request.Language} not found."); + entity.Language = language; + } + + if (request.TranslatedLanguages != null) + { + List? translatedLanguages = await _dbContext.Set() + .Where(l => request.TranslatedLanguages.Contains(l.Name)) + .ToListAsync(); + + if (translatedLanguages.Count != request.TranslatedLanguages.Count) + throw new ArgumentException("One or more provided Translated Languages are invalid."); + entity.TranslatedLanguages = translatedLanguages; + } + + + _dbContext.Set().Add(entity); + await _dbContext.SaveChangesAsync(); + + return new SecondarySourceDetailDto + { + Id = entity.Id, + AlternateNames = entity.AlternateNames, + Author = entity.Author, + YearWritten = entity.YearWritten, + University = entity.University, + Type = _mapper.Map(entity.Type), + Topic = entity.Topic, + BibliographyInformation = entity.BibliographyInformation, + OtherInformation = entity.OtherInformation, + Language = _mapper.Map(entity.Language), + TranslatedLanguages = _mapper.Map>(entity.TranslatedLanguages), + }; + } + + public async Task UpdateAsync(int id, SecondarySourceUpdateRequest request) + { + var secondarySource = await _dbContext.Set() + .Include(ws => ws.Type) + .Include(ws => ws.Language) + .Include(ws => ws.TranslatedLanguages) + .FirstOrDefaultAsync(ws => ws.Id == id); + + if (secondarySource == null) + throw new ArgumentException($"Entity with ID {id} not found."); + + // Only update fields if they are not null + if (request.AlternateNames != null) + secondarySource.AlternateNames = request.AlternateNames; + + if (request.Author != null) + secondarySource.Author = request.Author; + + if (request.YearWritten != null) // DateOnly + secondarySource.YearWritten = request.YearWritten; + + if (request.University != null) + secondarySource.University = request.University; + + // Type update only if a valid type is provided + if (request.Type != null) + { + var type = await _dbContext.Set().FirstOrDefaultAsync( + e => e.Name == request.Type); + if (type == null) + throw new ArgumentException($"Type with name {request.Type} not found."); + secondarySource.Type = type; + } + + if (request.Topic != null) + secondarySource.Topic = request.Topic; + + if (request.BibliographyInformation != null) + secondarySource.BibliographyInformation = request.BibliographyInformation; + + if (request.OtherInformation != null) + secondarySource.OtherInformation = request.OtherInformation; + + // Language update only if a valid language is provided + if (request.Language != null) + { + var language = await _dbContext.Set().FirstOrDefaultAsync( + e => e.Name == request.Language); + if (language == null) + throw new ArgumentException($"Language with name {request.Language} not found."); + secondarySource.Language = language; + } + + // Update TranslatedLanguages (List of LanguageDto) + if (request.TranslatedLanguages != null) + { + var translatedLanguages = await _dbContext.Set() + .Where(l => request.TranslatedLanguages.Contains(l.Name)) + .ToListAsync(); + + if (translatedLanguages.Count != request.TranslatedLanguages.Count) + throw new ArgumentException("One or more provided Translated Language IDs are invalid."); + + secondarySource.TranslatedLanguages = translatedLanguages; + } + + await _dbContext.SaveChangesAsync(); + + return new SecondarySourceDetailDto + { + Id = secondarySource.Id, + AlternateNames = secondarySource.AlternateNames, + Author = secondarySource.Author, + YearWritten = secondarySource.YearWritten, + University = secondarySource.University, + Type = _mapper.Map(secondarySource.Type), + Topic = secondarySource.Topic, + BibliographyInformation = secondarySource.BibliographyInformation, + OtherInformation = secondarySource.OtherInformation, + Language = _mapper.Map(secondarySource.Language), + TranslatedLanguages = _mapper.Map>(secondarySource.TranslatedLanguages), + }; + } + + public async Task DeleteAsync(int id) + { + var secondarySource = await _dbContext.Set().FindAsync(id); + if (secondarySource == null) + return false; + + _dbContext.Set().Remove(secondarySource); + await _dbContext.SaveChangesAsync(); + return true; + } +} diff --git a/backend/Services/UnordinaryPersonService.cs b/backend/Services/UnordinaryPersonService.cs new file mode 100644 index 0000000..3e9199d --- /dev/null +++ b/backend/Services/UnordinaryPersonService.cs @@ -0,0 +1,414 @@ +using Mappa.Db; +using Mappa.Dtos; +using Mappa.Entities; +using Microsoft.EntityFrameworkCore; +using AutoMapper; +using Microsoft.IdentityModel.Tokens; +using System.ComponentModel.DataAnnotations; + +namespace Mappa.Services; + +public class UnordinaryPersonService : IComplexEntityService +{ + private readonly AppDbContext _dbContext; + private readonly IMapper _mapper; + + public UnordinaryPersonService(AppDbContext dbContext, IMapper mapper) + { + _dbContext = dbContext; + _mapper = mapper; + } + + public async Task> GetAllAsync() + { + return await _dbContext.Set() + .Include(ws => ws.Religion) + .Include(ws => ws.Ethnicity) + .Include(ws => ws.DeathPlace) + .Include(ws => ws.InteractionsWithOrdinary) + .Select(e => new UnordinaryPersonGeneralDto + { + Id = e.Id, + Name = e.Name, + Religion = _mapper.Map(e.Religion), + Ethnicity = _mapper.Map(e.Ethnicity), + DeathYear = e.DeathYear, + DeathPlace = _mapper.Map(e.DeathPlace), + InteractionsWithOrdinary = _mapper.Map>(e.InteractionsWithOrdinary) + }) + .ToListAsync(); + } + + public async Task GetByIdAsync(int id) + { + var entity = await _dbContext.Set() + .Include(ws => ws.Religion) + .Include(ws => ws.Ethnicity) + .Include(ws => ws.DeathPlace) + .Include(ws => ws.InteractionsWithOrdinary) + .Include(ws => ws.FormerReligion) + .Include(ws => ws.Profession) + .Include(ws => ws.Gender) + .Include(ws => ws.InteractionsWithUnordinaryA) + .Include(ws => ws.Sources) + .FirstOrDefaultAsync(ws => ws.Id == id); + + if (entity == null) + throw new ArgumentException($"Entity with ID {id} not found."); + + return new UnordinaryPersonDetailDto + { + Id = entity.Id, + Name = entity.Name, + Religion = _mapper.Map(entity.Religion), + Ethnicity = _mapper.Map(entity.Ethnicity), + DeathYear = entity.DeathYear, + DeathPlace = _mapper.Map(entity.DeathPlace), + InteractionsWithOrdinary = _mapper.Map>(entity.InteractionsWithOrdinary), + AlternateName = entity.AlternateName, + BirthYear = entity.BirthYear, + ProbableBirthYear = entity.ProbableBirthYear, + ProbableDeathYear = entity.ProbableDeathYear, + Description = entity.Description, + FormerReligion = _mapper.Map>(entity.FormerReligion), + Profession = _mapper.Map(entity.Profession), + Gender = _mapper.Map(entity.Gender), + BirthPlace = _mapper.Map(entity.BirthPlace), + InteractionsWithUnordinaryA = _mapper.Map>(entity.InteractionsWithUnordinaryA), + InteractionsWithUnordinaryB = _mapper.Map>(entity.InteractionsWithUnordinaryB), + Sources = _mapper.Map>(entity.Sources), + }; + } + + public async Task CreateAsync(UnordinaryPersonCreateRequest request) + { + var unordinaryPerson = new UnordinaryPerson + { + Name = request.Name, + AlternateName = request.AlternateName, + BirthYear = request.BirthYear, + DeathYear = request.DeathYear, + ProbableBirthYear = request.ProbableBirthYear, + ProbableDeathYear = request.ProbableDeathYear, + Description = request.Description, + // Religion = _mapper.Map(request.Religion), + // Ethnicity = _mapper.Map(request.Ethnicity), + // FormerReligion = _mapper.Map>(request.FormerReligion), + // Profession = _mapper.Map(request.Profession), + // Gender = _mapper.Map(request.Gender), + // Sources = _mapper.Map>(request.Sources), + // InteractionsWithOrdinary = _mapper.Map>(request.InteractionsWithOrdinary), + // InteractionsWithUnordinaryA = _mapper.Map>(request.InteractionsWithUnordinaryA), + // BirthPlace = _mapper.Map(request.BirthPlace), + // DeathPlace = _mapper.Map(request.DeathPlace), + }; + + // Check if Religion exists + if(request.Religion != null) + { + var religion = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Religion); + if (religion == null) + throw new ArgumentException($"Religion with name {request.Religion} not found."); + unordinaryPerson.Religion = religion; + } + + // Check if Ethnicity exists + if(request.Ethnicity != null) + { + var ethnicity = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Ethnicity); + if (ethnicity == null) + throw new ArgumentException($"Ethnicity with name {request.Ethnicity} not found."); + unordinaryPerson.Ethnicity = ethnicity; + } + + // Check if DeathPlace exists + if(request.DeathPlace != null) + { + var deathPlace = await _dbContext.Set().FirstOrDefaultAsync(e => e.AsciiName == request.DeathPlace); + if (deathPlace == null) + throw new ArgumentException($"DeathPlace with name {request.DeathPlace} not found."); + unordinaryPerson.DeathPlace = deathPlace; + } + + // Check if InteractionsWithOrdinary elements exists + if (request.InteractionsWithOrdinary != null) + { + var interactionsWithOrdinary = await _dbContext.Set() + .Where(c => request.InteractionsWithOrdinary.Contains(c.Id)) + .ToListAsync(); + + if (interactionsWithOrdinary.Count != request.InteractionsWithOrdinary.Count) + throw new ArgumentException("One or more provided InteractionsWithOrdinary are invalid."); + unordinaryPerson.InteractionsWithOrdinary = interactionsWithOrdinary; + } + + // Check if FormerReligion elements exists + if (request.FormerReligion != null) + { + var formerReligion = await _dbContext.Set() + .Where(c => request.FormerReligion.Contains(c.Name)) + .ToListAsync(); + + if (formerReligion.Count != request.FormerReligion.Count) + throw new ArgumentException("One or more provided Formerreligion are invalid."); + unordinaryPerson.FormerReligion = formerReligion; + } + + // Check if Profession exists + if(request.Profession != null) + { + var profession = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Profession); + if (profession == null) + throw new ArgumentException($"Profession with name {request.Profession} not found."); + unordinaryPerson.Profession = profession; + } + + // Check if Gender exists + if(request.Gender != null) + { + var gender = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Gender); + if (gender == null) + throw new ArgumentException($"Gender with name {request.Gender} not found."); + unordinaryPerson.Gender = gender; + } + + // Check if BirthPlace exists + if(request.BirthPlace != null) + { + var birthPlace = await _dbContext.Set().FirstOrDefaultAsync(e => e.AsciiName == request.BirthPlace); + if (birthPlace == null) + throw new ArgumentException($"BirthPlace with name {request.BirthPlace} not found."); + unordinaryPerson.BirthPlace = birthPlace; + } + + // Check if InteractionsWithUnordinaryA elements exists + if (request.InteractionsWithUnordinaryA != null) + { + var interactionsWithUnordinaryA = await _dbContext.Set() + .Where(c => request.InteractionsWithUnordinaryA.Contains(c.Id)) + .ToListAsync(); + + if (interactionsWithUnordinaryA.Count != request.InteractionsWithUnordinaryA.Count) + throw new ArgumentException("One or more provided InteractionsWithUnordinaryA are invalid."); + unordinaryPerson.InteractionsWithUnordinaryA = interactionsWithUnordinaryA; + } + + // Check if Sources elements exists + if (request.Sources != null) + { + var sources = await _dbContext.Set() + .Where(c => request.Sources.Contains(c.Id)) + .ToListAsync(); + + if (sources.Count != request.Sources.Count) + throw new ArgumentException("One or more provided Sources are invalid."); + unordinaryPerson.Sources = sources; + } + + _dbContext.Set().Add(unordinaryPerson); + await _dbContext.SaveChangesAsync(); + + return new UnordinaryPersonDetailDto + { + Id = unordinaryPerson.Id, + Name = unordinaryPerson.Name, + AlternateName = unordinaryPerson.AlternateName, + BirthYear = unordinaryPerson.BirthYear, + DeathYear = unordinaryPerson.DeathYear, + ProbableBirthYear = unordinaryPerson.ProbableBirthYear, + ProbableDeathYear = unordinaryPerson.ProbableDeathYear, + Description = unordinaryPerson.Description, + Religion = _mapper.Map(unordinaryPerson.Religion), + Ethnicity = _mapper.Map(unordinaryPerson.Ethnicity), + FormerReligion = _mapper.Map>(unordinaryPerson.FormerReligion), + Profession = _mapper.Map(unordinaryPerson.Profession), + Gender = _mapper.Map(unordinaryPerson.Gender), + Sources = _mapper.Map>(unordinaryPerson.Sources), + InteractionsWithOrdinary = _mapper.Map>(unordinaryPerson.InteractionsWithOrdinary), + InteractionsWithUnordinaryA = _mapper.Map>(unordinaryPerson.InteractionsWithUnordinaryA), + InteractionsWithUnordinaryB = _mapper.Map>(unordinaryPerson.InteractionsWithUnordinaryB), + BirthPlace = _mapper.Map(unordinaryPerson.BirthPlace), + DeathPlace = _mapper.Map(unordinaryPerson.DeathPlace), + }; + } + + public async Task UpdateAsync(int id, UnordinaryPersonUpdateRequest request) + { + var unordinaryPerson = await _dbContext.Set() + .Include(ws => ws.Religion) + .Include(ws => ws.Ethnicity) + .Include(ws => ws.DeathPlace) + .Include(ws => ws.InteractionsWithOrdinary) + .Include(ws => ws.FormerReligion) + .Include(ws => ws.Profession) + .Include(ws => ws.Gender) + .Include(ws => ws.InteractionsWithUnordinaryA) + .Include(ws => ws.Sources) + .FirstOrDefaultAsync(ws => ws.Id == id); + + if (unordinaryPerson == null) + throw new ArgumentException($"Entity with ID {id} not found."); + + // Religion update only if a valid religion is provided + if (request.Religion != null) + { + var religion = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Religion); + if (religion == null) + throw new ArgumentException($"Religion with name {request.Religion} not found."); + unordinaryPerson.Religion = religion; + } + + // Ethnicity update only if a valid ethnicity is provided + if (request.Ethnicity != null) + { + var ethnicity = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Ethnicity); + if (ethnicity == null) + throw new ArgumentException($"Ethnicity with name {request.Ethnicity} not found."); + unordinaryPerson.Ethnicity = ethnicity; + } + + // Only update fields if they are not null + if ((request.DeathYear != null) && (request.DeathYear.Count > 0)) + unordinaryPerson.DeathYear = request.DeathYear; + + // DeathPlace update only if a valid city name is provided + if (request.DeathPlace != null) + { + var deathPlace = await _dbContext.Set().FirstOrDefaultAsync(e => e.AsciiName == request.DeathPlace); + if (deathPlace == null) + throw new ArgumentException($"DeathPlace with name {request.DeathPlace} not found."); + unordinaryPerson.DeathPlace = deathPlace; + } + + // Update InteractionsWithOrdinary + if (request.InteractionsWithOrdinary != null) + { + var interactionsWithOrdinary = await _dbContext.Set() + .Where(l => request.InteractionsWithOrdinary.Contains(l.Id)) + .ToListAsync(); + + if (interactionsWithOrdinary.Count != request.InteractionsWithOrdinary.Count) + throw new ArgumentException("One or more provided Ordinary Person are invalid."); + + unordinaryPerson.InteractionsWithOrdinary = interactionsWithOrdinary; + } + + if (request.AlternateName != null) + unordinaryPerson.AlternateName = request.AlternateName; + + if (request.BirthYear != null && request.BirthYear.Count > 0) + unordinaryPerson.BirthYear = request.BirthYear; + + // Only update fields if they are provided in the request + if (request.ProbableBirthYear != null) + unordinaryPerson.ProbableBirthYear = request.ProbableBirthYear; + + if (request.ProbableDeathYear != null) + unordinaryPerson.ProbableDeathYear = request.ProbableDeathYear; + + if (request.Description != null) + unordinaryPerson.Description = request.Description; + + // Update FormerReligion + if (request.FormerReligion != null) + { + var formerReligion = await _dbContext.Set() + .Where(l => request.FormerReligion.Contains(l.Name)) + .ToListAsync(); + + if (formerReligion.Count != request.FormerReligion.Count) + throw new ArgumentException("One or more provided Former Religion are invalid."); + + unordinaryPerson.FormerReligion = formerReligion; + } + + // Profession update only if a valid profession is provided + if (request.Profession != null) + { + var profession = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Profession); + if (profession == null) + throw new ArgumentException($"Profession with name {request.Profession} not found."); + unordinaryPerson.Profession = profession; + } + + // Gender update only if a valid gender is provided + if (request.Gender != null) + { + var gender = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Gender); + if (gender == null) + throw new ArgumentException($"Gender with name {request.Gender} not found."); + unordinaryPerson.Gender = gender; + } + + // BirthPlace update only if a valid city is provided + if (request.BirthPlace != null) + { + var birthPlace = await _dbContext.Set().FirstOrDefaultAsync(e => e.AsciiName == request.BirthPlace); + if (birthPlace == null) + throw new ArgumentException($"BirthPlace with name {request.BirthPlace} not found."); + unordinaryPerson.BirthPlace = birthPlace; + } + + // Update InteractionsWithUnordinaryA + if (request.InteractionsWithUnordinaryA != null) + { + var interactionsWithUnordinaryA = await _dbContext.Set() + .Where(l => request.InteractionsWithUnordinaryA.Contains(l.Id)) + .ToListAsync(); + + if (interactionsWithUnordinaryA.Count != request.InteractionsWithUnordinaryA.Count) + throw new ArgumentException("One or more provided Unordinary Person are invalid."); + + unordinaryPerson.InteractionsWithUnordinaryA = interactionsWithUnordinaryA; + } + + // Update Sources + if (request.Sources != null) + { + var sources = await _dbContext.Set() + .Where(l => request.Sources.Contains(l.Id)) + .ToListAsync(); + + if (sources.Count != request.Sources.Count) + throw new ArgumentException("One or more provided Written Source are invalid."); + + unordinaryPerson.Sources = sources; + } + + await _dbContext.SaveChangesAsync(); + + return new UnordinaryPersonDetailDto + { + Id = unordinaryPerson.Id, + Name = unordinaryPerson.Name, + AlternateName = unordinaryPerson.AlternateName, + BirthYear = unordinaryPerson.BirthYear, + DeathYear = unordinaryPerson.DeathYear, + ProbableBirthYear = unordinaryPerson.ProbableBirthYear, + ProbableDeathYear = unordinaryPerson.ProbableDeathYear, + Description = unordinaryPerson.Description, + Religion = _mapper.Map(unordinaryPerson.Religion), + Ethnicity = _mapper.Map(unordinaryPerson.Ethnicity), + FormerReligion = _mapper.Map>(unordinaryPerson.FormerReligion), + Profession = _mapper.Map(unordinaryPerson.Profession), + Gender = _mapper.Map(unordinaryPerson.Gender), + Sources = _mapper.Map>(unordinaryPerson.Sources), + InteractionsWithOrdinary = _mapper.Map>(unordinaryPerson.InteractionsWithOrdinary), + InteractionsWithUnordinaryA = _mapper.Map>(unordinaryPerson.InteractionsWithUnordinaryA), + InteractionsWithUnordinaryB = _mapper.Map>(unordinaryPerson.InteractionsWithUnordinaryB), + BirthPlace = _mapper.Map(unordinaryPerson.BirthPlace), + DeathPlace = _mapper.Map(unordinaryPerson.DeathPlace), + }; + } + + public async Task DeleteAsync(int id) + { + var unordinaryPerson = await _dbContext.Set().FindAsync(id); + if (unordinaryPerson == null) + return false; + + _dbContext.Set().Remove(unordinaryPerson); + await _dbContext.SaveChangesAsync(); + return true; + } +} diff --git a/backend/Services/WrittenSourceService.cs b/backend/Services/WrittenSourceService.cs new file mode 100644 index 0000000..7acd406 --- /dev/null +++ b/backend/Services/WrittenSourceService.cs @@ -0,0 +1,304 @@ +using Mappa.Db; +using Mappa.Dtos; +using Mappa.Entities; +using Microsoft.EntityFrameworkCore; +using AutoMapper; +using Microsoft.IdentityModel.Tokens; +using System.Threading.Tasks.Dataflow; + +namespace Mappa.Services; + +public class WrittenSourceService : IComplexEntityService +{ + private readonly AppDbContext _dbContext; + private readonly IMapper _mapper; + + public WrittenSourceService(AppDbContext dbContext, IMapper mapper) + { + _dbContext = dbContext; + _mapper = mapper; + } + + public async Task> GetAllAsync() + { + return await _dbContext.Set() + .Include(ws => ws.Genre) + .Include(ws => ws.Language) + .Select(e => new WrittenSourceGeneralDto + { + Id = e.Id, + AlternateNames = e.AlternateNames, + Author = e.Author, + YearWritten = e.YearWritten, + Genre = _mapper.Map(e.Genre), + Language = _mapper.Map(e.Language) + }) + .ToListAsync(); + } + + public async Task GetByIdAsync(int id) + { + var entity = await _dbContext.Set() + .Include(ws => ws.Genre) + .Include(ws => ws.Language) + .Include(ws => ws.TranslatedLanguages) + .Include(ws => ws.CitiesMentioningTheSources) + .Include(ws => ws.CitiesWhereSourcesAreWritten) + .FirstOrDefaultAsync(ws => ws.Id == id); + + if (entity == null) + throw new ArgumentException($"Entity with ID {id} not found."); + + return new WrittenSourceDetailDto + { + Id = entity.Id, + AlternateNames = entity.AlternateNames, + Author = entity.Author, + YearWritten = entity.YearWritten, + Genre = _mapper.Map(entity.Genre), + Language = _mapper.Map(entity.Language), + KnownCopies = entity.KnownCopies, + SurvivedCopies = entity.SurvivedCopies, + LibraryInformation = entity.LibraryInformation, + OtherInformation = entity.OtherInformation, + RemarkableWorksOnTheBook = entity.RemarkableWorksOnTheBook, + Image = entity.Image, + TranslatedLanguages = _mapper.Map>(entity.TranslatedLanguages), + CitiesMentioningTheSources = _mapper.Map>(entity.CitiesMentioningTheSources), + CitiesWhereSourcesAreWritten = _mapper.Map>(entity.CitiesWhereSourcesAreWritten), + }; + } + + public async Task CreateAsync(WrittenSourceCreateRequest request) + { + if ((request.AlternateNames != null) && (request.AlternateNames.Count != 0) ) + throw new ArgumentException("Alternate names is not provided"); + + bool exists = await _dbContext.Set() + .AnyAsync(ws => ws.AlternateNames.Any(name => request.AlternateNames.Contains(name))); + + if (exists) + throw new ArgumentException("A written source with one or more of the provided alternate names already exists."); + + var writtenSource = new WrittenSource + { + AlternateNames = request.AlternateNames, + Author = request.Author, + YearWritten = request.YearWritten, + KnownCopies = request.KnownCopies, + SurvivedCopies = request.SurvivedCopies, + LibraryInformation = request.LibraryInformation, + OtherInformation = request.OtherInformation, + RemarkableWorksOnTheBook = request.RemarkableWorksOnTheBook, + Image = request.Image, + }; + + // Check if Genre exists + if(request.Genre != null) + { + var genre = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Genre ); + if (genre == null) + throw new ArgumentException($"Genre with name {request.Genre} not found."); + writtenSource.Genre = genre; + } + + // Check if Language exists + if(request.Language != null) + { + var language = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Language ); + if (language == null) + throw new ArgumentException($"Language with name {request.Language} not found."); + writtenSource.Language = language; + } + + // Update TranslatedLanguages (List of LanguageDto) + if (request.TranslatedLanguages != null) + { + var translatedLanguages = await _dbContext.Set() + .Where(l => request.TranslatedLanguages.Contains(l.Name)) + .ToListAsync(); + + if (translatedLanguages.Count != request.TranslatedLanguages.Count) + throw new ArgumentException("One or more provided Translated Language are invalid."); + writtenSource.TranslatedLanguages = translatedLanguages; + } + + // Update CitiesMentioningTheSources (List of CityBaseDto) + if (request.CitiesMentioningTheSources != null) + { + var mentionedCities = await _dbContext.Set() + .Where(c => request.CitiesMentioningTheSources.Contains(c.AsciiName)) + .ToListAsync(); + + if (mentionedCities.Count != request.CitiesMentioningTheSources.Count) + throw new ArgumentException("One or more provided CitiesMentioningTheSources are invalid."); + writtenSource.CitiesMentioningTheSources = mentionedCities; + } + + // Update CitiesWhereSourcesAreWritten (List of CityBaseDto) + if (request.CitiesWhereSourcesAreWritten != null) + { + var writtenCities = await _dbContext.Set() + .Where(c => request.CitiesWhereSourcesAreWritten.Contains(c.AsciiName)) + .ToListAsync(); + + if (writtenCities.Count != request.CitiesWhereSourcesAreWritten.Count) + throw new ArgumentException("One or more provided CitiesWhereSourcesAreWritten IDs are invalid."); + writtenSource.CitiesWhereSourcesAreWritten = writtenCities; + } + + _dbContext.Set().Add(writtenSource); + await _dbContext.SaveChangesAsync(); + + return new WrittenSourceDetailDto + { + Id = writtenSource.Id, + AlternateNames = writtenSource.AlternateNames, + Author = writtenSource.Author, + YearWritten = writtenSource.YearWritten, + Genre = _mapper.Map(writtenSource.Genre), + Language = _mapper.Map(writtenSource.Language), + KnownCopies = writtenSource.KnownCopies, + SurvivedCopies = writtenSource.SurvivedCopies, + LibraryInformation = writtenSource.LibraryInformation, + OtherInformation = writtenSource.OtherInformation, + RemarkableWorksOnTheBook = writtenSource.RemarkableWorksOnTheBook, + Image = writtenSource.Image, + TranslatedLanguages = _mapper.Map>(writtenSource.TranslatedLanguages), + CitiesMentioningTheSources = _mapper.Map>(writtenSource.CitiesMentioningTheSources), + CitiesWhereSourcesAreWritten = _mapper.Map>(writtenSource.CitiesWhereSourcesAreWritten) + }; + } + + public async Task UpdateAsync(int id, WrittenSourceUpdateRequest request) + { + var writtenSource = await _dbContext.Set() + .Include(ws => ws.Genre) + .Include(ws => ws.Language) + .Include(ws => ws.TranslatedLanguages) + .Include(ws => ws.CitiesMentioningTheSources) + .Include(ws => ws.CitiesWhereSourcesAreWritten) + .FirstOrDefaultAsync(ws => ws.Id == id); + + if (writtenSource == null) + throw new ArgumentException($"Entity with ID {id} not found."); + + // Only update fields if they are not null + if (request.AlternateNames != null) + writtenSource.AlternateNames = request.AlternateNames; + + if (request.Author != null) + writtenSource.Author = request.Author; + + if ((request.YearWritten != null) && (request.YearWritten.Count != 0) ) + writtenSource.YearWritten = request.YearWritten; + + // Genre update only if a valid genre is provided + if (request.Genre != null) + { + var genre = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Genre); + if (genre == null) + throw new ArgumentException($"Genre with name {request.Genre} not found."); + writtenSource.Genre = genre; + } + + // Language update only if a valid language is provided + if (request.Language != null) + { + var language = await _dbContext.Set().FirstOrDefaultAsync(e => e.Name == request.Language); + if (language == null) + throw new ArgumentException($"Language with name {request.Language} not found."); + writtenSource.Language = language; + } + + // Only update fields if they are provided in the request + if (request.KnownCopies != null) + writtenSource.KnownCopies = request.KnownCopies; + + if (request.SurvivedCopies != null) + writtenSource.SurvivedCopies = request.SurvivedCopies; + + if (request.LibraryInformation != null) + writtenSource.LibraryInformation = request.LibraryInformation; + + if (request.OtherInformation != null) + writtenSource.OtherInformation = request.OtherInformation; + + if (request.RemarkableWorksOnTheBook != null) + writtenSource.RemarkableWorksOnTheBook = request.RemarkableWorksOnTheBook; + + if (request.Image != null) + writtenSource.Image = request.Image; + + // Update TranslatedLanguages (List of LanguageDto) + if (request.TranslatedLanguages != null) + { + var translatedLanguages = await _dbContext.Set() + .Where(l => request.TranslatedLanguages.Contains(l.Name)) + .ToListAsync(); + + if (translatedLanguages.Count != request.TranslatedLanguages.Count) + throw new ArgumentException("One or more provided Translated Languages are invalid."); + + writtenSource.TranslatedLanguages = translatedLanguages; + } + + // Update CitiesMentioningTheSources (List of CityBaseDto) + if (request.CitiesMentioningTheSources != null) + { + var mentionedCities = await _dbContext.Set() + .Where(c => request.CitiesMentioningTheSources.Contains(c.AsciiName)) + .ToListAsync(); + + if (mentionedCities.Count != request.CitiesMentioningTheSources.Count) + throw new ArgumentException("One or more provided CitiesMentioningTheSources are invalid."); + + writtenSource.CitiesMentioningTheSources = mentionedCities; + } + + // Update CitiesWhereSourcesAreWritten (List of CityBaseDto) + if (request.CitiesWhereSourcesAreWritten != null) + { + var writtenCities = await _dbContext.Set() + .Where(c => request.CitiesWhereSourcesAreWritten.Contains(c.AsciiName)) + .ToListAsync(); + + if (writtenCities.Count != request.CitiesWhereSourcesAreWritten.Count) + throw new ArgumentException("One or more provided CitiesWhereSourcesAreWritten are invalid."); + + writtenSource.CitiesWhereSourcesAreWritten = writtenCities; + } + + await _dbContext.SaveChangesAsync(); + + return new WrittenSourceDetailDto + { + Id = writtenSource.Id, + AlternateNames = writtenSource.AlternateNames, + Author = writtenSource.Author, + YearWritten = writtenSource.YearWritten, + Genre = _mapper.Map(writtenSource.Genre), + Language = _mapper.Map(writtenSource.Language), + KnownCopies = writtenSource.KnownCopies, + SurvivedCopies = writtenSource.SurvivedCopies, + LibraryInformation = writtenSource.LibraryInformation, + OtherInformation = writtenSource.OtherInformation, + RemarkableWorksOnTheBook = writtenSource.RemarkableWorksOnTheBook, + Image = writtenSource.Image, + TranslatedLanguages = _mapper.Map>(writtenSource.TranslatedLanguages), + CitiesMentioningTheSources = _mapper.Map>(writtenSource.CitiesMentioningTheSources), + CitiesWhereSourcesAreWritten = _mapper.Map>(writtenSource.CitiesWhereSourcesAreWritten) + }; + } + + public async Task DeleteAsync(int id) + { + var writtenSource = await _dbContext.Set().FindAsync(id); + if (writtenSource == null) + return false; + + _dbContext.Set().Remove(writtenSource); + await _dbContext.SaveChangesAsync(); + return true; + } +} diff --git a/backend/example.appsettings.Development.json b/backend/example.appsettings.Development.json new file mode 100644 index 0000000..b7ca0bb --- /dev/null +++ b/backend/example.appsettings.Development.json @@ -0,0 +1,18 @@ +{ + "Logging": { + "LogLevel": { + "Microsoft.AspNetCore.Authentication": "Debug", + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "db": "Host=;Port=;Database=;Username=;Password=" + }, + "JWT": { + "ValidAudience": "http://:", + "ValidIssuer": "http://:", + "Secret": "", + "TokenExpirationInHours": 3 + } +} \ No newline at end of file diff --git a/backend/example.appsettings.json b/backend/example.appsettings.json new file mode 100644 index 0000000..15bb8a3 --- /dev/null +++ b/backend/example.appsettings.json @@ -0,0 +1,18 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "ConnectionStrings": { + "db": "Host=;Port=;Database=;Username=;Password=" + }, + "AllowedHosts": "*", + "JWT": { + "ValidAudience": "http://:", + "ValidIssuer": "http://:", + "Secret": "", + "TokenExpirationInHours": 3 + } +} diff --git a/backend/mappa.csproj b/backend/mappa.csproj index 803c0af..e9e035b 100644 --- a/backend/mappa.csproj +++ b/backend/mappa.csproj @@ -7,6 +7,7 @@ + @@ -20,6 +21,7 @@ + diff --git a/compose.yml b/compose.yml index 2b49d5f..c4c4c71 100644 --- a/compose.yml +++ b/compose.yml @@ -1,22 +1,33 @@ services: web_api: container_name: mappa_backend - build: ./backend + build: + context: ./backend + args: + DATABASE_CONNECTION_STRING: ${DATABASE_CONNECTION_STRING} ports: - 8080:8080 depends_on: - - "db" + db: + condition: service_healthy + # environment: + # DATABASE_CONNECTION_STRING: ${DATABASE_CONNECTION_STRING} db: image: postgres container_name: mappa_db ports: - 5433:5432 environment: - - POSTGRES_DB=MappaDB - - POSTGRES_USER=postgres - - POSTGRES_PASSWORD=formatlatan123. + POSTGRES_DB: ${POSTGRES_DB} + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres -d MappaDB"] + interval: 5s + retries: 15 + timeout: 3s volumes: postgres_data: diff --git a/example.env b/example.env new file mode 100644 index 0000000..6416f27 --- /dev/null +++ b/example.env @@ -0,0 +1,4 @@ +POSTGRES_PASSWORD= +POSTGRES_DB= +POSTGRES_USER= +DATABASE_CONNECTION_STRING="Host=;Port=;Database=;Username=;Password=" \ No newline at end of file