diff --git a/src/HelloShop.IdentityService/Controllers/UsersController.cs b/src/HelloShop.IdentityService/Controllers/UsersController.cs index a49b30e..0108a10 100644 --- a/src/HelloShop.IdentityService/Controllers/UsersController.cs +++ b/src/HelloShop.IdentityService/Controllers/UsersController.cs @@ -1,8 +1,12 @@ using HelloShop.IdentityService.Entities; using HelloShop.IdentityService.EntityFrameworks; +using HelloShop.IdentityService.Models.Users; using HelloShop.ServiceDefaults.Authorization; +using HelloShop.ServiceDefaults.Models.Paging; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using System.Collections; // For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 @@ -14,14 +18,29 @@ namespace HelloShop.IdentityService.Controllers { [HttpGet] [Authorize(IdentityPermissions.Users.Default)] - public IEnumerable GetUsers() + public async Task>> GetUsers([FromQuery] UserListRequest model) { - return dbContext.Set(); + var userList= await dbContext.Set().Skip((model.PageNumber - 1) * model.PageSize).Take(model.PageSize).ToListAsync(); + + var result = userList.Select(e => new UserListItem + { + Id = e.Id, + UserName = e.UserName!, + PhoneNumber = e.PhoneNumber, + PhoneNumberConfirmed = e.PhoneNumberConfirmed, + Email = e.Email, + EmailConfirmed = e.EmailConfirmed, + CreationTime = e.CreationTime, + }).ToList(); + + var responseModel = new PagedResponse(result, result.Count); + + return Ok(responseModel); } [HttpGet("{id}")] [Authorize(IdentityPermissions.Users.Default)] - public async Task> GetUser(int id, [FromServices] IAuthorizationService authorizationService) + public async Task> GetUser(int id, [FromServices] IAuthorizationService authorizationService) { ResourceInfo resource = new(nameof(User), id.ToString()); @@ -31,7 +50,7 @@ namespace HelloShop.IdentityService.Controllers { return Forbid(); } - + User? user = dbContext.Set().Find(id); if (user == null) @@ -39,26 +58,70 @@ namespace HelloShop.IdentityService.Controllers return NotFound(); } - return Ok(user); + UserDetailsResponse responseModel = new() + { + Id = user.Id, + UserName = user.UserName!, + PhoneNumber = user.PhoneNumber, + PhoneNumberConfirmed = user.PhoneNumberConfirmed, + Email = user.Email, + EmailConfirmed = user.EmailConfirmed, + CreationTime = user.CreationTime, + }; + + return Ok(responseModel); } [HttpPost] [Authorize(IdentityPermissions.Users.Create)] - public void PostUser([FromBody] User value) + public async Task> PostUser([FromBody] UserCreateRequest model) { - dbContext.Add(value); - dbContext.SaveChanges(); + var user = new User + { + UserName = model.UserName, + PhoneNumber = model.PhoneNumber, + Email = model.Email + }; + + await dbContext.AddAsync(user); + await dbContext.SaveChangesAsync(); + + UserDetailsResponse responseModel = new() + { + Id = user.Id, + UserName = user.UserName, + PhoneNumber = user.PhoneNumber, + PhoneNumberConfirmed = user.PhoneNumberConfirmed, + Email = user.Email, + EmailConfirmed = user.EmailConfirmed, + CreationTime = user.CreationTime, + }; + + return CreatedAtAction(nameof(GetUser), new { id = user.Id }, responseModel); } + [HttpPut("{id}")] [Authorize(IdentityPermissions.Users.Update)] - public void PutUser(int id, [FromBody] User value) + public async Task PutUser(int id, [FromBody] UserUpdateRequest model) { + if (model.Id != id) + { + throw new ArgumentException("Id mismatch", nameof(model)); + } + var user = dbContext.Set().Find(id); + if (user != null) { - dbContext.SaveChanges(); + user.UserName = model.UserName; + user.PhoneNumber = model.PhoneNumber; + user.Email = model.Email; } + + await dbContext.SaveChangesAsync(); + + return Ok(); } [HttpDelete("{id}")] @@ -84,11 +147,13 @@ namespace HelloShop.IdentityService.Controllers return Unauthorized(); } - [HttpGet(nameof(Bar))] - [Authorize(IdentityPermissions.Users.Create)] - public IActionResult Bar() + [HttpDelete] + [Authorize(IdentityPermissions.Users.Delete)] + public async Task DeleteUsers(IEnumerable ids) { - return Ok("Hello, World!"); + await dbContext.Set().Where(e => ids.Contains(e.Id)).ExecuteDeleteAsync(); + + return NoContent(); } } } diff --git a/src/HelloShop.IdentityService/Models/Users/UserCreateRequest.cs b/src/HelloShop.IdentityService/Models/Users/UserCreateRequest.cs new file mode 100644 index 0000000..7b9c144 --- /dev/null +++ b/src/HelloShop.IdentityService/Models/Users/UserCreateRequest.cs @@ -0,0 +1,12 @@ +namespace HelloShop.IdentityService.Models.Users; + +public class UserCreateRequest +{ + public required string UserName { get; init; } + + public string? PhoneNumber { get; set; } + + public string? Email { get; set; } + + public required string Password { get; init; } +} diff --git a/src/HelloShop.IdentityService/Models/Users/UserDetailsResponse.cs b/src/HelloShop.IdentityService/Models/Users/UserDetailsResponse.cs new file mode 100644 index 0000000..d325de3 --- /dev/null +++ b/src/HelloShop.IdentityService/Models/Users/UserDetailsResponse.cs @@ -0,0 +1,20 @@ +namespace HelloShop.IdentityService.Models.Users; + +public class UserDetailsResponse +{ + public int Id { get; init; } + + public required string UserName { get; init; } + + public string? PhoneNumber { get; set; } + + public bool PhoneNumberConfirmed { get; set; } + + public string? Email { get; set; } + + public bool EmailConfirmed { get; set; } + + public DateTimeOffset CreationTime { get; init; } + + public List? Roles { get; set; } +} diff --git a/src/HelloShop.IdentityService/Models/Users/UserListItem.cs b/src/HelloShop.IdentityService/Models/Users/UserListItem.cs new file mode 100644 index 0000000..e47b9e2 --- /dev/null +++ b/src/HelloShop.IdentityService/Models/Users/UserListItem.cs @@ -0,0 +1,18 @@ +namespace HelloShop.IdentityService; + +public class UserListItem +{ + public int Id { get; init; } + + public required string UserName { get; init; } + + public string? PhoneNumber { get; set; } + + public bool PhoneNumberConfirmed { get; set; } + + public string? Email { get; set; } + + public bool EmailConfirmed { get; set; } + + public DateTimeOffset CreationTime { get; init; } +} diff --git a/src/HelloShop.IdentityService/Models/Users/UserListRequest.cs b/src/HelloShop.IdentityService/Models/Users/UserListRequest.cs new file mode 100644 index 0000000..69c8fdb --- /dev/null +++ b/src/HelloShop.IdentityService/Models/Users/UserListRequest.cs @@ -0,0 +1,8 @@ +using HelloShop.ServiceDefaults.Models.Paging; + +namespace HelloShop.IdentityService.Models.Users; + +public class UserListRequest : KeywordSearchRequest +{ + public string? PhoneNumber { get; init; } +} diff --git a/src/HelloShop.IdentityService/Models/Users/UserUpdateRequest.cs b/src/HelloShop.IdentityService/Models/Users/UserUpdateRequest.cs new file mode 100644 index 0000000..b0d4030 --- /dev/null +++ b/src/HelloShop.IdentityService/Models/Users/UserUpdateRequest.cs @@ -0,0 +1,14 @@ +namespace HelloShop.IdentityService.Models.Users; + +public class UserUpdateRequest +{ + public int Id { get; init; } + + public required string UserName { get; init; } + + public string? PhoneNumber { get; set; } + + public string? Email { get; set; } + + public string? Password { get; set; } +} diff --git a/src/HelloShop.ServiceDefaults/Constants/PagingConstants.cs b/src/HelloShop.ServiceDefaults/Constants/PagingConstants.cs new file mode 100644 index 0000000..4f903d5 --- /dev/null +++ b/src/HelloShop.ServiceDefaults/Constants/PagingConstants.cs @@ -0,0 +1,7 @@ +namespace HelloShop.ServiceDefaults.Constants; + +public class PagingConstants +{ + public const int DefaultPageSize = 10; + +} diff --git a/src/HelloShop.ServiceDefaults/Models/Paging/KeywordSearchRequest.cs b/src/HelloShop.ServiceDefaults/Models/Paging/KeywordSearchRequest.cs new file mode 100644 index 0000000..36d2c3b --- /dev/null +++ b/src/HelloShop.ServiceDefaults/Models/Paging/KeywordSearchRequest.cs @@ -0,0 +1,6 @@ +namespace HelloShop.ServiceDefaults.Models.Paging; + +public class KeywordSearchRequest : PagedAndSortedRequest +{ + public string? Keyword { get; init; } +} diff --git a/src/HelloShop.ServiceDefaults/Models/Paging/PagedAndSortedRequest.cs b/src/HelloShop.ServiceDefaults/Models/Paging/PagedAndSortedRequest.cs new file mode 100644 index 0000000..6ec15b8 --- /dev/null +++ b/src/HelloShop.ServiceDefaults/Models/Paging/PagedAndSortedRequest.cs @@ -0,0 +1,6 @@ +namespace HelloShop.ServiceDefaults.Models.Paging; + +public class PagedAndSortedRequest : PagedRequest +{ + public IEnumerable? Sorts { get; init; } +} diff --git a/src/HelloShop.ServiceDefaults/Models/Paging/PagedRequest.cs b/src/HelloShop.ServiceDefaults/Models/Paging/PagedRequest.cs new file mode 100644 index 0000000..4d8b3bd --- /dev/null +++ b/src/HelloShop.ServiceDefaults/Models/Paging/PagedRequest.cs @@ -0,0 +1,10 @@ +using HelloShop.ServiceDefaults.Constants; + +namespace HelloShop.ServiceDefaults.Models.Paging; + +public class PagedRequest +{ + public int PageNumber { get; init; } = 1; + + public int PageSize { get; init; } = PagingConstants.DefaultPageSize; +} \ No newline at end of file diff --git a/src/HelloShop.ServiceDefaults/Models/Paging/PagedResponse.cs b/src/HelloShop.ServiceDefaults/Models/Paging/PagedResponse.cs new file mode 100644 index 0000000..dc8cc71 --- /dev/null +++ b/src/HelloShop.ServiceDefaults/Models/Paging/PagedResponse.cs @@ -0,0 +1,8 @@ +namespace HelloShop.ServiceDefaults.Models.Paging; + +public class PagedResponse(IReadOnlyList items, int totalCount) +{ + public IReadOnlyList Items { get; init; } = items; + + public int TotalCount { get; init; } = totalCount; +} \ No newline at end of file diff --git a/src/HelloShop.ServiceDefaults/Models/Paging/SortingOrder.cs b/src/HelloShop.ServiceDefaults/Models/Paging/SortingOrder.cs new file mode 100644 index 0000000..a618efb --- /dev/null +++ b/src/HelloShop.ServiceDefaults/Models/Paging/SortingOrder.cs @@ -0,0 +1,8 @@ +namespace HelloShop.ServiceDefaults.Models.Paging; + +public class SortingOrder +{ + public required string PropertyName { get; init; } + + public bool Ascending { get; init; } +}