From 74e3957274cdc09ef0638e064f34223a3efc85f5 Mon Sep 17 00:00:00 2001
From: mborzyszkowski <maciej.borzyszkowski@gmail.com>
Date: Sun, 8 Nov 2020 10:53:14 +0100
Subject: [PATCH 1/4] Edition Get and Delete

---
 src/InternshipSystem.Api/ApiProfile.cs        |  12 +-
 .../EditionManagementController.cs            | 127 ++++++++++++++++++
 .../Queries/EditionForm.cs                    |  27 ++++
 .../Queries/SearchQuery/EditionSearchQuery.cs |   7 +
 .../Result/EditionFullResult.cs               |  18 +++
 .../Result/EditionManagementResult.cs         |  14 ++
 src/InternshipSystem.Api/Security/Policies.cs |   1 +
 src/InternshipSystem.Api/Startup.cs           |   2 +
 8 files changed, 207 insertions(+), 1 deletion(-)
 create mode 100644 src/InternshipSystem.Api/Controllers/EditionManagementController.cs
 create mode 100644 src/InternshipSystem.Api/Queries/EditionForm.cs
 create mode 100644 src/InternshipSystem.Api/Queries/SearchQuery/EditionSearchQuery.cs
 create mode 100644 src/InternshipSystem.Api/Result/EditionFullResult.cs
 create mode 100644 src/InternshipSystem.Api/Result/EditionManagementResult.cs

diff --git a/src/InternshipSystem.Api/ApiProfile.cs b/src/InternshipSystem.Api/ApiProfile.cs
index 9f20a90..efbe56d 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<Edition, EditionManagementResult>();
+
+            CreateMap<Edition, EditionFullResult>();
             
             CreateMap<Edition, EditionConfigurationResult>();
 
             CreateMap<InternshipSubject, InternshipSubject>();
             
-            CreateMap<EditionSubject, InternshipSubject>().IncludeMembers(es => es.Subject);
+            CreateMap<EditionSubject, InternshipSubject>()
+                .IncludeMembers(es => es.Subject);
+
+            CreateMap<EditionInternshipType, InternshipType>()
+                .IncludeMembers(eit => eit.InternshipType);
+
+            CreateMap<InternshipType, InternshipType>();
         }
     }
 }
