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

Development #39

Merged
merged 11 commits into from
May 29, 2024
20 changes: 15 additions & 5 deletions src/HigiaServer.API/Endpoints/AuthenticationEndpoint.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System.Security.Claims;
using AutoMapper;

using HigiaServer.Application.Contracts.Requests;
using HigiaServer.Application.Contracts.Responses;
using HigiaServer.Application.Errors;
using HigiaServer.Application.Repositories;
using HigiaServer.Application.Services;
using HigiaServer.Domain.Entities;
using Microsoft.AspNetCore.Authentication;

namespace HigiaServer.API.Endpoints;

Expand Down Expand Up @@ -44,14 +45,23 @@ public static IEndpointRouteBuilder AddAuthenticationEndpoint(this IEndpointRout
# region private methods

private static async Task<IResult> HandleRegister(
HttpContext context,
RegisterRequest request,
IUserRepository repository,
IMapper mapper,
IJwtTokenService jwtTokenService
)
{
if (await repository.GetUserByEmail(request.Email) != null)
throw new DuplicateEmailException(request.Email);
if (!context.User!.Identity!.IsAuthenticated)
{
throw new UnauthenticatedException();
}
if (context.User.FindFirstValue(ClaimTypes.Role) != "admin")
{
throw new UnauthorizedAccessException();
}

if (await repository.GetUserByEmail(request.Email) != null) throw new DuplicateEmailException(request.Email);

request.Password = BCrypt.Net.BCrypt.HashPassword(request.Password);
var user = mapper.Map<User>(request);
Expand All @@ -75,8 +85,8 @@ IJwtTokenService jwtTokenService
{
if (await repository.GetUserByEmail(request.Email) is not { } user)
throw new EmailGivenNotFoundException(request.Email);
if (!BCrypt.Net.BCrypt.Verify(request.Password, user.Password))
throw new InvalidPasswordException();
if (!BCrypt.Net.BCrypt.Verify(request.Password, user.Password)) throw new InvalidPasswordException();

var authResponse = new AuthenticationResponse(
mapper.Map<UserResponse>(user),
Expand Down
59 changes: 31 additions & 28 deletions src/HigiaServer.API/Endpoints/TaskEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ public static class TaskEndpoint
{
public static IEndpointRouteBuilder AddTaskEndpoint(this IEndpointRouteBuilder app)
{
var authEndpoint = app.MapGroup("higia-server/api/tasks").WithTags("Tasks");
var taskEndpoint = app.MapGroup("higia-server/api/tasks").WithTags("Tasks");

// add task
authEndpoint.MapPost("/", HandleAddTask)
taskEndpoint.MapPost("/", HandleAddTask)
.WithName("Add new task")
.Produces<TaskResponse>(StatusCodes.Status201Created)
.WithOpenApi(x =>
Expand All @@ -25,7 +25,7 @@ public static IEndpointRouteBuilder AddTaskEndpoint(this IEndpointRouteBuilder a
});

// get task by id
authEndpoint.MapGet("/{taskId:guid}", HandleGetTask)
taskEndpoint.MapGet("/{taskId:guid}", HandleGetTask)
.WithName("Get task by id")
.Produces<TaskResponse>()
.WithOpenApi(x =>
Expand All @@ -35,7 +35,7 @@ public static IEndpointRouteBuilder AddTaskEndpoint(this IEndpointRouteBuilder a
});

// update status
authEndpoint.MapPatch("/{taskId:guid}/{status}", HandleUpdateTaskStatus)
taskEndpoint.MapPatch("/{taskId:guid}/{status}", HandleUpdateTaskStatus)
.WithName("Update Task Status")
.WithOpenApi(x =>
{
Expand All @@ -44,7 +44,7 @@ public static IEndpointRouteBuilder AddTaskEndpoint(this IEndpointRouteBuilder a
});

// update task info
authEndpoint.MapPut("/{taskId:guid}/info", HandleUpdateTaskInformation)
taskEndpoint.MapPut("/{taskId:guid}/info", HandleUpdateTaskInformation)
.WithName("Update Task")
.WithOpenApi(x =>
{
Expand All @@ -53,7 +53,7 @@ public static IEndpointRouteBuilder AddTaskEndpoint(this IEndpointRouteBuilder a
});

// add collaborator to task
authEndpoint.MapPatch("/{taskId:guid}/collaborators/{collaboratorId:guid}", HandleAddCollaboratorToTask)
taskEndpoint.MapPatch("/{taskId:guid}/collaborators/{collaboratorId:guid}", HandleAddCollaboratorToTask)
.WithName("Add collaborator to task")
.WithOpenApi(x =>
{
Expand All @@ -62,7 +62,7 @@ public static IEndpointRouteBuilder AddTaskEndpoint(this IEndpointRouteBuilder a
});

// delete task
authEndpoint.MapDelete("/{taskId:guid}", HandleDeleteTask)
taskEndpoint.MapDelete("/{taskId:guid}", HandleDeleteTask)
.WithName("Delete task by id")
.WithOpenApi(x =>
{
Expand All @@ -71,14 +71,16 @@ public static IEndpointRouteBuilder AddTaskEndpoint(this IEndpointRouteBuilder a
});

// remove collaborator from task
authEndpoint.MapPatch("/{taskId:guid}/{collaboratorId:guid}", HandleRemoveCollaboratorToTask)
taskEndpoint.MapPatch("/{taskId:guid}/{collaboratorId:guid}", HandleRemoveCollaboratorToTask)
.WithName("Remove collaborator to task")
.WithOpenApi(x =>
{
x.Summary = "Remove collaborator to task";
return x;
});



return app;
}

Expand All @@ -93,19 +95,19 @@ private static async Task<IResult> HandleRemoveCollaboratorToTask(
{
CheckAuthorizationAsAdministrator(context);
if (await taskRepository.GetTaskById(taskId) is not { } task)
return Results.BadRequest(new BaseSuccessResponse("The request could not be continued because no matching tasks were found", false));
return Results.BadRequest(new BaseResponse("The request could not be continued because no matching tasks were found", false));

if (await userRepository.GetUserById(collaboratorId) is not { } collaborator)
return Results.BadRequest(new BaseSuccessResponse("The request could not be continued because no matching collaborator were found", false));
return Results.BadRequest(new BaseResponse("The request could not be continued because no matching collaborator were found", false));

if (!task.Collaborators.Any(c => c.Id == collaboratorId!))
return Results.BadRequest(new BaseSuccessResponse("Unable to update task because no matching task was found", false));
return Results.BadRequest(new BaseResponse("Unable to update task because no matching task was found", false));

context.Response.Headers.Location = $"{context.Request.Scheme}://{context.Request.Host}/{context.Request.Path}/{task.Id}";
task.RemoveCollaboratorFromTask(collaborator);

taskRepository.UpdateTask(task);
return Results.Ok(new BaseSuccessResponse("Collaborator successfully removed from task"));
return Results.Ok(new BaseResponse("Collaborator successfully removed from task"));
}

private static async Task<IResult> HandleDeleteTask(
Expand All @@ -116,11 +118,11 @@ private static async Task<IResult> HandleDeleteTask(
CheckAuthorizationAsAdministrator(context);
if (await taskRepository.GetTaskById(taskId) is not { } task)
{
return Results.BadRequest(new BaseSuccessResponse("The request could not be continued because no matching tasks were found", false));
return Results.BadRequest(new BaseResponse("The request could not be continued because no matching tasks were found", false));
}

taskRepository.DeleteTask(taskId);
return Results.Ok(new BaseSuccessResponse("task deleted successfully"));
return Results.Ok(new BaseResponse("task deleted successfully"));
}

private static async Task<IResult> HandleAddCollaboratorToTask(
Expand All @@ -132,19 +134,19 @@ private static async Task<IResult> HandleAddCollaboratorToTask(
UpdateTaskRequest request)
{
CheckAuthorizationAsAdministrator(context);

if (await taskRepository.GetTaskById(taskId) is not { } task)
{
return Results.BadRequest(new BaseSuccessResponse("Unable to update task because no matching task was found", false));
}
return Results.BadRequest(new BaseResponse("Unable to update task because no matching task was found", false));

if (await userRepository.GetUserById(collaboratorId) is not { } collaborator)
{
return Results.BadRequest(new BaseSuccessResponse($"Collaborator with id {collaboratorId} was not found!", false));
}
return Results.BadRequest(new BaseResponse($"Collaborator with id {collaboratorId} was not found!", false));

if (collaborator.IsAdmin)
return Results.BadRequest(new BaseResponse("Only collaborators can be added to the task.", false));

if (task.Collaborators.Contains(collaborator))
{
return Results.BadRequest(new BaseSuccessResponse(
return Results.BadRequest(new BaseResponse(
$"The collaborator with id {collaboratorId} is already participating in this task",
false
));
Expand All @@ -155,7 +157,7 @@ private static async Task<IResult> HandleAddCollaboratorToTask(

context.Response.Headers.Location = $"{context.Request.Scheme}://{context.Request.Host}/{context.Request.Path}/{task.Id}";

return Results.Ok(new BaseSuccessResponse("collaborator successfully added to task"));
return Results.Ok(new BaseResponse("collaborator successfully added to task"));
}

private static async Task<IResult> HandleUpdateTaskInformation(
Expand All @@ -167,7 +169,7 @@ private static async Task<IResult> HandleUpdateTaskInformation(
CheckAuthorizationAsAdministrator(context);
if (await taskRepository.GetTaskById(taskId) is not { } task)
{
return Results.BadRequest(new BaseSuccessResponse("Unable to update task because no matching task was found", false));
return Results.BadRequest(new BaseResponse("Unable to update task because no matching task was found", false));
}

task.UpdateTask(
Expand All @@ -180,7 +182,7 @@ private static async Task<IResult> HandleUpdateTaskInformation(

context.Response.Headers.Location =
$"{context.Request.Scheme}://{context.Request.Host}/{context.Request.Path}/{taskId}";
return Results.Ok(new BaseSuccessResponse("task information updated successfully"));
return Results.Ok(new BaseResponse("task information updated successfully"));
}

private static async Task<IResult> HandleUpdateTaskStatus(
Expand All @@ -190,14 +192,12 @@ private static async Task<IResult> HandleUpdateTaskStatus(
ITaskRepository taskRepository)
{
CheckAuthorizationAsAdministrator(context);
if (await taskRepository.GetTaskById(taskId) is not { } task)
return Results.NoContent();
if (await taskRepository.GetTaskById(taskId) is not { } task) return Results.NoContent();

task.UpdateTaskStatus(status);
taskRepository.UpdateTask(task);

context.Response.Headers.Location =
$"{context.Request.Scheme}://{context.Request.Host}/{context.Request.Path}/{task.Id}";
context.Response.Headers.Location = "{context.Request.Scheme}://{context.Request.Host}/{context.Request.Path}/{task.Id}";
return Results.Ok("task status updated successfully");
}

Expand All @@ -221,6 +221,9 @@ await userRepository.GetUserById(id)
)
).ToList();

var hasAdmin = collaborators.FindAll(c => c.IsAdmin).ToList();
if (hasAdmin.Count != 0) return Results.BadRequest(new BaseResponse("Only collaborators can be added to the task.", false));

task.AddCollaboratorsToTask(collaborators);
taskRepository.AddTask(task);

Expand Down
56 changes: 56 additions & 0 deletions src/HigiaServer.API/Endpoints/UserEndpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using AutoMapper;

using HigiaServer.Application.Contracts.Requests;
using HigiaServer.Application.Contracts.Responses;
using HigiaServer.Application.Errors;
using HigiaServer.Application.Repositories;

namespace HigiaServer.API.Endpoints;

public static class UserEndpoint
{
public static IEndpointRouteBuilder AddUserEndpoint(this IEndpointRouteBuilder app)
{
var userEndpoint = app.MapGroup("higia-server/api/user").WithTags("User");

// update info user
userEndpoint.MapPut("/{userId:guid}", HandleUpdaterInfoUser)
.WithName("Update user information")
.WithOpenApi(x =>
{
x.Summary = "Update user information";
return x;
});

return app;
}

#region

public static async Task<IResult> HandleUpdaterInfoUser(
Guid userId,
UpdateInfoUserRequest request,
HttpContext context,
IUserRepository userRepository,
IMapper mapper
)
{
if (!context.User!.Identity!.IsAuthenticated) throw new UnauthenticatedException();
if (await userRepository.GetUserById(userId) is not { } user)
{
return Results.BadRequest(new BaseResponse($"User with id {userId} was not found!", false));
}

// update user information
user.UpdateInfoUser(
name: request.Name,
email: request.Email,
number: request.Number
);

await userRepository.UpdateUser(user);
return Results.Ok(new BaseResponse("user information updated successfully", false));
}

#endregion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations;

namespace HigiaServer.Application.Contracts.Requests;

public class UpdateInfoUserRequest(string? name, string? email, string? number)
{
public string? Name { get; private set; } = name;
[EmailAddress] public string? Email { get; private set; } = email;
public string? Number { get; private set; } = number;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace HigiaServer.Application.Contracts.Responses;

public class BaseSuccessResponse(string message, bool success = true)
public class BaseResponse(string message, bool success = true)
{
public bool Success { get; private set; } = success;
public string Message { get; private set; } = message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ public interface IUserRepository
void AddUser(User user);
Task<User?> GetUserByEmail(string email);
Task<User?> GetUserById(Guid userId);
System.Threading.Tasks.Task UpdateUser(User user);
}
Loading
Loading