Skip to content

Commit

Permalink
Merge pull request #70 from TunNetCom/add-change-password
Browse files Browse the repository at this point in the history
Replace controller with minimal API and add change password
  • Loading branch information
MarwenSaad authored Oct 29, 2024
2 parents f050edf + 822017e commit 4ce6d60
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 60 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
global using IdentityService.Application;
global using IdentityService.Application.Features.AddRole;
global using IdentityService.Application.Features.AttachUserToRole;
global using IdentityService.Application.Features.ChangePassword;
global using IdentityService.Application.Features.CreateAccount;
global using IdentityService.Application.Features.Login;
global using IdentityService.Contracts;
Expand Down
64 changes: 64 additions & 0 deletions src/TimeLogIdentityService/IdentityService.API/IdentityEndPoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

namespace IdentityService.API;

public static class IdentityEndPoint
{
public static void AddEndpoints(this IEndpointRouteBuilder app)
{
_ = app.MapPost("/CreateAccount", async (IMediator _mediator, [FromBody] CreateAccountCommand request) =>
{
IdentityResult userResponse = await _mediator.Send(request);
if (!userResponse.Succeeded)
{
return Results.BadRequest(userResponse);
}
return Results.Ok(userResponse);
});

_ = app.MapPost("/Login", async (IMediator _mediator, [FromBody] LoginCommand request) =>
{
ApiResponse<LoginResponse> userResponse = await _mediator.Send(request);
if (!userResponse.Succeeded)
{
return Results.BadRequest(userResponse);
}
return Results.Ok(userResponse);
});

_ = app.MapPost("/AddRole", async (IMediator _mediator, [FromBody] AddRoleCommand request) =>
{
IdentityResult roleResponse = await _mediator.Send(request);
if (!roleResponse.Succeeded)
{
return Results.BadRequest(roleResponse);
}
return Results.Ok(roleResponse);
});

_ = app.MapPost("/AttachUserToRole", async (IMediator _mediator, [FromBody] AttachUserToRoleCommand request) =>
{
ApiResponse<UserToRoleResponse> response = await _mediator.Send(request);
if (!response.Succeeded)
{
return Results.BadRequest(response);
}
return Results.Ok(response);
});

_ = app.MapPost("/ChangePassword", async (IMediator _mediator, [FromBody] ChangePasswordCommand request) =>
{
ApiResponse response = await _mediator.Send(request);
if (!response.Succeeded)
{
return Results.BadRequest(response);
}
return Results.Ok(response);
});
}
}
1 change: 1 addition & 0 deletions src/TimeLogIdentityService/IdentityService.API/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
_ = app.UseAuthorization();

_ = app.MapControllers();
app.AddEndpoints();

app.Run();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using IdentityService.Contracts.Constant;

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace IdentityService.Application.Features.AttachUserToRole;

