diff --git a/PostmanTestRequest/StudentOperations.postman_collection.json b/PostmanTestRequest/StudentOperations.postman_collection.json new file mode 100644 index 0000000..e1829fa --- /dev/null +++ b/PostmanTestRequest/StudentOperations.postman_collection.json @@ -0,0 +1,424 @@ +{ + "info": { + "_postman_id": "f0858747-6271-4176-9193-ed1f9be0d7d3", + "name": "StudentOperations", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "loginDev", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/dev/login", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "dev", + "login" + ] + } + }, + "response": [] + }, + { + "name": "loginEdition", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTUyLCJleHAiOjE2MDEyODM5NTEsImlhdCI6MTYwMTE5NzU1Mn0.0wcNQSXV55MFvEnRLC09nGwCqI7M2kuWdwe0EOV_C6Y", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "\"138da8a3-855c-4b17-9bd2-5f357679efa9\"" + }, + "url": { + "raw": "http://localhost:8080/access/loginEdition", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "access", + "loginEdition" + ] + } + }, + "response": [] + }, + { + "name": "currentInternship", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://localhost:8080/internshipRegistration", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "internshipRegistration" + ] + } + }, + "response": [] + }, + { + "name": "GetEditionManagementList", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA0ODI3ODgzLCJleHAiOjE2MDQ5MTQyODMsImlhdCI6MTYwNDgyNzg4M30.a3mMm3Zk3xpfsmIwlqtpjgWgTNEXv8O4hH_V_L9UFZo", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "url": { + "raw": "http://localhost:8080/editionManagement", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "editionManagement" + ] + } + }, + "response": [] + }, + { + "name": "GetEditionManagement", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA0ODI3ODgzLCJleHAiOjE2MDQ5MTQyODMsImlhdCI6MTYwNDgyNzg4M30.a3mMm3Zk3xpfsmIwlqtpjgWgTNEXv8O4hH_V_L9UFZo", + "type": "string" + } + ] + }, + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "url": { + "raw": "http://localhost:8080/editionManagement/bbc401c3-2d99-4142-bbb7-24c345d1fb21", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "editionManagement", + "bbc401c3-2d99-4142-bbb7-24c345d1fb21" + ] + } + }, + "response": [] + }, + { + "name": "CreateEdition", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA0ODMzMjY1LCJleHAiOjE2MDQ5MTk2NjUsImlhdCI6MTYwNDgzMzI2NX0.bGjMLDkCZ6zSBVUxC3WtYgyo-af16aJEGXKAUg_6p5Y", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"editionStart\": \"2020-11-15T11:02:04.002Z\",\r\n \"editionFinish\": \"2020-11-25T11:02:04.002Z\",\r\n \"reportingStart\": \"2020-11-20T11:02:04.002Z\",\r\n \"course\": {\r\n \"name\": \"Informatyka\"\r\n },\r\n \"availableSubjectsIds\": [2],\r\n \"availableInternshipTypesIds\": [8]\r\n}" + }, + "url": { + "raw": "http://localhost:8080/editionManagement", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "editionManagement" + ] + } + }, + "response": [] + }, + { + "name": "UpdateEdition", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA0ODMzMjY1LCJleHAiOjE2MDQ5MTk2NjUsImlhdCI6MTYwNDgzMzI2NX0.bGjMLDkCZ6zSBVUxC3WtYgyo-af16aJEGXKAUg_6p5Y", + "type": "string" + } + ] + }, + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"id\": \"138da8a3-855c-4b17-9bd2-5f357679efa9\",\r\n \"editionStart\": \"2020-11-15T11:02:04.002Z\",\r\n \"editionFinish\": \"2020-11-20T11:02:04.002Z\",\r\n \"reportingStart\": \"2020-11-17T11:02:04.002Z\",\r\n \"course\": {\r\n \"name\": \"Informatyka\"\r\n },\r\n \"availableSubjectsIds\": [3],\r\n \"availableInternshipTypesIds\": [3]\r\n}" + }, + "url": { + "raw": "http://localhost:8080/editionManagement", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "editionManagement" + ] + } + }, + "response": [] + }, + { + "name": "DeleteEditionManagement", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA0ODI3ODgzLCJleHAiOjE2MDQ5MTQyODMsImlhdCI6MTYwNDgyNzg4M30.a3mMm3Zk3xpfsmIwlqtpjgWgTNEXv8O4hH_V_L9UFZo", + "type": "string" + } + ] + }, + "method": "DELETE", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "url": { + "raw": "http://localhost:8080/editionManagement/bbc401c3-2d99-4142-bbb7-24c345d1fb21", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "editionManagement", + "bbc401c3-2d99-4142-bbb7-24c345d1fb21" + ] + } + }, + "response": [] + }, + { + "name": "updateRegistration", + "request": { + "method": "PUT", + "header": [ + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\r\n \"company\": {\r\n \"id\": 1,\r\n \"nip\": null,\r\n \"name\": null\r\n },\r\n \"branchOffice\": {\r\n \"id\": 1,\r\n \"street\": null,\r\n \"building\": null,\r\n \"city\": null,\r\n \"postalCode\": null,\r\n \"country\": null\r\n },\r\n \"start\": \"2020-07-27T09:43:49.094Z\",\r\n \"end\": \"2020-09-27T09:43:49.094Z\",\r\n \"type\": {\r\n \"id\": 2,\r\n \"type\": null,\r\n \"description\": null,\r\n \"descriptionEng\": null\r\n }\r\n}" + }, + "url": { + "raw": "http://localhost:8080/internshipRegistration", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "internshipRegistration" + ] + } + }, + "response": [] + }, + { + "name": "GetRegisteredEditions", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "http://localhost:8080/editions", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "editions" + ] + } + }, + "response": [] + }, + { + "name": "GetEditionsConfiguration", + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "type": "text", + "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE" + }, + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "url": { + "raw": "http://localhost:8080/editions/138da8a3-855c-4b17-9bd2-5f357679efa9", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "editions", + "138da8a3-855c-4b17-9bd2-5f357679efa9" + ] + } + }, + "response": [] + }, + { + "name": "RegisterForEdition", + "request": { + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "\"138da8a3-855c-4b17-9bd2-5f357679efa9\"" + }, + "url": { + "raw": "http://localhost:8080/register", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "register" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {} +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/ApiProfile.cs b/src/InternshipSystem.Api/ApiProfile.cs index 9f20a90..729a8ba 100644 --- a/src/InternshipSystem.Api/ApiProfile.cs +++ b/src/InternshipSystem.Api/ApiProfile.cs @@ -18,12 +18,22 @@ namespace InternshipSystem.Api .ForMember( result => result.Status, opt => opt.MapFrom(edition => edition.IsOpen ? "Open" : "Archival")); + + CreateMap(); + + CreateMap(); CreateMap(); CreateMap(); - CreateMap().IncludeMembers(es => es.Subject); + CreateMap() + .IncludeMembers(es => es.Subject); + + CreateMap() + .IncludeMembers(eit => eit.InternshipType); + + CreateMap(); } } } \ No newline at end of file diff --git a/src/InternshipSystem.Api/Controllers/EditionManagementController.cs b/src/InternshipSystem.Api/Controllers/EditionManagementController.cs new file mode 100644 index 0000000..bd5fda7 --- /dev/null +++ b/src/InternshipSystem.Api/Controllers/EditionManagementController.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using InternshipSystem.Api.Queries; +using InternshipSystem.Api.Queries.SearchQuery; +using InternshipSystem.Api.Result; +using InternshipSystem.Api.Security; +using InternshipSystem.Core; +using InternshipSystem.Repository; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace InternshipSystem.Api.Controllers +{ + [ApiController] + [Route("editionManagement")] + public class EditionManagementController : ControllerBase + { + private InternshipDbContext Context { get; } + private IMapper Mapper { get; } + + public EditionManagementController(IMapper mapper, InternshipDbContext context) + { + Context = context; + Mapper = mapper; + } + + [HttpGet] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [Authorize(Policy = Policies.IsOverseer)] + public async Task>> GetEditions([FromQuery] EditionSearchQuery searchQuery, CancellationToken token) => + await Context.Editions + .Include(e => e.Course) + .ProjectTo(Mapper.ConfigurationProvider) + .Skip(searchQuery.Page * searchQuery.PerPage) + .Take(searchQuery.PerPage) + .ToListAsync(token); + + [HttpGet("{editionId}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [Authorize(Policy = Policies.IsOverseer)] + public async Task> GetFullEdition(Guid editionId, CancellationToken token) + { + var edition = await Context.Editions + .Include(e => e.Course) + .Include(e => e.AvailableSubjects) + .ThenInclude(s => s.Subject) + .Include(e => e.AvailableInternshipTypes) + .ThenInclude(i => i.InternshipType) + .Where(e => e.Id == editionId) + .ProjectTo(Mapper.ConfigurationProvider) + .FirstOrDefaultAsync(token); + + if (edition == null) + { + return NotFound(); + } + + return Ok(edition); + } + + [HttpPut] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [Authorize(Policy = Policies.IsOverseer)] + public async Task UpsertEdition(EditionForm editionForm, CancellationToken token) + { + var validator = new EditionForm.Validator(); + var validationResult = await validator.ValidateAsync(editionForm, token); + + if (!validationResult.IsValid) + { + return BadRequest(validationResult.ToString()); + } + + //TODO: resolve courses (one for each edition or dictionary) + editionForm.Course.Id = 0; + + if (editionForm.Id.HasValue) + { + var editionToUpdate = await Context.Editions + .Include(e => e.AvailableSubjects) + .Include(e => e.AvailableInternshipTypes) + .FirstOrDefaultAsync(e => e.Id == editionForm.Id.Value, token); + + if (editionToUpdate == null) + { + return NotFound(); + } + + editionToUpdate.UpdateEdition(editionForm.EditionStart, editionForm.EditionFinish, editionForm.ReportingStart, + editionForm.Course, editionForm.AvailableSubjectsIds, editionForm.AvailableInternshipTypesIds); + + if (!editionToUpdate.IsValidDates) + { + return BadRequest(); + } + } + else + { + var newEdition = + Edition.CreateEdition(editionForm.EditionStart.Value, editionForm.EditionFinish.Value, editionForm.ReportingStart.Value, + editionForm.Course, editionForm.AvailableSubjectsIds, editionForm.AvailableInternshipTypesIds); + + if (!newEdition.IsValidDates) + { + return BadRequest(); + } + + await Context.Editions.AddAsync(newEdition, token); + } + + await Context.SaveChangesAsync(token); + return Ok(); + } + + [HttpDelete("{editionId}")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status409Conflict)] + [Authorize(Policy = Policies.IsOverseer)] + public async Task DeleteEdition(Guid editionId, CancellationToken token) + { + var editionToDelete = await Context.Editions + .Include(e => e.AvailableSubjects) + .Include(e => e.AvailableInternshipTypes) + .FirstOrDefaultAsync(e => e.Id.Equals(editionId), token); + + if (editionToDelete == null) + { + return NotFound(); + } + + var referencedInternships = + await Context + .Entry(editionToDelete) + .Collection(e => e.Internships) + .Query() + .CountAsync(token); + + if (referencedInternships > 0) + { + return Conflict(); + } + + Context.Editions.Remove(editionToDelete); + await Context.SaveChangesAsync(token); + return Ok(); + } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Controllers/InternshipTypesController.cs b/src/InternshipSystem.Api/Controllers/InternshipTypesController.cs index 41b218d..15778e4 100644 --- a/src/InternshipSystem.Api/Controllers/InternshipTypesController.cs +++ b/src/InternshipSystem.Api/Controllers/InternshipTypesController.cs @@ -163,7 +163,6 @@ namespace InternshipSystem.Api.Controllers return NotFound($"Internship type with id: {internshipTypeId} does not exist"); } - Context.InternshipTypes.Attach(internshipTypeToDelete); Context.InternshipTypes.Remove(internshipTypeToDelete); await Context.SaveChangesAsync(cancellationToken); return Ok($"Internship type with id: {internshipTypeId} deleted successfully"); diff --git a/src/InternshipSystem.Api/Controllers/StaticPagesController.cs b/src/InternshipSystem.Api/Controllers/StaticPagesController.cs index 94b9b2f..b065dda 100644 --- a/src/InternshipSystem.Api/Controllers/StaticPagesController.cs +++ b/src/InternshipSystem.Api/Controllers/StaticPagesController.cs @@ -155,7 +155,6 @@ namespace InternshipSystem.Api.Controllers return NotFound($"Static page with access name: {accessName} does not exist"); } - Context.StaticPages.Attach(pageToDelete); Context.StaticPages.Remove(pageToDelete); await Context.SaveChangesAsync(cancellationToken); return Ok($"Static page with access name: {accessName} deleted successfully"); diff --git a/src/InternshipSystem.Api/Queries/EditionForm.cs b/src/InternshipSystem.Api/Queries/EditionForm.cs new file mode 100644 index 0000000..6c30d3e --- /dev/null +++ b/src/InternshipSystem.Api/Queries/EditionForm.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using FluentValidation; +using InternshipSystem.Core; +using InternshipSystem.Core.Entity.Internship; + +namespace InternshipSystem.Api.Queries +{ + public class EditionForm + { + public Guid? Id { get; set; } + public DateTime? EditionStart { get; set; } + public DateTime? EditionFinish { get; set; } + public DateTime? ReportingStart { get; set; } + public Course Course { get; set; } + public List AvailableSubjectsIds { get; set; } = new List(); + public List AvailableInternshipTypesIds { get; set; } = new List(); + + public class Validator : AbstractValidator + { + public Validator() + { + RuleFor(e => e.Id).NotNull() + .When(e => !e.EditionStart.HasValue || !e.EditionFinish.HasValue + || !e.ReportingStart.HasValue || e.Course == null); + + RuleFor(e => e.EditionStart).NotEmpty() + .When(e => !e.Id.HasValue); + RuleFor(e => e.EditionFinish).NotEmpty() + .When(e => !e.Id.HasValue); + RuleFor(e => e.ReportingStart).NotEmpty() + .When(e => !e.Id.HasValue); + RuleFor(e => e.Course).NotNull() + .When(e => !e.Id.HasValue); + } + } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Queries/SearchQuery/EditionSearchQuery.cs b/src/InternshipSystem.Api/Queries/SearchQuery/EditionSearchQuery.cs new file mode 100644 index 0000000..3495ecf --- /dev/null +++ b/src/InternshipSystem.Api/Queries/SearchQuery/EditionSearchQuery.cs @@ -0,0 +1,7 @@ +namespace InternshipSystem.Api.Queries.SearchQuery +{ + public class EditionSearchQuery : SearchQuery + { + + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Result/EditionDetailsResult.cs b/src/InternshipSystem.Api/Result/EditionDetailsResult.cs new file mode 100644 index 0000000..19754bd --- /dev/null +++ b/src/InternshipSystem.Api/Result/EditionDetailsResult.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using InternshipSystem.Core; +using InternshipSystem.Core.Entity.Internship; + +namespace InternshipSystem.Api.Result +{ + public class EditionDetailsResult + { + public Guid Id { get; set; } + public DateTime EditionStart { get; set; } + public DateTime EditionFinish { get; set; } + public DateTime ReportingStart { get; set; } + public Course Course { get; set; } + public List AvailableSubjects { get; set; } + public List AvailableInternshipTypes { get; set; } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Result/EditionManagementResult.cs b/src/InternshipSystem.Api/Result/EditionManagementResult.cs new file mode 100644 index 0000000..2e86aa3 --- /dev/null +++ b/src/InternshipSystem.Api/Result/EditionManagementResult.cs @@ -0,0 +1,14 @@ +using System; +using InternshipSystem.Core; + +namespace InternshipSystem.Api.Result +{ + public class EditionManagementResult + { + public Guid Id { get; set; } + public DateTime EditionStart { get; set; } + public DateTime EditionFinish { get; set; } + public DateTime ReportingStart { get; set; } + public Course Course { get; set; } + } +} \ No newline at end of file diff --git a/src/InternshipSystem.Api/Security/Policies.cs b/src/InternshipSystem.Api/Security/Policies.cs index 58e6d99..2f6a466 100644 --- a/src/InternshipSystem.Api/Security/Policies.cs +++ b/src/InternshipSystem.Api/Security/Policies.cs @@ -3,5 +3,6 @@ public static class Policies { public const string RegisteredOnly = "RegisteredForEditionOnly"; + public const string IsOverseer = "IsOverseer"; } } \ No newline at end of file diff --git a/src/InternshipSystem.Api/Startup.cs b/src/InternshipSystem.Api/Startup.cs index 595b43e..a1b1bed 100644 --- a/src/InternshipSystem.Api/Startup.cs +++ b/src/InternshipSystem.Api/Startup.cs @@ -38,6 +38,8 @@ namespace InternshipSystem.Api .AddAuthorization(o => { o.AddPolicy(Policies.RegisteredOnly, policy => policy.RequireClaim("Edition")); + //TODO: change to claim for InternshipRepresentative + o.AddPolicy(Policies.IsOverseer, policy => policy.RequireClaim("PersonNumber")); }) .AddHttpClient(); diff --git a/src/InternshipSystem.Core/Entity/Edition.cs b/src/InternshipSystem.Core/Entity/Edition.cs index c22eb53..567693f 100644 --- a/src/InternshipSystem.Core/Entity/Edition.cs +++ b/src/InternshipSystem.Core/Entity/Edition.cs @@ -18,17 +18,77 @@ namespace InternshipSystem.Core public List AvailableInternshipTypes { get; set; } public bool IsOpen => EditionFinish < DateTime.Today; - - public Edition CreateEdition(DateTime start, DateTime end, DateTime reportingStart) + + public static Edition CreateEdition(DateTime start, DateTime end, DateTime reportingStart, Course course, + IEnumerable subjectsIds, IEnumerable internshipTypesIds) + { + var newEdition = CreateEdition(start, end, reportingStart, course); + + newEdition.AvailableSubjects = + subjectsIds + .Select(s => new EditionSubject + { + Edition = newEdition, + InternshipSubjectId = s, + }) + .ToList(); + + newEdition.AvailableInternshipTypes = + internshipTypesIds + .Select(i => new EditionInternshipType + { + Edition = newEdition, + InternshipTypeId = i, + }) + .ToList(); + + return newEdition; + } + + public static Edition CreateEdition(DateTime start, DateTime end, DateTime reportingStart, Course course) { return new Edition { EditionStart = start, EditionFinish = end, - ReportingStart = reportingStart + ReportingStart = reportingStart, + Course = course, + AvailableSubjects = new List(), + AvailableInternshipTypes = new List(), }; } + public void UpdateEdition(DateTime? start, DateTime? end, DateTime? reportingStart, Course course, + IEnumerable subjectsIds, IEnumerable internshipTypesIds) + { + EditionStart = start ?? EditionStart; + EditionFinish = end ?? EditionFinish; + ReportingStart = reportingStart ?? ReportingStart; + Course = course; + + if (subjectsIds != null) + { + AvailableSubjects = + subjectsIds + .Select(s => new EditionSubject + { + InternshipSubjectId = s, + }) + .ToList(); + } + + if (internshipTypesIds != null) + { + AvailableInternshipTypes = + internshipTypesIds + .Select(i => new EditionInternshipType + { + InternshipTypeId = i, + }) + .ToList(); + } + } + public void RegisterInternship(Student student) { if (Internships.Any(i => i.Student.Id == student.Id)) @@ -55,5 +115,7 @@ namespace InternshipSystem.Core { return internshipSubjects.All(s => AvailableSubjects.Any(su => su.InternshipSubjectId == s)); } + + public bool IsValidDates => EditionStart <= EditionFinish; } } \ No newline at end of file