Skip to content

Commit

Permalink
Merge pull request #455 from DigitalExcellence/release/v.1.4.0
Browse files Browse the repository at this point in the history
Release v.1.4.0-beta
  • Loading branch information
niraymak authored Jun 7, 2021
2 parents 3ead4fa + 249dc0f commit a98bb8d
Show file tree
Hide file tree
Showing 55 changed files with 2,436 additions and 239 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -338,4 +338,4 @@ IdentityServer/tempkey.rsa
!/API/Uploads/Images/.gitkeep

###
rabbitmq/data/
rabbitmq/data/
2 changes: 1 addition & 1 deletion API/01_API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<DocumentationFile>.\API.xml</DocumentationFile>
<Company>Digital Excellence Fontys</Company>
<LangVersion>8</LangVersion>
<Version>1.3.0-beta</Version>
<Version>1.4.0-beta</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions API/Configuration/MappingProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public class MappingProfile : Profile
/// </summary>
public MappingProfile()
{
CreateMap<Project, AutocompleteProjectResourceResult>();
CreateMap<AutocompleteProjectResourceResult, Project>();

CreateMap<ProjectLike, UserProjectLikeResourceResult>()
.ForMember(source => source.Id,
option => option
Expand Down
2 changes: 0 additions & 2 deletions API/Controllers/CategoryController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public CategoryController(ICategoryService categoryService, IProjectCategoryServ
/// <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()
{
Expand All @@ -64,7 +63,6 @@ public async Task<IActionResult> GetAllCategories()
/// <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)]
Expand Down
98 changes: 93 additions & 5 deletions API/Controllers/HighlightController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
using Models.Defaults;
using Serilog;
using Services.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
Expand All @@ -43,16 +44,22 @@ public class HighlightController : ControllerBase

private readonly IHighlightService highlightService;
private readonly IMapper mapper;
private readonly IFileService fileService;
private readonly IProjectService projectService;

/// <summary>
/// Initializes a new instance of the <see cref="HighlightController" /> class
/// </summary>
/// <param name="highlightService">The highlight 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 models to resource results.</param>
public HighlightController(IHighlightService highlightService, IMapper mapper)
/// <param name="fileService">The file service which is used to communicate with the logic layer.</param>
/// <param name="projectService">The project service which is used to communicate with the logic layer.</param>
public HighlightController(IHighlightService highlightService, IMapper mapper, IFileService fileService, IProjectService projectService)
{
this.highlightService = highlightService;
this.mapper = mapper;
this.fileService = fileService;
this.projectService = projectService;
}

/// <summary>
Expand Down Expand Up @@ -165,7 +172,8 @@ public async Task<IActionResult> GetHighlightsByProjectId(int projectId)
[Authorize(Policy = nameof(Defaults.Scopes.HighlightWrite))]
[ProducesResponseType(typeof(HighlightResourceResult), (int) HttpStatusCode.Created)]
[ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.BadRequest)]
public IActionResult CreateHighlight(HighlightResource highlightResource)
[ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.NotFound)]
public async Task<IActionResult> CreateHighlight(HighlightResource highlightResource)
{
if(highlightResource == null)
{
Expand All @@ -179,6 +187,38 @@ public IActionResult CreateHighlight(HighlightResource highlightResource)
}

Highlight highlight = mapper.Map<HighlightResource, Highlight>(highlightResource);
File file = null;

if(highlightResource.ImageId != null)
{
file = await fileService.FindAsync(highlightResource.ImageId.Value);
if(file == null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "File was not found.",
Detail = "The specified file was not found while creating highlight.",
Instance = "F4AF3D06-DD74-40E0-99BB-8E1183A6A734"
};
return NotFound(problem);
}
}

Project project = await projectService.FindWithUserCollaboratorsAndInstitutionsAsync(highlightResource.ProjectId);

if(project == null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "Project was not found.",
Detail = "The specified project was not found while creating highlight.",
Instance = "A6DBEE27-0363-479B-B099-A467D4B2CF00"
};
return NotFound(problem);
}

highlight.Image = file;
highlight.Project = project;

try
{
Expand Down Expand Up @@ -214,6 +254,7 @@ public IActionResult CreateHighlight(HighlightResource highlightResource)
[Authorize(Policy = nameof(Defaults.Scopes.HighlightWrite))]
[ProducesResponseType(typeof(HighlightResourceResult), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(ProblemDetails), (int) HttpStatusCode.BadRequest)]
public async Task<IActionResult> UpdateHighlight(int highlightId,
[FromBody] HighlightResource highlightResource)
{
Expand All @@ -231,10 +272,57 @@ public async Task<IActionResult> UpdateHighlight(int highlightId,

mapper.Map(highlightResource, highlight);

highlightService.Update(highlight);
highlightService.Save();
File file = null;

return Ok(mapper.Map<Highlight, HighlightResourceResult>(highlight));
if(highlightResource.ImageId != null)
{
file = await fileService.FindAsync(highlightResource.ImageId.Value);
if(file == null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "File was not found.",
Detail = "The specified file was not found while creating highlight.",
Instance = "412CC9A8-CB2A-4389-9F9C-F8494AB65AE0"
};
return NotFound(problem);
}
}

Project project = await projectService.FindWithUserCollaboratorsAndInstitutionsAsync(highlightResource.ProjectId);

if(project == null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "Project was not found.",
Detail = "The specified project was not found while creating highlight.",
Instance = "B923484E-D562-4F03-A57E-88D02819EBD6"
};
return NotFound(problem);
}

highlight.Image = file;
highlight.Project = project;

try
{
highlightService.Update(highlight);
highlightService.Save();

return Ok(mapper.Map<Highlight, HighlightResourceResult>(highlight));
} catch(DbUpdateException e)
{
Log.Logger.Error(e, "Database exception");

ProblemDetails problem = new ProblemDetails
{
Title = "Failed updating highlight.",
Detail = "Failed updating the highlight to the database.",
Instance = "D9933508-F7B6-44B1-9266-5B040D2EA07D"
};
return BadRequest(problem);
}
}

/// <summary>
Expand Down
96 changes: 78 additions & 18 deletions API/Controllers/ProjectController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using Microsoft.EntityFrameworkCore;
using Models;
using Models.Defaults;
using Models.Exceptions;
using Serilog;
using Services.Services;
using System;
Expand All @@ -34,7 +35,6 @@
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using File = Models.File;

namespace API.Controllers
{
Expand Down Expand Up @@ -228,17 +228,45 @@ public async Task<IActionResult> GetAllProjects(
{
Results = results.ToArray(),
Count = results.Count(),
TotalCount =
await projectService.ProjectsCount(projectFilterParams),
TotalCount = await projectService.ProjectsCount(projectFilterParams),
Page = projectFilterParams.Page,
TotalPages =
await projectService.GetProjectsTotalPages(
projectFilterParams)
TotalPages = await projectService.GetProjectsTotalPages(projectFilterParams)
};

return Ok(resultsResource);
}

/// <summary>
/// This method returns suggestions while searching for projects
/// </summary>
/// <param name="query"></param>
/// <returns>This method returns a list of autocomplete project resources.</returns>
/// <response code="200">This endpoint returns a list with suggested projects.</response>
/// <response code="503">A 503 status code is returned when the Elastic Search service is unavailable.</response>
[HttpGet("search/autocomplete")]
[ProducesResponseType(typeof(List<AutocompleteProjectResourceResult>), (int) HttpStatusCode.OK)]
[ProducesResponseType(typeof(ProblemDetails), 503)]
public async Task<IActionResult> GetAutoCompleteProjects([FromQuery(Name ="query")] string query)
{
try
{
List<Project> projects = await projectService.FindProjectsWhereTitleStartsWithQuery(query);
List<AutocompleteProjectResourceResult> autocompleteProjectResourceResults = mapper.Map<List<Project>, List<AutocompleteProjectResourceResult>>(projects);
return Ok(autocompleteProjectResourceResults);
}
catch(ElasticUnavailableException)
{
return StatusCode(503,
new ProblemDetails
{
Title = "Autocomplete results could not be retrieved.",
Detail = "ElasticSearch service unavailable.",
Instance = "26E7C55F-21DE-4A7B-804C-BC0B74597222"
});
}
}


/// <summary>
/// This method is responsible for retrieving a single project.
/// </summary>
Expand Down Expand Up @@ -340,16 +368,15 @@ await callToActionOptionService.GetCallToActionOptionFromValueAsync(
ProblemDetails problem = new ProblemDetails
{
Title = "Call to action value was not found.",
Detail =
"The specified call to action value was not found while creating the project.",
Detail = "The specified call to action value was not found while creating the project.",
Instance = "40EE82EB-930F-40C8-AE94-0041F7573FE9"
};
return BadRequest(problem);
}
}

Project project = mapper.Map<ProjectResource, Project>(projectResource);
File file = await fileService.FindAsync(projectResource.FileId);
Models.File file = await fileService.FindAsync(projectResource.FileId);

if(projectResource.FileId != 0 &&
file == null)
Expand All @@ -363,6 +390,23 @@ await callToActionOptionService.GetCallToActionOptionFromValueAsync(
return BadRequest(problem);
}

foreach(int projectResourceImageId in projectResource.ImageIds)
{
Models.File image = await fileService.FindAsync(projectResourceImageId);
if(image == null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "Image was not found.",
Detail = "The specified image was not found while creating project.",
Instance = "B040FAAD-FD22-4C77-822E-C498DFA1A9CB"
};
return BadRequest(problem);
}

project.Images.Add(image);
}

