Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/362 categories #378

Merged
merged 52 commits into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
03fd8c3
Added Tags, added project tag connection, added tag migration, seeded…
JVerbruggen Feb 24, 2021
c17526a
All project and tag endpoints work
JVerbruggen Feb 26, 2021
c476ddd
Added changelog record
JVerbruggen Feb 26, 2021
15684f3
Added administrator tag postman tests
JVerbruggen Feb 26, 2021
e3e376b
Added postman ACL tests for all users, updated necessary env vars
JVerbruggen Feb 26, 2021
2f0b47d
Tweaked roles and postman tests
JVerbruggen Feb 26, 2021
af5cabf
Added Unit Tests
JVerbruggen Feb 26, 2021
80a94f0
Name now required at creation tag
JVerbruggen Mar 1, 2021
4dbb3a8
Updated documentation
JVerbruggen Mar 1, 2021
0820bdf
Removed unnecessary userservice from tagcontroller
JVerbruggen Mar 1, 2021
93eb22b
Updated responsetype attributes
JVerbruggen Mar 1, 2021
4b72b15
Updated HTTP status code delete tag conflict
JVerbruggen Mar 1, 2021
bd0d6ae
Update API/Resources/ProjectTagResourceResult.cs
JVerbruggen Mar 1, 2021
7ed003c
Update API/Resources/TagResourceResult.cs
JVerbruggen Mar 1, 2021
c307c58
Update CHANGELOG.md
JVerbruggen Mar 1, 2021
03a50ec
Fixed role and tag service switch
JVerbruggen Mar 1, 2021
432c089
Updated GUID problems from GetTag
JVerbruggen Mar 1, 2021
083b07a
Renamed Tag to Category
JVerbruggen Mar 4, 2021
8d4bc9c
Removed itemgroup tag identityserver csproj
JVerbruggen Mar 4, 2021
1c47bf9
Corrected an oopsie in identityserver csproj, removing getallasync...
JVerbruggen Mar 4, 2021
c4cf004
Removed GetAllAsync completely
JVerbruggen Mar 4, 2021
78c9176
Added own + other project controller response tags (niray request)
JVerbruggen Mar 4, 2021
cf7e759
Added summary comments, fixed unit tests
JVerbruggen Mar 4, 2021
2c08a6e
Fixed role unit test because of name change tags
JVerbruggen Mar 4, 2021
7369a62
Renamed ALL postman tests and vars (hour long big sigh)
JVerbruggen Mar 4, 2021
b536cf6
Solved merge conflict
JVerbruggen Mar 4, 2021
46d7b47
Updated postman for multiple iterations now, cleaned up project repo
JVerbruggen Mar 8, 2021
ab6e795
Fixed some final translation errors
JVerbruggen Mar 11, 2021
d66adb0
Changed back mysterious apirequesthandler changes
JVerbruggen Mar 11, 2021
6016b3b
Put back merge conflict code ramon
JVerbruggen Mar 11, 2021
2ba79b1
Fixed tagId to ctaegoryId
JVerbruggen Mar 11, 2021
8bf1a91
Altered applicationdbcontextmodelsnapshot
JVerbruggen Mar 11, 2021
0b33a62
Update CHANGELOG.md
JVerbruggen Mar 12, 2021
2454620
Update API/Controllers/ProjectController.cs
JVerbruggen Mar 12, 2021
6cd31f8
Added producesresponsetype to responses controller
JVerbruggen Mar 12, 2021
c72ac39
Resolved invalid ProducesResponseType type attribute
RubenFricke Mar 14, 2021
5bafd35
Added category option to create project endpoint
JVerbruggen Mar 16, 2021
f51dd8a
Merge branch 'feature/362-add-tags-categories' of https://github.com/…
JVerbruggen Mar 16, 2021
65a7d12
Working on adding with update
JVerbruggen Mar 16, 2021
5f87250
Category update on project update not necessary
JVerbruggen Apr 1, 2021
16f96a7
Changed add category to project response type to Project
JVerbruggen Apr 1, 2021
1e12864
Added postman test to test categorize on project create
JVerbruggen Apr 1, 2021
4a71a9f
Repaired postman on project create test
JVerbruggen Apr 1, 2021
96254c9
Merged with develop
JVerbruggen Apr 1, 2021
a69a384
Merged postman collection
JVerbruggen Apr 1, 2021
52be976
Optimised project categories fetching from repo
JVerbruggen Apr 8, 2021
5772c14
removed init from projectcategory list
JVerbruggen Apr 12, 2021
d869c19
changed category name length from max to 100
JVerbruggen Apr 12, 2021
551d1ad
Added category update on project update
JVerbruggen Apr 12, 2021
309787f
Forgot to update problem details guid
JVerbruggen Apr 13, 2021
1e749ab
Merged postman collection manually
JVerbruggen Apr 13, 2021
1225e2c
Merged develop into here
JVerbruggen Apr 13, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion API/Configuration/MappingProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using Models;
using Services.ExternalDataProviders;
using Services.ExternalDataProviders.Resources;
using System.Collections.Generic;

