Skip to content

Commit ba901d9

Browse files
committed
- Added details xml comments in Controllers
- Added 2.2 feature: Api Analyzer - Refactor responses in Login and Log List - Added Utls folder for shared extensions / classes - Added warn filter in csproj - Updated swagger configurations
1 parent 9e69a56 commit ba901d9

22 files changed

+228
-87
lines changed

src/Api/Features/Accounts/AccountsController.cs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
using MediatR;
77
using System.Security.Claims;
88
using Microsoft.AspNetCore.Http;
9+
using WebApi.Features.Employees;
10+
using WebApi.Utils;
911

1012
namespace WebApi.Features.Accounts
1113
{
@@ -23,19 +25,28 @@ public AccountsController(IMediator mediator, IHttpContextAccessor httpContext)
2325
}
2426

2527
// POST: api/accounts/register
28+
/// <summary>
29+
/// Register new employee
30+
/// </summary>
31+
/// <remarks>
32+
/// Unique card no. and username filter will be applied
33+
/// </remarks>
34+
/// <param name="viewModel"></param>
2635
[Authorize(Roles = "Admin")]
2736
[HttpPost("register")]
37+
[ProducesResponseType(typeof(EmployeeViewModel), StatusCodes.Status201Created)]
38+
[ProducesResponseType(typeof(ErrorHandler), StatusCodes.Status400BadRequest)]
2839
public async Task<IActionResult> Register(RegisterViewModel viewModel)
2940
{
3041
// mediator from Features/Employees
3142
var isCardExist = await _mediator.Send(new Employees.IsCardExists.Query(Guid.Empty, viewModel.CardNo));
3243
if (isCardExist)
33-
return BadRequest("Card No. is already in use");
44+
return BadRequest(new ErrorHandler{ Description = "Card No. is already in use" });
3445

3546
// mediator from Features/Employees
3647
var isUsernameExist = await _mediator.Send(new Auth.IsUserExists.Query(viewModel.UserName));
3748
if (isUsernameExist)
38-
return BadRequest($"Username {viewModel.UserName} is already taken");
49+
return BadRequest(new ErrorHandler{ Description = $"Username {viewModel.UserName} is already taken" });
3950

4051
// Create user account
4152
var employeeInfo = await _mediator.Send(new Register.Command(viewModel));
@@ -44,32 +55,44 @@ public async Task<IActionResult> Register(RegisterViewModel viewModel)
4455
}
4556

4657
// PUT: api/accounts/update-password
58+
/// <summary>
59+
/// Update an Employee password
60+
/// </summary>
61+
/// <param name="viewModel"></param>
4762
[Authorize(Roles = "Admin")]
4863
[HttpPut("update-password")]
64+
[ProducesResponseType(StatusCodes.Status200OK)]
65+
[ProducesResponseType(typeof(ErrorHandler), StatusCodes.Status400BadRequest)]
4966
public async Task<IActionResult> UpdatePassword(UpdatePasswordViewModel viewModel)
5067
{
5168
// Change a specific Employee account's password
5269
var result = await _mediator.Send(new UpdatePassword.Command(viewModel));
5370
if (!result)
54-
return BadRequest();
71+
return BadRequest(new ErrorHandler{ Description = "Unable to update password." });
5572

5673
return Ok();
5774
}
5875

5976
// PUT: api/accounts/change-password
77+
/// <summary>
78+
/// Update your current password
79+
/// </summary>
80+
/// <param name="viewModel"></param>
6081
[HttpPut("change-password")]
82+
[ProducesResponseType(StatusCodes.Status200OK)]
83+
[ProducesResponseType(typeof(ErrorHandler), StatusCodes.Status400BadRequest)]
6184
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel viewModel)
6285
{
6386
// Check if Old password is correct
6487
var currentUser = _httpContext.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
6588
var validatePassword = await _mediator.Send(new Auth.ValidatePassword.Query(currentUser, viewModel.OldPassword));
6689
if (!validatePassword)
67-
return BadRequest("Incorrect password");
90+
return BadRequest(new ErrorHandler{ Description = "Incorrect password." });
6891

6992
// Change account password
7093
var result = await _mediator.Send(new ChangePassword.Command(viewModel));
7194
if (!result.Succeeded)
72-
return BadRequest("Unable to change password");
95+
return BadRequest(new ErrorHandler{ Description = "Unable to change password." });
7396

7497
return Ok();
7598
}

src/Api/Features/Accounts/ChangePassword.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@
1010

