doroboty #53

Closed
maxchil wants to merge 4 commits from doroboty into master
16 changed files with 347 additions and 182 deletions
Showing only changes of commit 59840ffd5c - Show all commits

View File

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using IdentityServer4.Extensions;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity.Internship;
namespace InternshipSystem.Api.Commands
{
public class UpdateRegistrationForm
{
public UpdateCompany? Company { get; set; }
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
public UpdateMentor? Mentor { get; set; }
public List<Internship> Subjects { get; set; }
public InternshipType Type { get; set; }
}
public struct UpdateMentor
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
}
public struct UpdateCompany
{
public long? Id { get; set; }
public string Nip { get; set; }
public string Name { get; set; }
public UpdateBranchOffice? BranchOffice { get; set; }
public bool IsCustomUpdate => !Nip.IsNullOrEmpty() || !Name.IsNullOrEmpty();
}
public struct UpdateBranchOffice
{
public long? Id { get; set; }
public string Street { get; set; }
public string Building { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public bool IsCustomUpdate => !string.IsNullOrEmpty(Street) ||
!string.IsNullOrEmpty(Building) ||
!string.IsNullOrEmpty(City) ||
!string.IsNullOrEmpty(PostalCode) ||
!string.IsNullOrEmpty(Country);
}
}

View File

@ -1,13 +1,11 @@
using System.Threading;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Queries;
using InternshipSystem.Api.Commands;
using InternshipSystem.Api.Security;
using InternshipSystem.Core.Commands;
using InternshipSystem.Api.UseCases;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using InternshipSystem.Api.Security;
using InternshipSystem.Api.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
@ -17,17 +15,16 @@ namespace InternshipSystem.Api.Controllers
[Route("internshipRegistration")]
public class InternshipRegistrationController : ControllerBase
{
private readonly IInternshipService _internshipService;
private readonly InternshipDbContext _dbContext;
public InternshipRegistrationController(IInternshipService internshipService)
public InternshipRegistrationController(InternshipDbContext dbContext)
{
_internshipService = internshipService;
_dbContext = dbContext;
}
/// <summary>
/// Validate and add filled internship registration form
/// </summary>
/// <param name="updateRegistration">Internship registration data</param>
/// <response code="200">If registration form was successfully added</response>
/// <response code="400">If the provided registration query was malformed</response>
/// <response code="401">This action is only available for authorized student registered for current edition</response>
@ -35,19 +32,33 @@ namespace InternshipSystem.Api.Controllers
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize]
public async Task<ActionResult> SubmitRegistrationForm([FromBody] RegistrationFormQuery registrationQuery,
[FromServices] User user, CancellationToken cancellationToken)
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult> SubmitRegistrationForm(
UpdateRegistrationForm registrationCommand,
[FromServices] User user,
CancellationToken cancellationToken)
{
var validator = new RegistrationFormQuery.Validator();
var validationResult = await validator.ValidateAsync(registrationQuery, cancellationToken);
var edition = await _dbContext.Editions.FirstAsync(e => e.Id == user.EditionId, cancellationToken);
if (!validationResult.IsValid)
{
return BadRequest(validationResult.ToString());
}
var internshipRegistration =
await _dbContext
.Entry(edition)
.Collection(e => e.Internships)
.Query()
.Where(i => i.Student.Id == user.PersonNumber)
.Select(i => i.InternshipRegistration)
.Include(r => r.BranchAddress)
.Include(r => r.Company)
.ThenInclude(c => c.Branches)
.FirstAsync(cancellationToken);
return await _internshipService.SubmitRegistration(registrationQuery, user.PersonNumber, cancellationToken);
var useCase = new UpdateInternshipRegistrationUseCase(_dbContext, internshipRegistration, edition, user);
var result = await useCase.UpdateInternshipRegistration(registrationCommand, cancellationToken);
await _dbContext.SaveChangesAsync(cancellationToken);
return Ok(result);
}
}
}

View File

