Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion docker-compose.test.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,7 @@ services:
ports:
- '8888:80'
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_ENVIRONMENT=Testing
- PROFILE_DatabaseSettings__ConnectionString=Server=database;Port=5432;Database=mytestdb;User ID=profiletester;Password=supasupasecured;
depends_on:
database:
Expand Down
1 change: 1 addition & 0 deletions src/Api/Api.csproj
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<ItemGroup>
Expand Down
15 changes: 14 additions & 1 deletion src/Api/ConfigureServices.cs
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
using System.Reflection;
using Api.Middlewares;
using Api.Policies;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.OpenApi.Models;

namespace Api;

Expand DownExpand Up@@ -31,7 +33,18 @@ public static IServiceCollection AddApiServices(this IServiceCollection services

// For swagger
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "ProFile API",
Description = "An ASP.NET Core Web API for managing documents",
});

var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
});

return services;
}
Expand Down
54 changes: 36 additions & 18 deletions src/Api/Controllers/AuthController.cs
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Authentication;
using Api.Controllers.Payload.Requests;
using Api.Controllers.Payload.Requests.Auth;
using Api.Controllers.Payload.Responses;
using Application.Common.Interfaces;
using Application.Common.Models;
Expand All@@ -23,6 +23,11 @@ public AuthController(IIdentityService identityService)
_identityService = identityService;
}

/// <summary>
/// Login
/// </summary>
/// <param name="loginModel">Login credentials</param>
/// <returns>A LoginResult indicating the result of logging in</returns>
[AllowAnonymous]
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
Expand All@@ -48,23 +53,11 @@ public async Task<ActionResult<Result<LoginResult>>> Login([FromBody] LoginModel

return Ok(Result<LoginResult>.Succeed(loginResult));
}

[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Logout()
{
var refreshToken = Request.Cookies[nameof(RefreshToken)];
var jweToken = Request.Cookies["JweToken"];

RemoveJweToken();
RemoveRefreshToken();

await _identityService.LogoutAsync(jweToken!, refreshToken!);

return Ok();
}


/// <summary>
/// Refresh session and token
/// </summary>
/// <returns>An IActionResult indicating the result of refreshing token</returns>
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
Expand All@@ -90,6 +83,10 @@ public async Task<IActionResult> Refresh()
return Ok();
}

/// <summary>
/// Validate current user
/// </summary>
/// <returns>An IActionResult indicating the result of validating the user</returns>
[Authorize]
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
Expand All@@ -99,11 +96,32 @@ public IActionResult Validate()
return Ok();
}

/// <summary>
/// Logout of the system
/// </summary>
/// <returns>An IActionResult indicating the result of logging out of the system</returns>
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> Logout()
{
var refreshToken = Request.Cookies[nameof(RefreshToken)];
var jweToken = Request.Cookies["JweToken"];

RemoveJweToken();
RemoveRefreshToken();

await _identityService.LogoutAsync(jweToken!, refreshToken!);

return Ok();
}