namespace API.Configuration
{
Expand Down Expand Up @@ -83,7 +84,8 @@ public MappingProfile()

CreateMap<User, LimitedUserResourceResult>();

CreateMap<ProjectResource, Project>();
CreateMap<ProjectResource, Project>()
.ForMember(q => q.Categories, opt => opt.Ignore());
CreateMap<Project, ProjectResourceResult>();
CreateMap<ProjectLike, ProjectLikesResourceResult>();
CreateMap<Project, ProjectHighlightResourceResult>();
Expand All @@ -103,6 +105,13 @@ public MappingProfile()
CreateMap<RoleResource, Role>();
CreateMap<Role, RoleResourceResult>();

CreateMap<CategoryResource, Category>();
CreateMap<Category, CategoryResourceResult>();
CreateMap<ProjectCategoryResource, ProjectCategory>();
CreateMap<ProjectCategory, ProjectCategoryResourceResult>()
.ForMember(q => q.Id, opt => opt.MapFrom(q=> q.Category.Id))
.ForMember(q => q.Name, opt => opt.MapFrom(q => q.Category.Name));

CreateMap<EmbeddedProjectResource, EmbeddedProject>();
CreateMap<EmbeddedProject, EmbeddedProjectResourceResult>();

Expand Down
233 changes: 233 additions & 0 deletions API/Controllers/CategoryController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
using API.Resources;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Models;
using Serilog;
using Services.Services;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using static Models.Defaults.Defaults;

namespace API.Controllers
{

/// <summary>
/// This class is responsible for handling HTTP requests that are related
/// to categories, for example creating, retrieving, updating or deleting.
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class CategoryController : ControllerBase
{

private readonly IMapper mapper;
private readonly ICategoryService categoryService;
private readonly IProjectCategoryService projectCategoryService;

/// <summary>
/// Initializes a new instance of the <see cref="CategoryController" /> class
/// </summary>
/// <param name="categoryService">The category service which is used to communicate with the logic layer.</param>
/// <param name="projectCategoryService">The project category service which is used to communicate with the logic layer.</param>
/// <param name="mapper">The mapper which is used to convert the resources to the model to the resource result.</param>
public CategoryController(ICategoryService categoryService, IProjectCategoryService projectCategoryService, IMapper mapper)
{
this.categoryService = categoryService;
this.projectCategoryService = projectCategoryService;
this.mapper = mapper;
}

/// <summary>
/// This method is responsible for retrieving all categories.
/// </summary>
/// <returns>This method returns a list of category resource results.</returns>
/// <response code="200">This endpoint returns a list of categories.</response>
[HttpGet]
[Authorize(Policy = nameof(Scopes.CategoryRead))]
[ProducesResponseType(typeof(IEnumerable<CategoryResourceResult>), (int) HttpStatusCode.OK)]
public async Task<IActionResult> GetAllCategories()
{
IEnumerable<Category> categories = await categoryService.GetAll()
.ConfigureAwait(false);

return Ok(mapper.Map<IEnumerable<Category>, IEnumerable<CategoryResourceResult>>(categories));
}

/// <summary>
/// This method is responsible for retrieving a single category.
/// </summary>
/// <returns>This method returns the category resource result.</returns>
/// <response code="200">This endpoint returns the category with the specified id.</response>
/// <response code="400">The 400 Bad Request status code is returned when the specified category id is invalid.</response>
/// <response code="404">The 404 Not Found status code is returned when no category is found with the specified category id.</response>
[HttpGet("{categoryId}")]
[Authorize(Policy = nameof(Scopes.CategoryRead))]
[ProducesResponseType(typeof(CategoryResourceResult), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.NotFound)]
public async Task<IActionResult> GetCategory(int categoryId)
{
if(categoryId < 0)
{
ProblemDetails problem = new ProblemDetails
{
Title = "Failed getting category.",
Detail =
"The Id is smaller then 0 and therefore it could never be a valid category id.",
Instance = "758F4B36-A047-42D4-9F9E-B09BF8106F85"
};
return BadRequest(problem);
}

Category category = await categoryService.FindAsync(categoryId)
.ConfigureAwait(false);
if(category == null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "Failed getting category.",
Detail = "The category could not be found in the database.",
Instance = "872DEE7C-D1C8-4161-B8BA-B577EAA5A1C9"
};
return NotFound(problem);
}

return Ok(mapper.Map<Category, CategoryResourceResult>(category));
}

/// <summary>
/// This method is responsible for creating the category.
/// </summary>
/// <param name="categoryResource">The category resource which is used to create a category.</param>
/// <returns>This method returns the created category resource result.</returns>
/// <response code="201">This endpoint returns the created category.</response>
/// <response code="400">The 400 Bad Request status code is returned when unable to create category.</response>
[HttpPost]
[Authorize(Policy = nameof(Scopes.CategoryWrite))]
[ProducesResponseType(typeof(CategoryResourceResult), (int) HttpStatusCode.Created)]
[ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.BadRequest)]
public async Task<IActionResult> CreateCategoryAsync([FromBody] CategoryResource categoryResource)
{
if(categoryResource == null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "Failed to create a new category.",
Detail = "The specified category resource was null",
Instance = "ABA3B997-1B80-47FC-A72B-69BC0D8DFA93"
};
return BadRequest(problem);
}
Category category = mapper.Map<CategoryResource, Category>(categoryResource);

try
{
await categoryService.AddAsync(category)
.ConfigureAwait(false);
categoryService.Save();
return Created(nameof(CreateCategoryAsync), mapper.Map<Category, CategoryResourceResult>(category));
}
catch(DbUpdateException e)
{
Log.Logger.Error(e, "Database exception");

ProblemDetails problem = new ProblemDetails
{
Title = "Failed to save the new category.",
Detail = "There was a problem while saving the category to the database.",
Instance = "D56DBE55-57A1-4655-99C5-4F4ECEEE3BE4"
};
return BadRequest(problem);
}
}