@ -7,9 +7,6 @@ namespace InternshipSystem.Api.Services
{
public interface IInternshipService
{
Task<ActionResult> SubmitRegistration(RegistrationFormQuery registrationQuery, long personNumber,
CancellationToken cancellationToken);
Task<ActionResult> AddDocumentToInternship(DocumentPublishRequest documentRequest, long personNumber,
CancellationToken cancellationToken);
}

View File

@ -21,63 +21,6 @@ namespace InternshipSystem.Api.Services
Mapper = mapper;
}
public async Task<ActionResult> SubmitRegistration(RegistrationFormQuery registrationQuery, long personNumber,
CancellationToken cancellationToken)
{
var edition = await _context.Editions.FindAsync(personNumber);
var internship = await _context.Entry(edition)
.Collection(e => e.Internships)
.Query()
.SingleAsync(i => i.Student.Id == personNumber, cancellationToken);
var internshipRegistration = internship.InternshipRegistration;
if (registrationQuery.Company != null)
{
var company = registrationQuery.Company.Id.HasValue
? await _context.Companies.SingleAsync(c => c.Id == registrationQuery.Company.Id,
cancellationToken: cancellationToken)
: Company.CreateCompany(registrationQuery.Company.Nip, registrationQuery.Company.Name);
internshipRegistration.UpdateCompany(company);
}
var officeForm = registrationQuery.BranchOffice;
if (officeForm != null)
{
BranchOffice branch;
if (officeForm.Id.HasValue)
{
branch = await _context.Entry(internshipRegistration.Company)
.Collection(c => c.Branches)
.Query()
.SingleAsync(o => o.Id == officeForm.Id, cancellationToken: cancellationToken);
}
else
{
branch = BranchOffice.CreateBranch(officeForm.Country, officeForm.City, officeForm.PostalCode,
officeForm.Street, officeForm.Building);
internshipRegistration.Company.AddBranchOffice(branch);
}
internshipRegistration.UpdateBranch(branch);
}
internshipRegistration.Start = registrationQuery.Start ?? internshipRegistration.Start;
internshipRegistration.End = registrationQuery.End ?? internshipRegistration.End;
if (registrationQuery.Type != null && edition.IsInternshipTypeAllowed(registrationQuery.Type))
{
return new BadRequestObjectResult("Edition doesn't have this type of employment in available employments type");
}
internshipRegistration.Type = registrationQuery.Type ?? internshipRegistration.Type;
await _context.SaveChangesAsync(cancellationToken);
return new OkResult();
}
public async Task<ActionResult> AddDocumentToInternship(DocumentPublishRequest documentRequest, long personNumber,
CancellationToken cancellationToken)

View File