private void SetJweToken(SecurityToken jweToken, RefreshTokenDto newRefreshToken)
{
var cookieOptions = new CookieOptions
{
HttpOnly = true,
Expires = newRefreshToken.ExpiryDateTime
};
var handler = new JwtSecurityTokenHandler();
Response.Cookies.Append("JweToken", handler.WriteToken(jweToken), cookieOptions);
Expand Down
65 changes: 34 additions & 31 deletions src/Api/Controllers/DepartmentsController.cs
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
using Api.Controllers.Payload.Requests;
using Api.Controllers.Payload.Requests.Departments;
using Application.Common.Models;
using Application.Departments.Commands.DeleteDepartment;
using Application.Departments.Commands.UpdateDepartment;
using Application.Departments.Commands.AddDepartment;
using Application.Departments.Queries.GetAllDepartments;
using Application.Departments.Queries.GetDepartmentById;
using Application.Common.Models.Dtos;
using Application.Departments.Commands;
using Application.Departments.Queries;
using Application.Identity;
using Application.Users.Queries;
using Infrastructure.Identity.Authorization;
Expand All@@ -15,52 +13,57 @@ namespace Api.Controllers;
public class DepartmentsController : ApiControllerBase
{
/// <summary>
/// Create a department
/// Get back a department based on its id
/// </summary>
/// <param name="command">command parameter to create a department</param>
/// <returns>Result[DepartmentDto]</returns>
[RequiresRole(IdentityData.Roles.Admin)]
[HttpPost]
/// <param name="departmentId">id of the department to be retrieved</param>
/// <returns>A DepartmentDto of the retrieved department</returns>
[HttpGet("{departmentId:guid}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<ActionResult<Result<DepartmentDto>>> AddDepartment([FromBody] AddDepartmentCommand command)
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Result<DepartmentDto>>> GetById([FromRoute] Guid departmentId)
{
var result = await Mediator.Send(command);
var query = new GetDepartmentById.Query()
{
DepartmentId = departmentId
};
var result = await Mediator.Send(query);
return Ok(Result<DepartmentDto>.Succeed(result));
}

/// <summary>
/// Get all documents
/// </summary>
/// <returns>a Result of an IEnumerable of DepartmentDto</returns>
/// <returns>A list of DocumentDto</returns>
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<Result<IEnumerable<DepartmentDto>>>> GetAllDepartments()
public async Task<ActionResult<Result<IEnumerable<DepartmentDto>>>> GetAll()
{
var result = await Mediator.Send(new GetAllDepartmentsQuery());
var result = await Mediator.Send(new GetAllDepartments.Query());
return Ok(Result<IEnumerable<DepartmentDto>>.Succeed(result));
}

/// <summary>
/// Get back a department based on its id
/// Add a department
/// </summary>
/// <param name="departmentId">id of the department to be retrieved</param>
/// <returns>A DepartmentDto of the retrieved department</returns>
[HttpGet("{departmentId:guid}")]
/// <param name="request">Add department details</param>
/// <returns>A DepartmentDto of the the added department</returns>
[RequiresRole(IdentityData.Roles.Admin)]
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<Result<DepartmentDto>>> GetDepartmentById([FromRoute] Guid departmentId)
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<ActionResult<Result<DepartmentDto>>> Add([FromBody] AddDepartmentRequest request)
{
var query = new GetDepartmentByIdQuery()
var command = new AddDepartment.Command()
{
DepartmentId = departmentId
Name = request.Name,
};
var result = await Mediator.Send(query);
var result = await Mediator.Send(command);
return Ok(Result<DepartmentDto>.Succeed(result));
}

/// <summary>
/// Update a department
/// </summary>
Expand All@@ -72,9 +75,9 @@ public async Task<ActionResult<Result<DepartmentDto>>> GetDepartmentById([FromRo
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Result<DepartmentDto>>> UpdateDepartment([FromRoute] Guid departmentId, [FromBody] UpdateDepartmentRequest request)
public async Task<ActionResult<Result<DepartmentDto>>> Update([FromRoute] Guid departmentId, [FromBody] UpdateDepartmentRequest request)
{
var command = new UpdateDepartmentCommand()
var command = new UpdateDepartment.Command()
{
DepartmentId = departmentId,
Name = request.Name
Expand All@@ -93,9 +96,9 @@ public async Task<ActionResult<Result<DepartmentDto>>> UpdateDepartment([FromRou
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Result<DepartmentDto>>> DeleteDepartment([FromRoute] Guid departmentId)
public async Task<ActionResult<Result<DepartmentDto>>> Delete([FromRoute] Guid departmentId)
{
var command = new DeleteDepartmentCommand()
var command = new DeleteDepartment.Command()
{
DepartmentId = departmentId,
};
Expand Down
Loading