Expand All @@ -18,8 +20,8 @@ public async Task<ApiResponse<UserToRoleResponse>> Handle(
Error = new ProblemDetails()
{
Status = 404,
Title = "NotFound",
Detail = "User not found",
Title = nameof(ErrorDetails.UserNotFound),
Detail = ErrorDetails.UserNotFound,
},
};
}
Expand All @@ -29,16 +31,16 @@ public async Task<ApiResponse<UserToRoleResponse>> Handle(
{
return new ApiResponse<UserToRoleResponse>()
{
Success = false,
Succeeded = false,
Error = new ProblemDetails()
{
Status = 400,
Title = "RoleAssignmentFailed",
Title = nameof(ErrorDetails.RoleAssignmentFailed),
Detail = string.Join(", ", result.Errors.Select(e => e.Description)),
},
};
}

return new ApiResponse<UserToRoleResponse>() { Success = true, };
return new ApiResponse<UserToRoleResponse>() { Succeeded = true, };
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace IdentityService.Application.Features.ChangePassword
{
public record class ChangePasswordCommand(string OldPassword, string NewPassword, string Email) : IRequest<ApiResponse>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using IdentityService.Contracts.Constant;

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member

namespace IdentityService.Application.Features.ChangePassword
{
public class ChangePasswordCommandHandler(UserManager<IdentityUser> userManager) :
IRequestHandler<ChangePasswordCommand, ApiResponse>
{
private readonly UserManager<IdentityUser> _userManager = userManager;

public async Task<ApiResponse> Handle(ChangePasswordCommand request, CancellationToken cancellationToken)
{
IdentityUser? user = await _userManager.FindByEmailAsync(request.Email);
if (user == null)
{
return new ApiResponse()
{
Succeeded = false,
Error = new ProblemDetails()
{
Title = nameof(ErrorDetails.InvalidEmail),
Detail = ErrorDetails.InvalidEmail,
Status = 404,
},
};
}

if (!await _userManager.CheckPasswordAsync(user, request.OldPassword))
{
return new ApiResponse()
{
Succeeded = false,
Error = new ProblemDetails()
{
Title = nameof(ErrorDetails.InvalidOldPassword),
Detail = ErrorDetails.InvalidOldPassword,
Status = 400,
},
};
}

_ = await _userManager.ChangePasswordAsync(user, request.OldPassword, request.NewPassword);
return new ApiResponse()
{
Succeeded = false,
};
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using IdentityService.Contracts.Constant;

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace IdentityService.Application.Features.Login;

Expand All @@ -14,11 +16,11 @@ public async Task<ApiResponse<LoginResponse>> Handle(LoginCommand request, Cance
{
return new ApiResponse<LoginResponse>()
{
Success = false,
Succeeded = false,
Error = new ProblemDetails()
{
Title = "InvalidEmail",
Detail = $"Email {request.Email} is invalid",
Title = nameof(ErrorDetails.InvalidEmail),
Detail = ErrorDetails.InvalidEmail,
Status = 400,
},
};
Expand All @@ -29,11 +31,11 @@ public async Task<ApiResponse<LoginResponse>> Handle(LoginCommand request, Cance
{
return new ApiResponse<LoginResponse>()
{
Success = false,
Succeeded = false,
Error = new ProblemDetails()
{
Title = "InvalidPassword",
Detail = "Password is invalid",
Title = nameof(ErrorDetails.InvalidPassword),
Detail = ErrorDetails.InvalidPassword,
Status = 400,
},
};
Expand Down Expand Up @@ -65,7 +67,7 @@ public async Task<ApiResponse<LoginResponse>> Handle(LoginCommand request, Cance

return new ApiResponse<LoginResponse>()
{
Success = true,
Succeeded = true,
Data = new LoginResponse() { Token = new JwtSecurityTokenHandler().WriteToken(token) },
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@

namespace IdentityService.Contracts;

public class ApiResponse<T>
public class ApiResponse<T>(T? data = default) : ApiResponse(data)
{
public bool Success { get; set; }

public T? Data { get; set; }

public ProblemDetails? Error { get; set; } = new();
public new T? Data { get; set; } = data;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.AspNetCore.Mvc;

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace IdentityService.Contracts
{
public class ApiResponse(object? data = null)
{
public bool Succeeded { get; set; }

public object? Data { get; set; } = data;

public ProblemDetails? Error { get; set; } = new();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.ComponentModel.DataAnnotations;
using System.Reflection;

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
namespace IdentityService.Contracts.Constant
{
public static class ErrorDetails
{
public const string InvalidUserName = "Invalid UserName";

public const string InvalidPassword = "Invalid Password";

public const string InvalidEmail = "Invalid Email";

public const string InvalidUserId = "Invalid UserId";

public const string InvalidOldPassword = "Invalid OldPassword";

public const string UserNotFound = "User Not Found";

public const string RoleNotFound = "Role Not Found";

public const string RoleAssignmentFailed = "Role Assignment Failed";
}
}

0 comments on commit 4ce6d60

Please sign in to comment.