@ -0,0 +1,129 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using IdentityServer4.Extensions;
using InternshipSystem.Api.Commands;
using InternshipSystem.Api.Security;
using InternshipSystem.Core;
using InternshipSystem.Core.UglyOrmArtifacts;
using InternshipSystem.Repository;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.UseCases
{
public class UpdateInternshipRegistrationUseCase
{
private readonly InternshipDbContext _dbContext;
private readonly Edition _edition;
private readonly User _user;
private readonly InternshipRegistration subjectRegistration;
public UpdateInternshipRegistrationUseCase(InternshipDbContext dbContext,
InternshipRegistration internshipRegistration, Edition edition, User user)
{
_dbContext = dbContext;
_edition = edition;
_user = user;
subjectRegistration = internshipRegistration;
}
public async Task<string> UpdateInternshipRegistration(
UpdateRegistrationForm registrationCommand,
CancellationToken cancellationToken)
{
subjectRegistration.Start = registrationCommand.Start ?? subjectRegistration.Start;
subjectRegistration.End = registrationCommand.End ?? subjectRegistration.End;
subjectRegistration.Type = registrationCommand.Type ?? subjectRegistration.Type;
if (registrationCommand.Mentor.HasValue)
{
UpdateMentor(registrationCommand.Mentor.Value);
}
if (!registrationCommand.Subjects.IsNullOrEmpty())
{
UpdateSubjects(registrationCommand.Subjects);
}
if (registrationCommand.Company.HasValue)
{
await UpdateCompanyAndBranch(registrationCommand.Company.Value, cancellationToken);
}
return subjectRegistration.ValidateStatus(_edition);
}
private async Task UpdateCompanyAndBranch(UpdateCompany companyUpdate, CancellationToken cancellationToken)
{
var company = subjectRegistration.Company;
if (companyUpdate.Id.HasValue)
{
company = await _dbContext.Companies
.Include(c => c.Branches)
.FirstAsync(c => c.Id == companyUpdate.Id.Value, cancellationToken);
}
else if (companyUpdate.IsCustomUpdate)
{
company = await _dbContext.Companies
.Include(c => c.Branches)
.SingleOrDefaultAsync(c => c.Provider == _user.PersonNumber, cancellationToken)
?? Company.CreateCompany(companyUpdate.Nip, companyUpdate.Name, _user.PersonNumber);
company.Name = companyUpdate.Name ?? company.Name;
company.Nip = companyUpdate.Nip ?? company.Nip;
}
if (companyUpdate.BranchOffice.HasValue)
{
var branchUpdate = companyUpdate.BranchOffice.Value;
var branch = subjectRegistration.BranchAddress;
if (branchUpdate.Id.HasValue)
{
branch = company.Branches.First(b => b.Id == branchUpdate.Id.Value);
}
else if (branchUpdate.IsCustomUpdate)
{
branch = company.Branches.FirstOrDefault(b => b.Provider == _user.PersonNumber);
if (branch == null)
{
branch = BranchOffice.CreateBranch(branchUpdate.Country, branchUpdate.City, branchUpdate.PostalCode,
branchUpdate.Street, branchUpdate.Building, _user.PersonNumber);
company.AddBranchOffice(branch);
}
branch.Address.Country = branchUpdate.Country ?? branch.Address.Country;
branch.Address.City = branchUpdate.City ?? branch.Address.City;
branch.Address.PostalCode = branchUpdate.PostalCode ?? branch.Address.PostalCode;
branch.Address.Street = branchUpdate.Country ?? branch.Address.Street;
branch.Address.Building = branchUpdate.Building ?? branch.Address.Building;
}
subjectRegistration.BranchAddress = branch;
}
subjectRegistration.Company = company;
}
private void UpdateSubjects(IEnumerable<Internship> subjects)
{
subjectRegistration.Subjects =
subjects
.Select(i => new ProgramSubject
{
Registration = subjectRegistration,
InternshipSubjectId = i.Id
})
.ToList();
}
private void UpdateMentor(UpdateMentor mentorUpdate)
{
subjectRegistration.Mentor.UpdateInformation(mentorUpdate.FirstName, mentorUpdate.LastName, mentorUpdate.Email, mentorUpdate.PhoneNumber);
}
}
}

View File

