From fa0448bef6a099a1c53247d219df9b499c6db02a Mon Sep 17 00:00:00 2001 From: mborzyszkowski Date: Wed, 23 Sep 2020 09:18:54 +0200 Subject: [PATCH 1/2] New DbContext and crud for companies --- .../Controllers/CompaniesController.cs | 187 +++++++++++++++++- .../Queries/BranchOfficeForm.cs | 6 +- .../Queries/CompanyForm.cs | 2 +- src/InternshipSystem.Api/Startup.cs | 4 +- src/InternshipSystem.Core/Entity/Edition.cs | 6 - .../Entity/Internship/Internship.cs | 2 +- .../InternshipDbContextFactory.cs | 6 +- .../InternshipPractiseSupervisorDbContext.cs | 12 ++ ...nshipPractiseSupervisorDbContextFactory.cs | 16 ++ 9 files changed, 224 insertions(+), 17 deletions(-) create mode 100644 src/InternshipSystem.Repository/InternshipPractiseSupervisorDbContext.cs create mode 100644 src/InternshipSystem.Repository/InternshipPractiseSupervisorDbContextFactory.cs diff --git a/src/InternshipSystem.Api/Controllers/CompaniesController.cs b/src/InternshipSystem.Api/Controllers/CompaniesController.cs index b23aaef..39011e6 100644 --- a/src/InternshipSystem.Api/Controllers/CompaniesController.cs +++ b/src/InternshipSystem.Api/Controllers/CompaniesController.cs @@ -8,6 +8,7 @@ using InternshipSystem.Repository; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; +using static System.String; namespace InternshipSystem.Api.Controllers { @@ -15,16 +16,21 @@ namespace InternshipSystem.Api.Controllers [Route("companies")] public class CompaniesController : ControllerBase { - public CompaniesController(InternshipDbContext context) + public CompaniesController(InternshipDbContext context, InternshipPractiseSupervisorDbContext practiseSupervisorDbContext) { Context = context; + PractiseSupervisorDbContext = practiseSupervisorDbContext; } + private InternshipDbContext Context { get; } + private InternshipPractiseSupervisorDbContext PractiseSupervisorDbContext { get; } /// /// Get companies matching provided paginated query /// /// Paginated query description + /// Successfully retrieved Companies + /// Search query was malformed /// Part of companies collection [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] @@ -60,6 +66,183 @@ namespace InternshipSystem.Api.Controllers .Take(searchQuery.PerPage) .ToListAsync(token); } - } + /// + /// Updates or add new company (if not new than contains id) + /// + /// + /// Successfully updated company + /// Company form was malformed + /// Company not found + /// + [HttpPut] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task UpdateCompany([FromBody] CompanyForm companyForm, CancellationToken cancellationToken) + { + var validator = new CompanyForm.Validator(); + var validationResult = await validator.ValidateAsync(companyForm, cancellationToken); + + if (!validationResult.IsValid) + { + return BadRequest(validationResult.ToString()); + } + + if (companyForm.Id.HasValue) + { + var companyToUpdate = await PractiseSupervisorDbContext.Companies.FindAsync(companyForm.Id); + + if (companyToUpdate != null) + { + companyToUpdate.Name = IsNullOrEmpty(companyForm.Name) ? companyToUpdate.Name : companyForm.Name; + companyToUpdate.Nip = IsNullOrEmpty(companyForm.Nip) ? companyToUpdate.Nip : companyForm.Nip; + } + else + { + return NotFound($"Company with id: {companyForm.Id} does not exist"); + } + } + else + { + var newCompany = new Company + { + Name = companyForm.Name, + Nip = companyForm.Nip, + }; + await PractiseSupervisorDbContext.Companies.AddAsync(newCompany, cancellationToken); + } + + await PractiseSupervisorDbContext.SaveChangesAsync(cancellationToken); + return Ok($"Company updated successfully"); + } + + /// + /// Deletes existing company by id + /// + /// + /// Successfully deleted company + /// Company id is empty + /// Company not found + /// + [HttpDelete("{companyId}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteCompany(long companyId, CancellationToken cancellationToken) + { + var companyToDelete = await PractiseSupervisorDbContext.Companies + .Include(c => c.Branches) + .FirstOrDefaultAsync(c => c.Id.Equals(companyId), cancellationToken: cancellationToken); + + if (companyToDelete == null) + { + return NotFound($"Company with id: {companyId} does not exist"); + } + + PractiseSupervisorDbContext.Companies.Attach(companyToDelete); + PractiseSupervisorDbContext.Companies.Remove(companyToDelete); + await PractiseSupervisorDbContext.SaveChangesAsync(cancellationToken); + return Ok($"Company with id: {companyId} deleted successfully"); + } + + /// + /// Updates or add new branchOffice (if not new than contains id) + /// + /// + /// + /// Successfully updated company branch office + /// Branch office was malformed/response> + /// Company or branch office not found + /// + [HttpPut("branchOffice/{companyId}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task UpdateBranch([FromBody] BranchOfficeForm branchOfficeForm, long companyId, CancellationToken cancellationToken) + { + var validator = new BranchOfficeForm.Validator(); + var validationResult = await validator.ValidateAsync(branchOfficeForm, cancellationToken); + + if (!validationResult.IsValid) + { + return BadRequest(validationResult.ToString()); + } + + var company = await PractiseSupervisorDbContext.Companies + .Include(c => c.Branches) + .FirstOrDefaultAsync(c => c.Id.Equals(companyId), cancellationToken: cancellationToken); + + if (company == null) + { + return NotFound($"Company with id: {companyId} does not exist"); + } + + if (branchOfficeForm.Id.HasValue) + { + var branchOffice = company.Branches.Find(b => b.Id.Equals(branchOfficeForm.Id.Value)); + + if (branchOffice == null) + { + return NotFound($"Branch office with id: {branchOfficeForm.Id} does not exist"); + } + + branchOffice.Address.Country = IsNullOrEmpty(branchOfficeForm.Country) ? branchOffice.Address.Country : branchOfficeForm.Country; + branchOffice.Address.City = IsNullOrEmpty(branchOfficeForm.City) ? branchOffice.Address.City : branchOfficeForm.City; + branchOffice.Address.PostalCode = IsNullOrEmpty(branchOfficeForm.PostalCode) ? branchOffice.Address.PostalCode : branchOfficeForm.PostalCode; + branchOffice.Address.Street = IsNullOrEmpty(branchOfficeForm.Street) ? branchOffice.Address.Street : branchOfficeForm.Street; + branchOffice.Address.Building = IsNullOrEmpty(branchOfficeForm.Building) ? branchOffice.Address.Building : branchOfficeForm.Building; + } + else + { + var newBranchOffice = new BranchOffice + { + Address = new BranchAddress + { + Country = branchOfficeForm.Country, + City = branchOfficeForm.City, + PostalCode = branchOfficeForm.PostalCode, + Street = branchOfficeForm.Street, + Building = branchOfficeForm.Building, + } + }; + company.Branches.Add(newBranchOffice); + } + + await PractiseSupervisorDbContext.SaveChangesAsync(cancellationToken); + return Ok($"Branch office updated successfully"); + } + + /// + /// Deletes existing branchOffice + /// + /// + /// Successfully deleted company branch office + /// Branch office id is empty + /// Company or branch office not found + /// + [HttpDelete("branchOffice/{branchOfficeId}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task DeleteBranch(long branchOfficeId, CancellationToken cancellationToken) + { + var company = + await PractiseSupervisorDbContext.Companies + .Include(c => c.Branches) + .Where(c => c.Branches.Any(b => b.Id.Equals(branchOfficeId))) + .FirstOrDefaultAsync(cancellationToken: cancellationToken); + + if (company == null) + { + return NotFound($"Branch office with id: {branchOfficeId} does not exist"); + } + + var branchOffice = company.Branches.Find(b => b.Id.Equals(branchOfficeId)); + company.Branches.Remove(branchOffice); + + await PractiseSupervisorDbContext.SaveChangesAsync(cancellationToken); + return Ok($"Branch office with id: {branchOfficeId} deleted successfully"); + } + } } \ No newline at end of file diff --git a/src/InternshipSystem.Api/Queries/BranchOfficeForm.cs b/src/InternshipSystem.Api/Queries/BranchOfficeForm.cs index 5fbbafc..75219d5 100644 --- a/src/InternshipSystem.Api/Queries/BranchOfficeForm.cs +++ b/src/InternshipSystem.Api/Queries/BranchOfficeForm.cs @@ -17,9 +17,9 @@ namespace InternshipSystem.Api.Queries { RuleFor(b => b.Id).NotNull() .When(c => - !string.IsNullOrEmpty(c.Country) || !string.IsNullOrEmpty(c.City) || - !string.IsNullOrEmpty(c.PostalCode) || !string.IsNullOrEmpty(c.Street) || - !string.IsNullOrEmpty(c.Building)); + string.IsNullOrEmpty(c.Country) || string.IsNullOrEmpty(c.City) || + string.IsNullOrEmpty(c.PostalCode) || string.IsNullOrEmpty(c.Street) || + string.IsNullOrEmpty(c.Building)); RuleFor(b => b.Country).NotNull() .When(b => !b.Id.HasValue); RuleFor(b => b.City).NotNull() diff --git a/src/InternshipSystem.Api/Queries/CompanyForm.cs b/src/InternshipSystem.Api/Queries/CompanyForm.cs index 330a8f5..86fbfff 100644 --- a/src/InternshipSystem.Api/Queries/CompanyForm.cs +++ b/src/InternshipSystem.Api/Queries/CompanyForm.cs @@ -13,7 +13,7 @@ namespace InternshipSystem.Api.Queries public Validator() { RuleFor(c => c.Id).NotNull() - .When(c => !string.IsNullOrEmpty(c.Nip) || !string.IsNullOrEmpty(c.Name)); + .When(c => string.IsNullOrEmpty(c.Nip) || string.IsNullOrEmpty(c.Name)); RuleFor(c => c.Nip).NotEmpty() .When(c => !c.Id.HasValue); RuleFor(c => c.Name).NotEmpty() diff --git a/src/InternshipSystem.Api/Startup.cs b/src/InternshipSystem.Api/Startup.cs index ccdc27d..4757557 100644 --- a/src/InternshipSystem.Api/Startup.cs +++ b/src/InternshipSystem.Api/Startup.cs @@ -43,11 +43,13 @@ namespace InternshipSystem.Api services .AddDbContext(o => o.UseNpgsql(Configuration.GetConnectionString("InternshipDatabase"))) + .AddDbContext(o => + o.UseNpgsql(Configuration.GetConnectionString("InternshipDatabase"))) .AddScoped() .AddScoped() .AddScoped() .AddAutoMapper(cfg => cfg.AddProfile()); - + services .AddSwaggerGen(options => { diff --git a/src/InternshipSystem.Core/Entity/Edition.cs b/src/InternshipSystem.Core/Entity/Edition.cs index b6fa3cd..e2e79fb 100644 --- a/src/InternshipSystem.Core/Entity/Edition.cs +++ b/src/InternshipSystem.Core/Entity/Edition.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using InternshipSystem.Core.Entity.Internship; using InternshipSystem.Core.UglyOrmArtifacts; @@ -48,10 +47,5 @@ namespace InternshipSystem.Core { return start >= EditionStart && end <= EditionFinish; } - - public bool IsInternshiptypeAllowed(InternshipType internshipType) - { - return AllowedInternshipTypes.HasFlag(internshipType); - } } } \ No newline at end of file diff --git a/src/InternshipSystem.Core/Entity/Internship/Internship.cs b/src/InternshipSystem.Core/Entity/Internship/Internship.cs index 965835b..be8d8a6 100644 --- a/src/InternshipSystem.Core/Entity/Internship/Internship.cs +++ b/src/InternshipSystem.Core/Entity/Internship/Internship.cs @@ -64,7 +64,7 @@ namespace InternshipSystem.Core var internshipType = updateRegistration.Type ?? InternshipRegistration.Type; - if (!Edition.IsInternshiptypeAllowed(internshipType)) + if (!Edition.IsInternshipTypeAllowed(internshipType)) { throw new ArgumentException("Internship type not allowed for this edition", nameof(updateRegistration.Type)); } diff --git a/src/InternshipSystem.Repository/InternshipDbContextFactory.cs b/src/InternshipSystem.Repository/InternshipDbContextFactory.cs index 6292291..e52d20e 100644 --- a/src/InternshipSystem.Repository/InternshipDbContextFactory.cs +++ b/src/InternshipSystem.Repository/InternshipDbContextFactory.cs @@ -9,10 +9,10 @@ namespace InternshipSystem.Repository { public InternshipDbContext CreateDbContext(string[] args) { - var optionsBulider = new DbContextOptionsBuilder(); - optionsBulider.UseNpgsql("Host=localhost;Port=5432;Database=postgres;Username=postgres;Password=szwoniu"); + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Database=postgres;Username=postgres;Password=szwoniu"); - return new InternshipDbContext(optionsBulider.Options); + return new InternshipDbContext(optionsBuilder.Options); } } } \ No newline at end of file diff --git a/src/InternshipSystem.Repository/InternshipPractiseSupervisorDbContext.cs b/src/InternshipSystem.Repository/InternshipPractiseSupervisorDbContext.cs new file mode 100644 index 0000000..d7e66bb --- /dev/null +++ b/src/InternshipSystem.Repository/InternshipPractiseSupervisorDbContext.cs @@ -0,0 +1,12 @@ +using InternshipSystem.Core; +using Microsoft.EntityFrameworkCore; + +namespace InternshipSystem.Repository +{ + public class InternshipPractiseSupervisorDbContext : InternshipDbContext + { + public InternshipPractiseSupervisorDbContext(DbContextOptions options) : base(options) + { + } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Repository/InternshipPractiseSupervisorDbContextFactory.cs b/src/InternshipSystem.Repository/InternshipPractiseSupervisorDbContextFactory.cs new file mode 100644 index 0000000..57b3a2b --- /dev/null +++ b/src/InternshipSystem.Repository/InternshipPractiseSupervisorDbContextFactory.cs @@ -0,0 +1,16 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; + +namespace InternshipSystem.Repository +{ + public class InternshipPractiseSupervisorDbContextFactory : IDesignTimeDbContextFactory + { + public InternshipPractiseSupervisorDbContext CreateDbContext(string[] args) + { + var optionsBuilder = new DbContextOptionsBuilder(); + optionsBuilder.UseNpgsql("Host=localhost;Port=5432;Database=postgres;Username=postgres;Password=szwoniu"); + + return new InternshipPractiseSupervisorDbContext(optionsBuilder.Options); + } + } +} \ No newline at end of file -- 2.45.2 From da052c19aa675fdf9042996f99456315b427f87f Mon Sep 17 00:00:00 2001 From: mborzyszkowski Date: Wed, 23 Sep 2020 12:38:44 +0200 Subject: [PATCH 2/2] Student update current data and get current data --- .../Controllers/AccessController.cs | 6 +- .../Controllers/StudentController.cs | 56 +++++++++++++++++++ .../Queries/StudentForm.cs | 24 ++++++++ src/InternshipSystem.Core/Entity/Student.cs | 2 + 4 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 src/InternshipSystem.Api/Controllers/StudentController.cs create mode 100644 src/InternshipSystem.Api/Queries/StudentForm.cs diff --git a/src/InternshipSystem.Api/Controllers/AccessController.cs b/src/InternshipSystem.Api/Controllers/AccessController.cs index 69164e3..0109e48 100644 --- a/src/InternshipSystem.Api/Controllers/AccessController.cs +++ b/src/InternshipSystem.Api/Controllers/AccessController.cs @@ -4,7 +4,9 @@ using System.Linq; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; +using FluentValidation; using InternshipSystem.Api.Options; +using InternshipSystem.Api.Queries; using InternshipSystem.Api.Security; using InternshipSystem.Core; using InternshipSystem.Repository; @@ -50,7 +52,7 @@ namespace InternshipSystem.Api.Controllers return BadRequest(); } - var student = await _context.Students.FirstOrDefaultAsync(s => s.Id == id); + var student = await _context.Students.FirstOrDefaultAsync(s => s.Id == id, cancellationToken: cancellationToken); if (student == null) { @@ -104,7 +106,7 @@ namespace InternshipSystem.Api.Controllers return Ok(_tokenService.generateToken(newIdentity)); } - + private Student CreateStudentWithCasData(CasUserData casData) { var id = long.Parse(casData.PersonNumber); diff --git a/src/InternshipSystem.Api/Controllers/StudentController.cs b/src/InternshipSystem.Api/Controllers/StudentController.cs new file mode 100644 index 0000000..165dc6f --- /dev/null +++ b/src/InternshipSystem.Api/Controllers/StudentController.cs @@ -0,0 +1,56 @@ +using System.Threading; +using System.Threading.Tasks; +using InternshipSystem.Api.Queries; +using InternshipSystem.Api.Security; +using InternshipSystem.Core; +using InternshipSystem.Repository; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace InternshipSystem.Api.Controllers +{ + [Route("student")] + [ApiController] + public class StudentController : ControllerBase + { + private readonly InternshipDbContext _context; + + public StudentController(InternshipDbContext context) + { + _context = context; + } + + [HttpGet("current")] + [Authorize] + public async Task GetCurrentStudentData([FromServices] User user, CancellationToken cancellationToken) + { + return await _context.Students.FindAsync(user.PersonNumber); + } + + [HttpPut("updateCurrent")] + [Authorize] + public async Task UpdateStudentData([FromBody] StudentForm studentNewData, [FromServices] User user, CancellationToken cancellationToken) + { + var validator = new StudentForm.Validator(); + var validationResult = await validator.ValidateAsync(studentNewData, cancellationToken); + + if (!validationResult.IsValid || !user.PersonNumber.Equals(studentNewData.Id)) + { + return BadRequest(); + } + + var currentStudent = await _context.Students.FindAsync(user.PersonNumber); + + currentStudent.AlbumNumber = studentNewData.AlbumNumber ?? currentStudent.AlbumNumber; + currentStudent.FirstName = string.IsNullOrEmpty(studentNewData.FirstName) ? currentStudent.FirstName : studentNewData.FirstName; + currentStudent.LastName = string.IsNullOrEmpty(studentNewData.LastName) ? currentStudent.LastName : studentNewData.LastName; + currentStudent.Email = string.IsNullOrEmpty(studentNewData.Email) ? currentStudent.Email : studentNewData.Email; + currentStudent.Course = string.IsNullOrEmpty(studentNewData.Course) ? currentStudent.Course : studentNewData.Course; + currentStudent.Semester = studentNewData.Semester ?? currentStudent.Semester; + + await _context.SaveChangesAsync(cancellationToken); + + return Ok(); + } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Queries/StudentForm.cs b/src/InternshipSystem.Api/Queries/StudentForm.cs new file mode 100644 index 0000000..d9ab467 --- /dev/null +++ b/src/InternshipSystem.Api/Queries/StudentForm.cs @@ -0,0 +1,24 @@ +using FluentValidation; +using InternshipSystem.Core; + +namespace InternshipSystem.Api.Queries +{ + public class StudentForm + { + public long? Id { get; set; } + public int? AlbumNumber { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + public string Email { get; set; } + public string Course { get; set; } + public int? Semester { get; set; } + + public class Validator : AbstractValidator + { + public Validator() + { + RuleFor(c => c.Id).NotNull(); + } + } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Core/Entity/Student.cs b/src/InternshipSystem.Core/Entity/Student.cs index 04b7f1b..2ff5a39 100644 --- a/src/InternshipSystem.Core/Entity/Student.cs +++ b/src/InternshipSystem.Core/Entity/Student.cs @@ -9,6 +9,8 @@ namespace InternshipSystem.Core public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } + public string Course { get; set; } + public int? Semester { get; set; } public static Student CreateStudent(long id, string firstName, string lastName, string email, in int albumNumber) { -- 2.45.2