feat(storage-service): Add Social Service to Docker Compose and enhance IAM service integration
- Introduced a new social-service in the Docker Compose configuration for local development, including build context, environment variables, and health checks. - Updated architecture documentation to reflect the new storage service structure and its components, including user storage quotas and file management. - Enhanced README files to provide clearer instructions on service setup, configuration, and API endpoints for file storage management. - Implemented caching mechanisms in the IAM service client for improved performance and reduced latency in user information retrieval. - Updated appsettings for development to include caching settings for IAM service interactions.
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
using Asp.Versioning;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MembershipService.API.Application.Commands;
|
||||
using MembershipService.API.Application.Queries;
|
||||
using Swashbuckle.AspNetCore.Annotations;
|
||||
|
||||
namespace MembershipService.API.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// EN: Controller for managing members.
|
||||
/// VI: Controller để quản lý members.
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[Authorize]
|
||||
[SwaggerTag("Member management endpoints")]
|
||||
public class MembersController : ControllerBase
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
private readonly ILogger<MembersController> _logger;
|
||||
|
||||
public MembersController(IMediator mediator, ILogger<MembersController> logger)
|
||||
{
|
||||
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: Get member by ID.
|
||||
/// VI: Lấy member theo ID.
|
||||
/// </summary>
|
||||
[HttpGet("{id:guid}")]
|
||||
[SwaggerOperation(Summary = "Get member by ID", Description = "Retrieves a member by their unique identifier")]
|
||||
[SwaggerResponse(200, "Member found", typeof(MemberDto))]
|
||||
[SwaggerResponse(404, "Member not found")]
|
||||
[SwaggerResponse(401, "Unauthorized")]
|
||||
public async Task<ActionResult<MemberDto>> GetById(Guid id)
|
||||
{
|
||||
var member = await _mediator.Send(new GetMemberByIdQuery(id));
|
||||
if (member == null)
|
||||
{
|
||||
return NotFound(new { message = $"Member {id} not found" });
|
||||
}
|
||||
return Ok(member);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: Get current user's member profile.
|
||||
/// VI: Lấy profile member của user hiện tại.
|
||||
/// </summary>
|
||||
[HttpGet("me")]
|
||||
[SwaggerOperation(Summary = "Get my member profile", Description = "Retrieves the member profile for the authenticated user")]
|
||||
[SwaggerResponse(200, "Member found", typeof(MemberDto))]
|
||||
[SwaggerResponse(404, "Member not found")]
|
||||
[SwaggerResponse(401, "Unauthorized")]
|
||||
public async Task<ActionResult<MemberDto>> GetMe()
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
var member = await _mediator.Send(new GetMemberByIdQuery(userId.Value));
|
||||
if (member == null)
|
||||
{
|
||||
return NotFound(new { message = "Member profile not found" });
|
||||
}
|
||||
return Ok(member);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: Get paginated list of members.
|
||||
/// VI: Lấy danh sách members phân trang.
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[SwaggerOperation(Summary = "Get members list", Description = "Retrieves a paginated list of members")]
|
||||
[SwaggerResponse(200, "Members retrieved", typeof(GetMembersResult))]
|
||||
[SwaggerResponse(401, "Unauthorized")]
|
||||
public async Task<ActionResult<GetMembersResult>> GetAll(
|
||||
[FromQuery] int pageIndex = 0,
|
||||
[FromQuery] int pageSize = 10,
|
||||
[FromQuery] string? search = null)
|
||||
{
|
||||
var result = await _mediator.Send(new GetMembersQuery
|
||||
{
|
||||
PageIndex = pageIndex,
|
||||
PageSize = pageSize,
|
||||
SearchTerm = search
|
||||
});
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: Create a new member.
|
||||
/// VI: Tạo member mới.
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[SwaggerOperation(Summary = "Create member", Description = "Creates a new member profile")]
|
||||
[SwaggerResponse(201, "Member created", typeof(CreateMemberResult))]
|
||||
[SwaggerResponse(400, "Invalid request")]
|
||||
[SwaggerResponse(409, "Member already exists")]
|
||||
[SwaggerResponse(401, "Unauthorized")]
|
||||
public async Task<ActionResult<CreateMemberResult>> Create([FromBody] CreateMemberCommand command)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return CreatedAtAction(nameof(GetById), new { id = result.MemberId }, result);
|
||||
}
|
||||
catch (InvalidOperationException ex) when (ex.Message.Contains("already exists"))
|
||||
{
|
||||
return Conflict(new { message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: Update member profile.
|
||||
/// VI: Cập nhật profile member.
|
||||
/// </summary>
|
||||
[HttpPut("{id:guid}")]
|
||||
[SwaggerOperation(Summary = "Update member profile", Description = "Updates a member's profile information")]
|
||||
[SwaggerResponse(200, "Member updated", typeof(UpdateMemberProfileResult))]
|
||||
[SwaggerResponse(400, "Invalid request")]
|
||||
[SwaggerResponse(404, "Member not found")]
|
||||
[SwaggerResponse(401, "Unauthorized")]
|
||||
public async Task<ActionResult<UpdateMemberProfileResult>> UpdateProfile(
|
||||
Guid id,
|
||||
[FromBody] UpdateMemberProfileCommand command)
|
||||
{
|
||||
command.MemberId = id;
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
}
|
||||
catch (KeyNotFoundException ex)
|
||||
{
|
||||
return NotFound(new { message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EN: Change membership level.
|
||||
/// VI: Thay đổi cấp thành viên.
|
||||
/// </summary>
|
||||
[HttpPut("{id:guid}/level")]
|
||||
[SwaggerOperation(Summary = "Change membership level", Description = "Changes a member's membership level")]
|
||||
[SwaggerResponse(200, "Level changed", typeof(ChangeMembershipLevelResult))]
|
||||
[SwaggerResponse(400, "Invalid request")]
|
||||
[SwaggerResponse(404, "Member not found")]
|
||||
[SwaggerResponse(401, "Unauthorized")]
|
||||
public async Task<ActionResult<ChangeMembershipLevelResult>> ChangeLevel(
|
||||
Guid id,
|
||||
[FromBody] ChangeMembershipLevelCommand command)
|
||||
{
|
||||
command.MemberId = id;
|
||||
|
||||
try
|
||||
{
|
||||
var result = await _mediator.Send(command);
|
||||
return Ok(result);
|
||||
}
|
||||
catch (KeyNotFoundException ex)
|
||||
{
|
||||
return NotFound(new { message = ex.Message });
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
private Guid? GetCurrentUserId()
|
||||
{
|
||||
var userIdClaim = User.FindFirst("sub")?.Value ?? User.FindFirst("id")?.Value;
|
||||
if (Guid.TryParse(userIdClaim, out var userId))
|
||||
{
|
||||
return userId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user