@ -1,33 +0,0 @@
using System;
using InternshipSystem.Core.Entity.Internship;
namespace InternshipSystem.Core.Commands
{
public class UpdateRegistrationForm
{
public UpdateCompany? Company { get; set; }
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
public InternshipType? Type { get; set; }
}
public struct UpdateCompany
{
public long? Id { get; set; }
public string Nip { get; set; }
public string Name { get; set; }
public UpdateBranchOffice? BranchOffice { get; set; }
public bool IsUpdate => Id.HasValue;
}
public struct UpdateBranchOffice
{
public long? Id { get; set; }
public string Street { get; set; }
public string Building { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
}
}

View File

@ -1,20 +1,28 @@
namespace InternshipSystem.Core
using FluentValidation;
using FluentValidation.Validators;
namespace InternshipSystem.Core
{
public class BranchOffice
{
public BranchOffice()
{
}
private BranchOffice(BranchAddress address)
private BranchOffice(BranchAddress address, long provider)
{
Address = address;
Provider = provider;
}
public long Id { get; set; }
public BranchAddress Address { get; set; }
public static BranchOffice CreateBranch(string country, string city, string postalCode, string street, string building)
public long Provider { get; set; }
public static BranchOffice CreateBranch(string country, string city, string postalCode, string street,
string building, long provider = 0)
{
var address = new BranchAddress
{
@ -25,7 +33,16 @@
PostalCode = postalCode
};
return new BranchOffice(address);
return new BranchOffice(address, provider);
}
public class Validator : AbstractValidator<BranchOffice>
{
public Validator()
{
RuleFor(x => x.Address)
.SetValidator(new BranchAddress.Validator());
}
}
}
}

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using InternshipSystem.Core.Commands;
using FluentValidation;
using FluentValidation.Validators;
namespace InternshipSystem.Core
{
@ -11,25 +12,28 @@ namespace InternshipSystem.Core
public string Name { get; set; }
public List<BranchOffice> Branches { get; set; }
public static Company CreateCompany(string nip, string name) =>
public long Provider { get; set; }
public static Company CreateCompany(string nip, string name, long provider = 0) =>
new Company
{
Nip = nip,
Name = name
Name = name,
Provider = provider
};
public void AddBranchAddress(BranchAddress branch)
{
}
public void AddBranchOffice(BranchOffice createBranch)
{
Branches.Add(createBranch);
}
public static Company CreateCompany(UpdateCompany updateCompany)
public class Validator : AbstractValidator<Company>
{
throw new NotImplementedException();
public Validator()
{
RuleFor(x => x.Nip).NotNull();
RuleFor(x => x.Name).NotNull();
}
}
}
}

View File

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using InternshipSystem.Core.Commands;
using InternshipSystem.Core.ValueObject;
namespace InternshipSystem.Core
@ -51,38 +50,5 @@ namespace InternshipSystem.Core
return internship;
}
public void UpdateInternshipRegistration(UpdateRegistrationForm updateRegistration)
{
var start = updateRegistration.Start ?? InternshipRegistration.Start;
var end = updateRegistration.End ?? InternshipRegistration.End;
if (!Edition.IsDateDuringEdition(start, end))
{
throw new ArgumentOutOfRangeException(nameof(InternshipRegistration.Start) + nameof(InternshipRegistration.End),"Date outside of edition boundaries");
}
var internshipType = updateRegistration.Type ?? InternshipRegistration.Type;
if (!Edition.IsInternshipTypeAllowed(internshipType))
{
throw new ArgumentException("Internship type not allowed for this edition", nameof(updateRegistration.Type));
}
var company = InternshipRegistration.Company;
if (company == null)
{
if (!updateRegistration.Company.HasValue)
{
throw new ArgumentException("Company");
}
company = Company.CreateCompany(updateRegistration.Company.Value);
}
InternshipRegistration.Update(start, end, internshipType);
}
}
}

View File