project.ProjectIcon = file;
project.User = await HttpContext.GetContextUser(userService)
.ConfigureAwait(false);
Expand All @@ -373,10 +417,10 @@ await callToActionOptionService.GetCallToActionOptionFromValueAsync(

foreach(ProjectCategoryResource projectCategoryResource in projectCategoryResources)
{
ProjectCategory alreadyExcProjectCategory = await projectCategoryService.GetProjectCategory(project.Id, projectCategoryResource.CategoryId);
ProjectCategory alreadyExcProjectCategory = await projectCategoryService.GetProjectCategory(project.Id, projectCategoryResource.Id);
if(alreadyExcProjectCategory == null)
{
Category category = await categoryService.FindAsync(projectCategoryResource.CategoryId);
Category category = await categoryService.FindAsync(projectCategoryResource.Id);

if(category == null)
{
Expand Down Expand Up @@ -491,8 +535,7 @@ await callToActionOptionService.GetCallToActionOptionFromValueAsync(
ProblemDetails problem = new ProblemDetails
{
Title = "Call to action value was not found.",
Detail =
"The specified call to action value was not found while creating the project.",
Detail = "The specified call to action value was not found while creating the project.",
Instance = "40EE82EB-930F-40C8-AE94-0041F7573FE9"
};
return BadRequest(problem);
Expand All @@ -511,15 +554,15 @@ await callToActionOptionService.GetCallToActionOptionFromValueAsync(
}

// Upload the new file if there is one
File file = null;
Models.File file = null;
if(projectResource.FileId != 0)
{
if(project.ProjectIconId != 0 &&
project.ProjectIconId != null)
{
if(project.ProjectIconId != projectResource.FileId)
{
File fileToDelete = await fileService.FindAsync(project.ProjectIconId.Value);
Models.File fileToDelete = await fileService.FindAsync(project.ProjectIconId.Value);

// Remove the file from the filesystem
fileUploader.DeleteFileFromDirectory(fileToDelete);
Expand Down Expand Up @@ -550,17 +593,34 @@ await callToActionOptionService.GetCallToActionOptionFromValueAsync(
}
}

foreach(int projectResourceImageId in projectResource.ImageIds)
{
Models.File image = await fileService.FindAsync(projectResourceImageId);
if(image == null)
{
ProblemDetails problem = new ProblemDetails
{
Title = "Image was not found.",
Detail = "The specified image was not found while creating project.",
Instance = "FC816E40-31A6-4187-BEBA-D22F06019F8F"
};
return BadRequest(problem);
}

project.Images.Add(image);
}

await projectCategoryService.ClearProjectCategories(project);
if(projectResource.Categories != null)
{
ICollection<ProjectCategoryResource> projectCategoryResources = projectResource.Categories;

foreach(ProjectCategoryResource projectCategoryResource in projectCategoryResources)
{
ProjectCategory alreadyExcProjectCategory = await projectCategoryService.GetProjectCategory(project.Id, projectCategoryResource.CategoryId);
ProjectCategory alreadyExcProjectCategory = await projectCategoryService.GetProjectCategory(project.Id, projectCategoryResource.Id);
if(alreadyExcProjectCategory == null)
{
Category category = await categoryService.FindAsync(projectCategoryResource.CategoryId);
Category category = await categoryService.FindAsync(projectCategoryResource.Id);

if(category == null)
{
Expand Down Expand Up @@ -639,7 +699,7 @@ public async Task<IActionResult> DeleteProject(int projectId)
if(project.ProjectIconId.HasValue)
{
// We need to delete the old file.
File fileToDelete = await fileService.FindAsync(project.ProjectIconId.Value);
Models.File fileToDelete = await fileService.FindAsync(project.ProjectIconId.Value);
try
{
// Remove the file from the database
Expand Down
Loading

0 comments on commit a98bb8d

Please sign in to comment.