1111
namespace WebApi.Features.Accounts
1212
{
13-
/// <summary>
14-
/// Change account password
15-
/// </summary>
1613
public class ChangePassword
1714
{
1815
public class Command : IRequest<IdentityResult>

src/Api/Features/Accounts/Register.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99

1010
namespace WebApi.Features.Accounts
1111
{
12-
/// <summary>
13-
/// Create employee account
14-
/// </summary>
1512
public class Register
1613
{
1714
public class Command : IRequest<EmployeeViewModel>

src/Api/Features/Accounts/UpdatePassword.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99

1010
namespace WebApi.Features.Accounts
1111
{
12-
/// <summary>
13-
/// Change a specific Employee account's password
14-
/// </summary>
1512
public class UpdatePassword
1613
{
1714
public class Command : IRequest<bool>

src/Api/Features/Auth/AuthController.cs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using Microsoft.AspNetCore.Authorization;
44
using MediatR;
55
using Microsoft.AspNetCore.Http;
6+
using WebApi.Utils;
67

78
namespace WebApi.Features.Auth
89
{
@@ -19,14 +20,19 @@ public AuthController(IMediator mediator, IHttpContextAccessor httpContext)
1920
}
2021

2122
// POST api/auth/login
23+
/// <summary>
24+
/// Login endpoint that produces Json Web Token
25+
/// </summary>
26+
/// <param name="viewModel"></param>
2227
[HttpPost("login")]
23-
// [ValidateAntiForgeryToken]
24-
public async Task<IActionResult> Login(LoginViewModel viewModel)
28+
[ProducesResponseType(typeof(LoginResponse), StatusCodes.Status200OK)]
29+
[ProducesResponseType(typeof(ErrorHandler), StatusCodes.Status400BadRequest)]
30+
public async Task<ActionResult<LoginResponse>> Login(LoginViewModel viewModel)
2531
{
2632
// Check if credentials are correct
2733
var validate = await _mediator.Send(new ValidatePassword.Query(viewModel.UserName, viewModel.Password));
2834
if (!validate)
29-
return BadRequest("Invalid username or password");
35+
return BadRequest(new ErrorHandler{ Description = "Invalid username or password." });
3036

3137
// Get User Claims
3238
var claimsIdentity = await _mediator.Send(new GetRoleClaimsIdentity.Command(viewModel));
@@ -41,8 +47,15 @@ await _mediator.Send(new GenerateAccessToken.Command(claimsIdentity, employee, v
4147
}
4248

4349
// POST api/challenge/{role}
50+
/// <summary>
51+
/// Validate the bearer token
52+
/// </summary>
53+
/// <param name="role"></param>
54+
/// <returns></returns>
4455
[Authorize]
4556
[HttpPost("challenge/{role?}")]
57+
[ProducesResponseType(StatusCodes.Status200OK)]
58+
[ProducesResponseType(StatusCodes.Status403Forbidden)]
4659
public IActionResult ChallengeAuth(string role)
4760
{
4861
if(!string.IsNullOrEmpty(role))
@@ -55,13 +68,13 @@ public IActionResult ChallengeAuth(string role)
5568
return Ok();
5669
}
5770

58-
// GET api/auth/xsrfToken
59-
[HttpGet("xsrfToken")]
60-
public IActionResult XsrfToken()
61-
{
62-
return new OkObjectResult(
63-
_mediator.Send(new GenerateXsrfToken.Query(HttpContext))
64-
);
65-
}
71+
// // GET api/auth/xsrfToken
72+
// [HttpGet("xsrfToken")]
73+
// public IActionResult XsrfToken()
74+
// {
75+
// return new OkObjectResult(
76+
// _mediator.Send(new GenerateXsrfToken.Query(HttpContext))
77+
// );
78+
// }
6679
}
6780
}

src/Api/Features/Auth/GenerateAccessToken.cs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace WebApi.Features.Auth
1313
{
1414
public class GenerateAccessToken
1515
{
16-
public class Command : IRequest<Object>
16+
public class Command : IRequest<LoginResponse>
1717
{
1818
public Command(
1919
ClaimsIdentity claimsIdentity,
@@ -30,7 +30,7 @@ public Command(
3030
public string Uername { get; }
3131
}
3232

33-
public class CommandHandler : IRequestHandler<Command, Object>
33+
public class CommandHandler : IRequestHandler<Command, LoginResponse>
3434
{
3535
private readonly JwtIssuerOptions _jwtOptions;
3636

@@ -40,26 +40,24 @@ public CommandHandler(IOptions<JwtIssuerOptions> jwtOptions)
4040
Extensions.ThrowIfInvalidOptions(_jwtOptions);
4141
}
4242

43-
public async Task<object> Handle(Command request, CancellationToken cancellationToken)
43+
public async Task<LoginResponse> Handle(Command request, CancellationToken cancellationToken)
4444
{
4545
try
4646
{
47-
var response = new
47+
return new LoginResponse
4848
{
49-
user = new
49+
User = new UserDetails
5050
{
51-
empId = (request.Employee.Id != Guid.Empty) ? request.Employee.Id: Guid.Empty,
52-
fullName = request.Employee.FullName,
53-
username = request.Uername,
54-
roles = request.ClaimsIdentity.Claims.Where(c => c.Type == ClaimTypes.Role)
55-
.Select(c => c.Value)
56-
.ToList()
51+
EmployeeId = (request.Employee.Id != Guid.Empty) ? request.Employee.Id: Guid.Empty,
52+
FullName = request.Employee.FullName,
53+
UserName = request.Uername,
54+
Roles = request.ClaimsIdentity.Claims.Where(c => c.Type == ClaimTypes.Role)
55+
.Select(c => c.Value)
56+
.ToList()
5757
},
58-
access_token = await GenerateEncodedToken(request.Uername, request.ClaimsIdentity),
59-
expires_in = (int)_jwtOptions.ValidFor.TotalSeconds
58+
AccessToken = await GenerateEncodedToken(request.Uername, request.ClaimsIdentity),
59+
ExpiresIn = (int) _jwtOptions.ValidFor.TotalSeconds
6060
};
61-
62-
return response;
6361
}
6462
catch (Exception e)
6563
{
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Newtonsoft.Json;
4+
5+
namespace WebApi.Features.Auth
6+
{
7+
public class LoginResponse
8+
{
9+
[JsonProperty("user")]
10+
public UserDetails User { get; set; }
11+
12+
[JsonProperty("access_token")]
13+
public string AccessToken { get; set; }
14+
15+
[JsonProperty("expires_in")]
16+
public int ExpiresIn { get; set; }
17+
}
18+
19+
public class UserDetails
20+
{
21+
[JsonProperty("empId")]
22+
public Guid EmployeeId { get; set; }
23+
[JsonProperty("fullName")]
24+
public string FullName { get; set; }
25+
[JsonProperty("username")]
26+
public string UserName { get; set; }
27+
[JsonProperty("roles")]
28+
public List<string> Roles { get; set; }
29+
}
30+
}

src/Api/Features/Config/ConfigController.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using Microsoft.AspNetCore.Mvc;
33
using Microsoft.AspNetCore.Authorization;
44
using MediatR;
5+
using Microsoft.AspNetCore.Http;
6+
using WebApi.Utils;
57

68
namespace WebApi.Features.Config
79
{
@@ -17,20 +19,30 @@ public ConfigController(IMediator mediator)
1719
}
1820

1921
// GET api/config
22+
/// <summary>
23+
/// Get current atendance config
24+
/// </summary>
2025
[HttpGet]
26+
[ProducesResponseType(typeof(ConfigViewModel), StatusCodes.Status200OK)]
2127
public async Task<ConfigViewModel> Index()
2228
{
2329
return await _mediator.Send(new Details.Query());
2430
}
2531

2632
// PUT api/config
33+
/// <summary>
34+
/// Update attendance config
35+
/// </summary>
36+
/// <param name="viewModel"></param>
2737
[Authorize(Roles = "Admin")]
2838
[HttpPut]
39+
[ProducesResponseType(StatusCodes.Status200OK)]
40+
[ProducesResponseType(typeof(ErrorHandler), StatusCodes.Status400BadRequest)]
2941
public async Task<ActionResult<ConfigViewModel>> Update(ConfigViewModel viewModel)
3042
{
3143
string message;
3244
if (Extensions.ValidateTimeStrings(viewModel, out message))
33-
return BadRequest(message);
45+
return BadRequest(new ErrorHandler{ Description = message });
3446

3547
return await _mediator.Send(new Update.Command(viewModel));
3648
}

src/Api/Features/Config/Details.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88

99
namespace WebApi.Features.Config
1010
{
11-
/// <summary>
12-
/// Get current attendance config
13-
/// </summary>
1411
public class Details
1512
{
1613
public class Query : IRequest<ConfigViewModel> { }

src/Api/Features/Config/Update.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88

99
namespace WebApi.Features.Config
1010
{
11-
/// <summary>
12-
/// Update attendance config
13-
/// </summary>
1411
public class Update
1512
{
1613
public class Command : IRequest<ConfigViewModel>

0 commit comments

Comments
 (0)