@ -1,5 +1,9 @@
using System;
using System.Collections.Generic;
using FluentValidation;
using FluentValidation.Results;
using InternshipSystem.Core.Entity.Internship;
using InternshipSystem.Core.UglyOrmArtifacts;
namespace InternshipSystem.Core
{
@ -10,6 +14,8 @@ namespace InternshipSystem.Core
public BranchOffice BranchAddress { get; set; }
public DateTime Start { get; set; }
public DateTime End { get; set; }
public Mentor Mentor { get; set; }
public List<ProgramSubject> Subjects { get; set; }
public InternshipType Type { get; set; }
public DocumentState State { get; set; }
@ -18,21 +24,44 @@ namespace InternshipSystem.Core
return new InternshipRegistration();
}
public void Update(DateTime start, DateTime end, InternshipType internshipType)
public string ValidateStatus(Edition edition)
{
Start = start;
End = end;
Type = internshipType;
var validator = new Validator(edition);
var result = validator.Validate(this);
State = result.IsValid ? DocumentState.Submitted : DocumentState.Draft;
return result.ToString();
}
public void UpdateCompany(Company newCompany)
public class Validator : AbstractValidator<InternshipRegistration>
{
Company = newCompany;
public Validator(Edition edition)
{
RuleFor(x => x.Company)
.SetValidator(new Company.Validator())
.NotNull();
RuleFor(x => x.BranchAddress)
.SetValidator(new BranchOffice.Validator())
.NotNull();
RuleFor(x => x.Mentor)
.SetValidator(new Mentor.Validate())
.NotNull();
RuleFor(x => x.Subjects)
.NotEmpty();
RuleFor(x => x.Type)
.NotNull();
RuleFor(x => x.Start)
.GreaterThanOrEqualTo(edition.EditionStart)
.LessThan(x => x.End)
.NotEmpty();
RuleFor(x => x.End)
.LessThanOrEqualTo(edition.EditionFinish)
.GreaterThan(x => x.Start)
.NotEmpty();
}
public void UpdateBranch(BranchOffice branch)
{
BranchAddress = branch;
}
}
}

View File

@ -5,4 +5,8 @@
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="9.1.2" />
</ItemGroup>
</Project>

View File

@ -4,8 +4,8 @@ namespace InternshipSystem.Core.UglyOrmArtifacts
{
public class ProgramSubject
{
public long InternshipProgramId { get; set; }
public InternshipProgram Program { get; set; }
public long InternshipRegistrationId { get; set; }
public InternshipRegistration Registration { get; set; }
public long InternshipSubjectId { get; set; }
public InternshipSubject Subject { get; set; }
}

View File

@ -1,4 +1,7 @@
namespace InternshipSystem.Core
using FluentValidation;
using FluentValidation.Validators;
namespace InternshipSystem.Core
{
public class BranchAddress
{
@ -7,5 +10,22 @@
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public class Validator : AbstractValidator<BranchAddress>
{
public Validator()
{
RuleFor(x => x.Country)
.NotEmpty();
RuleFor(x => x.City)
.NotEmpty();
RuleFor(x => x.PostalCode)
.NotEmpty();
RuleFor(x => x.Street)
.NotEmpty();
RuleFor(x => x.Building)
.NotEmpty();
}
}
}
}

View File

@ -2,7 +2,7 @@
{
public enum DocumentState
{
NotSubmitted,
Draft,
Submitted,
Accepted,
Rejected

View File

@ -1,4 +1,6 @@
namespace InternshipSystem.Core
using FluentValidation;
namespace InternshipSystem.Core
{
public class Mentor
{
@ -6,5 +8,29 @@
public string LastName { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public void UpdateInformation(string firstName, string lastName, string email, string phoneNumber)
{
FirstName = firstName ?? FirstName;
LastName = lastName ?? LastName;
Email = email ?? Email;
PhoneNumber = phoneNumber ?? PhoneNumber;
}
public class Validate : AbstractValidator<Mentor>
{
public Validate()
{
RuleFor(x => x.FirstName)
.NotEmpty();
RuleFor(x => x.LastName)
.NotEmpty();
RuleFor(x => x.Email)
.NotEmpty();
RuleFor(x => x.PhoneNumber)
.NotEmpty();
}
}
}
}

View File

@ -33,12 +33,12 @@ namespace InternshipSystem.Repository
modelBuilder.Entity<ProgramSubject>(builder =>
{
builder
.HasKey(subject => new { subject.InternshipProgramId, subject.InternshipSubjectId });
.HasKey(subject => new { InternshipProgramId = subject.InternshipRegistrationId, subject.InternshipSubjectId });
builder
.HasOne(k => k.Program)
.WithMany(model => model.ChosenSubjects)
.HasForeignKey(subject => subject.InternshipProgramId);
.HasOne(k => k.Registration)
.WithMany(model => model.Subjects)
.HasForeignKey(subject => subject.InternshipRegistrationId);
builder
.HasOne(k => k.Subject)