\ 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..71cecc2
--- /dev/null
+++ b/src/InternshipSystem.Api/Controllers/EditionManagementController.cs
@@ -0,0 +1,127 @@
+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.SearchQuery;
+using InternshipSystem.Api.Result;
+using InternshipSystem.Api.Security;
+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<ActionResult<IReadOnlyCollection<EditionManagementResult>>> GetEditions([FromQuery] EditionSearchQuery searchQuery, CancellationToken token) =>
+            await Context.Editions
+                .Include(e => e.Course)
+                .ProjectTo<EditionManagementResult>(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<ActionResult<EditionFullResult>> GetFullEdition(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)
+                .ProjectTo<EditionFullResult>(Mapper.ConfigurationProvider)
+                .FirstOrDefaultAsync(token);
+
+            if (edition == null)
+            {
+                return NotFound();
+            }
+
+            return Ok(edition);
+        }
+        
+        [HttpPut]
+        [ProducesResponseType(StatusCodes.Status200OK)]
+        [ProducesResponseType(StatusCodes.Status400BadRequest)]
+        [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+        [ProducesResponseType(StatusCodes.Status404NotFound)]
+        [Authorize(Policy = Policies.IsOverseer)]
+        public async Task<ActionResult> UpsertEdition(EditionForm editionForm, CancellationToken token)
+        {
+            var validator = new EditionForm.Validator();
+            // TODO: complete validation rules
+            var validationResult = await validator.ValidateAsync(editionForm, token);
+
+            if (!validationResult.IsValid)
+            {
+                return BadRequest(validationResult.ToString());
+            }
+            
+            // TODO: complete add/update
+
+            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<ActionResult> 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.Attach(editionToDelete);
+            Context.Editions.Remove(editionToDelete);
+            await Context.SaveChangesAsync(token);
+            return Ok();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/InternshipSystem.Api/Queries/EditionForm.cs b/src/InternshipSystem.Api/Queries/EditionForm.cs
new file mode 100644
index 0000000..3b41aac
--- /dev/null
+++ b/src/InternshipSystem.Api/Queries/EditionForm.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using FluentValidation;
+using InternshipSystem.Core;
+using InternshipSystem.Core.Entity.Internship;
+
+namespace InternshipSystem.Api.Controllers
+{
+    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<InternshipSubject> AvailableSubjects { get; set; }
+        public List<InternshipType> AvailableInternshipTypes { get; set; }
+        
+        public class Validator : AbstractValidator<EditionForm>
+        {
+            public Validator()
+            {
+                //TODO: later
+            }
+        }
+    }
+}
\ 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/EditionFullResult.cs b/src/InternshipSystem.Api/Result/EditionFullResult.cs
new file mode 100644
index 0000000..57c9e29
--- /dev/null
+++ b/src/InternshipSystem.Api/Result/EditionFullResult.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 EditionFullResult
+    {
+        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<InternshipSubject> AvailableSubjects { get; set; }
+        public List<InternshipType> 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<GutCasClient>();
 
-- 
2.45.2


From 78707bf3c574388e86816f8ce4e4d94c96c81146 Mon Sep 17 00:00:00 2001
From: mborzyszkowski <maciej.borzyszkowski@gmail.com>
Date: Sun, 8 Nov 2020 13:08:38 +0100
Subject: [PATCH 2/4] Edition Create/Edit

---
 src/InternshipSystem.Api/ApiProfile.cs        |  2 +-
 .../EditionManagementController.cs            | 51 ++++++++++++--
 .../Queries/EditionForm.cs                    | 27 +++++---
 ...nFullResult.cs => EditionDetailsResult.cs} |  2 +-
 src/InternshipSystem.Core/Entity/Edition.cs   | 68 ++++++++++++++++++-
 5 files changed, 131 insertions(+), 19 deletions(-)
 rename src/InternshipSystem.Api/Result/{EditionFullResult.cs => EditionDetailsResult.cs} (93%)

diff --git a/src/InternshipSystem.Api/ApiProfile.cs b/src/InternshipSystem.Api/ApiProfile.cs
index efbe56d..729a8ba 100644
--- a/src/InternshipSystem.Api/ApiProfile.cs
+++ b/src/InternshipSystem.Api/ApiProfile.cs
@@ -21,7 +21,7 @@ namespace InternshipSystem.Api
 
             CreateMap<Edition, EditionManagementResult>();
 
-            CreateMap<Edition, EditionFullResult>();
+            CreateMap<Edition, EditionDetailsResult>();
             
             CreateMap<Edition, EditionConfigurationResult>();
 
diff --git a/src/InternshipSystem.Api/Controllers/EditionManagementController.cs b/src/InternshipSystem.Api/Controllers/EditionManagementController.cs
index 71cecc2..d56543b 100644
--- a/src/InternshipSystem.Api/Controllers/EditionManagementController.cs
+++ b/src/InternshipSystem.Api/Controllers/EditionManagementController.cs
@@ -5,9 +5,11 @@ 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;
@@ -46,7 +48,7 @@ namespace InternshipSystem.Api.Controllers
         [ProducesResponseType(StatusCodes.Status401Unauthorized)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
         [Authorize(Policy = Policies.IsOverseer)]
-        public async Task<ActionResult<EditionFullResult>> GetFullEdition(CancellationToken token)
+        public async Task<ActionResult<EditionDetailsResult>> GetFullEdition(Guid editionId, CancellationToken token)
         {
             var edition = await Context.Editions
                 .Include(e => e.Course)
@@ -54,7 +56,8 @@ namespace InternshipSystem.Api.Controllers
                     .ThenInclude(s => s.Subject)
                 .Include(e => e.AvailableInternshipTypes)
                     .ThenInclude(i => i.InternshipType)
-                .ProjectTo<EditionFullResult>(Mapper.ConfigurationProvider)
+                .Where(e => e.Id == editionId)
+                .ProjectTo<EditionDetailsResult>(Mapper.ConfigurationProvider)
                 .FirstOrDefaultAsync(token);
 
             if (edition == null)
@@ -68,22 +71,58 @@ namespace InternshipSystem.Api.Controllers
         [HttpPut]
         [ProducesResponseType(StatusCodes.Status200OK)]
         [ProducesResponseType(StatusCodes.Status400BadRequest)]
+        [ProducesResponseType(StatusCodes.Status400BadRequest)]
         [ProducesResponseType(StatusCodes.Status401Unauthorized)]
         [ProducesResponseType(StatusCodes.Status404NotFound)]
         [Authorize(Policy = Policies.IsOverseer)]
         public async Task<ActionResult> UpsertEdition(EditionForm editionForm, CancellationToken token)
         {
             var validator = new EditionForm.Validator();
-            // TODO: complete validation rules
             var validationResult = await validator.ValidateAsync(editionForm, token);
-
+    
             if (!validationResult.IsValid)
             {
                 return BadRequest(validationResult.ToString());
             }
-            
-            // TODO: complete add/update
 
+            //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();
         }
         
diff --git a/src/InternshipSystem.Api/Queries/EditionForm.cs b/src/InternshipSystem.Api/Queries/EditionForm.cs
index 3b41aac..6c30d3e 100644
--- a/src/InternshipSystem.Api/Queries/EditionForm.cs
+++ b/src/InternshipSystem.Api/Queries/EditionForm.cs
@@ -4,23 +4,34 @@ using FluentValidation;
 using InternshipSystem.Core;
 using InternshipSystem.Core.Entity.Internship;
 
-namespace InternshipSystem.Api.Controllers
+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 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<InternshipSubject> AvailableSubjects { get; set; }
-        public List<InternshipType> AvailableInternshipTypes { get; set; }
+        public List<long> AvailableSubjectsIds { get; set; } = new List<long>();
+        public List<long> AvailableInternshipTypesIds { get; set; } = new List<long>();
         
         public class Validator : AbstractValidator<EditionForm>
         {
             public Validator()
             {
-                //TODO: later
+                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);
             }
         }
     }
diff --git a/src/InternshipSystem.Api/Result/EditionFullResult.cs b/src/InternshipSystem.Api/Result/EditionDetailsResult.cs
similarity index 93%
rename from src/InternshipSystem.Api/Result/EditionFullResult.cs
rename to src/InternshipSystem.Api/Result/EditionDetailsResult.cs
index 57c9e29..19754bd 100644
--- a/src/InternshipSystem.Api/Result/EditionFullResult.cs
+++ b/src/InternshipSystem.Api/Result/EditionDetailsResult.cs
@@ -5,7 +5,7 @@ using InternshipSystem.Core.Entity.Internship;
 
 namespace InternshipSystem.Api.Result
 {
-    public class EditionFullResult
+    public class EditionDetailsResult
     {
         public Guid Id { get; set; }
         public DateTime EditionStart { get; set; }
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<EditionInternshipType> 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<long> subjectsIds, IEnumerable<long> 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<EditionSubject>(),
+                AvailableInternshipTypes = new List<EditionInternshipType>(),
             };
         }
 
+        public void UpdateEdition(DateTime? start, DateTime? end, DateTime? reportingStart, Course course,
+            IEnumerable<long> subjectsIds, IEnumerable<long> 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
-- 
2.45.2


From 3a64467661d8db74784b9ec71e163f7325a3f9bc Mon Sep 17 00:00:00 2001
From: mborzyszkowski <maciej.borzyszkowski@gmail.com>
Date: Sun, 8 Nov 2020 13:24:25 +0100
Subject: [PATCH 3/4] Refactor

---
 .../Controllers/EditionManagementController.cs                   | 1 -
 .../Controllers/InternshipTypesController.cs                     | 1 -
 src/InternshipSystem.Api/Controllers/StaticPagesController.cs    | 1 -
 3 files changed, 3 deletions(-)

diff --git a/src/InternshipSystem.Api/Controllers/EditionManagementController.cs b/src/InternshipSystem.Api/Controllers/EditionManagementController.cs
index d56543b..bd5fda7 100644
--- a/src/InternshipSystem.Api/Controllers/EditionManagementController.cs
+++ b/src/InternshipSystem.Api/Controllers/EditionManagementController.cs
@@ -157,7 +157,6 @@ namespace InternshipSystem.Api.Controllers
                 return Conflict();
             }
             
-            Context.Editions.Attach(editionToDelete);
             Context.Editions.Remove(editionToDelete);
             await Context.SaveChangesAsync(token);
             return Ok();
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");
-- 
2.45.2


From 2176fbe661ce24536be50423e152053c1a51956f Mon Sep 17 00:00:00 2001
From: mborzyszkowski <maciej.borzyszkowski@gmail.com>
Date: Sun, 8 Nov 2020 13:28:49 +0100
Subject: [PATCH 4/4] Postman endpoints tests

---
 .../StudentOperations.postman_collection.json | 424 ++++++++++++++++++
 1 file changed, 424 insertions(+)
 create mode 100644 PostmanTestRequest/StudentOperations.postman_collection.json

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
-- 
2.45.2