/// <summary>
/// This method is responsible for updating the category.
/// </summary>
/// <param name="categoryId">The category identifier which is used for searching the category.</param>
/// <param name="categoryResource">The category resource which is used to update the category.</param>
/// <returns>This method returns the updated category resource result.</returns>
/// <response code="200">This endpoint returns the updated category.</response>
/// <response code="404">The 404 Not Found status code is returned when the category with the specified id could not be found.</response>
[HttpPut("{categoryId}")]
[Authorize(Policy = nameof(Scopes.CategoryWrite))]
[ProducesResponseType(typeof(CategoryResourceResult), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.NotFound)]
public async Task<IActionResult> UpdateCategory(int categoryId, CategoryResource categoryResource)
{
Category currentCategory = await categoryService.FindAsync(categoryId)
.ConfigureAwait(false);
if(currentCategory == null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "Failed to update the category.",
Detail = "The specified category could not be found in the database",
Instance = "8F167FDF-3B2B-4E71-B3D0-AA2B1C1CE2C3"
};
return NotFound(problem);
}
mapper.Map(categoryResource, currentCategory);

categoryService.Update(currentCategory);
categoryService.Save();

return Ok(mapper.Map<Category, CategoryResourceResult>(currentCategory));
}

/// <summary>
/// This method is responsible for deleting the category.
/// </summary>
/// <param name="categoryId">The category identifier which is used for searching the category.</param>
/// <returns>This method returns status code 200.</returns>
/// <response code="200">This endpoint returns status code 200. Category is deleted.</response>
/// <response code="404">The 404 Not Found status code is returned when the category with the specified id could not be found.</response>
/// <response code="409">The 409 Conflict status code is returned when the category is still connected to a project.</response>
[HttpDelete("{categoryId}")]
[Authorize(Policy = nameof(Scopes.CategoryWrite))]
[ProducesResponseType(typeof(CategoryResourceResult), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.Conflict)]
[ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.NotFound)]
public async Task<IActionResult> DeleteCategory(int categoryId)
{
Category category = await categoryService.FindAsync(categoryId)
.ConfigureAwait(false);
if(category == null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "Failed to delete the category.",
Detail = "The category could not be found in the database.",
Instance = "A0853DE4-C881-4597-A5A7-42F6761CECE0"
};
return NotFound(problem);
}

ProjectCategory projectCategory = await projectCategoryService.GetProjectCategory(categoryId);

if(projectCategory != null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "Failed to delete the category.",
Detail = "The category is still connected to a project.",
Instance = "4AA5102B-3A6F-4144-BF01-0EC32B4E69A8"
};
return Conflict(problem);
}

await categoryService.RemoveAsync(category.Id)
.ConfigureAwait(false);
categoryService.Save();

IEnumerable<Category> categories = await categoryService.GetAll()
.ConfigureAwait(false);

return Ok(mapper.Map<IEnumerable<Category>, IEnumerable<CategoryResourceResult>>(categories));
}
}

}
Loading