netcore-blueprint 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/BlueprintTemplate/Host.API/Extensions/ApplicationBuilderExtensions.cs +26 -0
  2. package/BlueprintTemplate/Host.API/Extensions/DatabaseExtensions.cs +37 -0
  3. package/BlueprintTemplate/Host.API/Extensions/ServiceCollectionExtensions.cs +54 -0
  4. package/BlueprintTemplate/Host.API/Extensions/ThirdPartyExtensions.cs +30 -0
  5. package/BlueprintTemplate/Host.API/Host.API.csproj +29 -0
  6. package/BlueprintTemplate/Host.API/Host.API.csproj.user +6 -0
  7. package/BlueprintTemplate/Host.API/Host.API.http +6 -0
  8. package/BlueprintTemplate/Host.API/Program.cs +25 -0
  9. package/BlueprintTemplate/Host.API/Properties/launchSettings.json +23 -0
  10. package/BlueprintTemplate/Host.API/appsettings.Development.json +8 -0
  11. package/BlueprintTemplate/Host.API/appsettings.json +15 -0
  12. package/BlueprintTemplate/ItemModule.API/Controllers/Public/ItemController.cs +65 -0
  13. package/BlueprintTemplate/ItemModule.API/ItemModule.API.csproj +26 -0
  14. package/BlueprintTemplate/ItemModule.API/Mappers/DtoItemMappingProfile.cs +26 -0
  15. package/BlueprintTemplate/ItemModule.Core/Dtos/Admin/ItemRequestDto.cs +8 -0
  16. package/BlueprintTemplate/ItemModule.Core/Dtos/Admin/ItemResponseDto.cs +8 -0
  17. package/BlueprintTemplate/ItemModule.Core/Entities/Item.cs +8 -0
  18. package/BlueprintTemplate/ItemModule.Core/Interfaces/API/IItemService.cs +9 -0
  19. package/BlueprintTemplate/ItemModule.Core/Interfaces/SPI/IItemInfra.cs +9 -0
  20. package/BlueprintTemplate/ItemModule.Core/ItemModule.Core.csproj +18 -0
  21. package/BlueprintTemplate/ItemModule.Core/Services/ItemService.cs +20 -0
  22. package/BlueprintTemplate/ItemModule.Infrastructure/Database/ItemConfiguration.cs +22 -0
  23. package/BlueprintTemplate/ItemModule.Infrastructure/Database/Seeder.cs +21 -0
  24. package/BlueprintTemplate/ItemModule.Infrastructure/ItemDependencyInjection.cs +27 -0
  25. package/BlueprintTemplate/ItemModule.Infrastructure/ItemModule.Infrastructure.csproj +14 -0
  26. package/BlueprintTemplate/ItemModule.Infrastructure/Services/MySQLItemInfra.cs +16 -0
  27. package/BlueprintTemplate/MyBlueprint.slnx +23 -0
  28. package/BlueprintTemplate/README.md +22 -0
  29. package/BlueprintTemplate/Shared.Core/Dtos/Requests/BaseRequestDto.cs +27 -0
  30. package/BlueprintTemplate/Shared.Core/Dtos/Responses/BaseResponseDto.cs +27 -0
  31. package/BlueprintTemplate/Shared.Core/Entities/BaseEntity.cs +15 -0
  32. package/BlueprintTemplate/Shared.Core/Enums/EntityStatus.cs +9 -0
  33. package/BlueprintTemplate/Shared.Core/Exceptions/Errors.cs +20 -0
  34. package/BlueprintTemplate/Shared.Core/Interfaces/API/IItemService.cs +14 -0
  35. package/BlueprintTemplate/Shared.Core/Interfaces/SPI/IItemInfra.cs +14 -0
  36. package/BlueprintTemplate/Shared.Core/Interfaces/SPI/IModuleSeeder.cs +9 -0
  37. package/BlueprintTemplate/Shared.Core/Interfaces/SPI/IRepositoryFactory.cs +7 -0
  38. package/BlueprintTemplate/Shared.Core/Models/Error.cs +69 -0
  39. package/BlueprintTemplate/Shared.Core/Models/ErrorDetail.cs +8 -0
  40. package/BlueprintTemplate/Shared.Core/Models/PagerData.cs +8 -0
  41. package/BlueprintTemplate/Shared.Core/Models/PagingParams.cs +8 -0
  42. package/BlueprintTemplate/Shared.Core/Services/ItemService.cs +53 -0
  43. package/BlueprintTemplate/Shared.Core/Shared.Core.csproj +13 -0
  44. package/BlueprintTemplate/Shared.Infrastructure/DbInitializer.cs +18 -0
  45. package/BlueprintTemplate/Shared.Infrastructure/Migrations/20260131121133_SeedInitialData.Designer.cs +123 -0
  46. package/BlueprintTemplate/Shared.Infrastructure/Migrations/20260131121133_SeedInitialData.cs +82 -0
  47. package/BlueprintTemplate/Shared.Infrastructure/Migrations/MyDbContextModelSnapshot.cs +120 -0
  48. package/BlueprintTemplate/Shared.Infrastructure/MyDbContext.cs +24 -0
  49. package/BlueprintTemplate/Shared.Infrastructure/Services/Mongo/MongoItemInfra.cs +117 -0
  50. package/BlueprintTemplate/Shared.Infrastructure/Services/MySQL/MySQLItemInfra.cs +132 -0
  51. package/BlueprintTemplate/Shared.Infrastructure/Services/RepositoryFactory.cs +36 -0
  52. package/BlueprintTemplate/Shared.Infrastructure/Shared.Infrastructure.csproj +28 -0
  53. package/BlueprintTemplate/Shared.Infrastructure/SharedDependencyInjection.cs +19 -0
  54. package/BlueprintTemplate/User.API/Controllers/Admin/UserController.cs +153 -0
  55. package/BlueprintTemplate/User.API/Mappers/DtoUserMappingProfile.cs +27 -0
  56. package/BlueprintTemplate/User.API/UserModule.API.csproj +26 -0
  57. package/BlueprintTemplate/User.Core/Dtos/Admin/UserRequestDto.cs +12 -0
  58. package/BlueprintTemplate/User.Core/Dtos/Admin/UserResponseDto.cs +12 -0
  59. package/BlueprintTemplate/User.Core/Entities/User.cs +13 -0
  60. package/BlueprintTemplate/User.Core/Enums/UserRole.cs +8 -0
  61. package/BlueprintTemplate/User.Core/Interfaces/API/IUserService.cs +9 -0
  62. package/BlueprintTemplate/User.Core/Interfaces/SPI/IUserInfra.cs +9 -0
  63. package/BlueprintTemplate/User.Core/Services/UserService.cs +20 -0
  64. package/BlueprintTemplate/User.Core/UserModule.Core.csproj +17 -0
  65. package/BlueprintTemplate/User.Infrastructure/Database/ItemConfiguration.cs +27 -0
  66. package/BlueprintTemplate/User.Infrastructure/Database/Seeder.cs +44 -0
  67. package/BlueprintTemplate/User.Infrastructure/Services/MySQLUserInfra.cs +16 -0
  68. package/BlueprintTemplate/User.Infrastructure/UserDependencyInjection.cs +22 -0
  69. package/BlueprintTemplate/User.Infrastructure/UserModule.Infrastructure.csproj +14 -0
  70. package/create.js +1 -1
  71. package/package.json +2 -2
@@ -0,0 +1,117 @@
1
+ using Microsoft.Extensions.Logging;
2
+ using MongoDB.Driver;
3
+ using Shared.Core.Entities;
4
+ using Shared.Core.Exceptions;
5
+ using Shared.Core.Interfaces.SPI;
6
+ using Shared.Core.Shared.Models;
7
+ using System;
8
+ using System.Collections.Generic;
9
+ using System.Linq.Expressions;
10
+ using System.Text;
11
+
12
+ namespace Shared.Infrastructure.Services.Mongo
13
+ {
14
+ public class MongoItemInfra<T> : IItemInfra<T> where T : BaseEntity
15
+ {
16
+ public readonly IMongoCollection<T> _dbSet;
17
+ public readonly ILogger<MongoItemInfra<T>> _logger;
18
+
19
+ public MongoItemInfra(
20
+ IMongoDatabase database,
21
+ ILogger<MongoItemInfra<T>> logger)
22
+ {
23
+ _dbSet = database.GetCollection<T>(typeof(T).Name.ToLower());
24
+ _logger = logger;
25
+ }
26
+ public async Task AddItemAsync(T item)
27
+ {
28
+ try
29
+ {
30
+ await _dbSet.InsertOneAsync(item);
31
+ }
32
+ catch (Exception ex)
33
+ {
34
+ _logger.LogError(ex, "Error while adding an item.");
35
+ throw Errors.CannotQueryError;
36
+ }
37
+ }
38
+
39
+ public async Task DeleteItemsAsync(List<Guid> ids)
40
+ {
41
+ try
42
+ {
43
+ // Build a filter to match all the IDs in the list
44
+ var filter = Builders<T>.Filter.In("Id", ids);
45
+
46
+ // Delete all matching documents
47
+ var result = await _dbSet.DeleteManyAsync(filter);
48
+ _logger.LogInformation($"Deleted {result.DeletedCount} items with the provided IDs.");
49
+ }
50
+ catch (Exception ex)
51
+ {
52
+ _logger.LogError(ex, $"Error while deleting items with IDs: {string.Join(", ", ids)}");
53
+ throw Errors.CannotQueryError;
54
+ }
55
+ }
56
+
57
+ public async Task<T> GetItemByIdAsync(Guid id, params Expression<Func<T, object>>[] includes)
58
+ {
59
+ try
60
+ {
61
+ return await _dbSet.Find(Builders<T>.Filter.Eq("Id", id)).FirstOrDefaultAsync();
62
+ }
63
+ catch (Exception ex)
64
+ {
65
+ _logger.LogError(ex, $"Error while fetching item with Id {id}");
66
+ throw Errors.CannotQueryError;
67
+ }
68
+ }
69
+
70
+ public async Task<PagerData<T>> GetItemsAsync(
71
+ PagingParams pagingParams,
72
+ params Expression<Func<T, object>>[] includes)
73
+ {
74
+ try
75
+ {
76
+ int skipValues = (pagingParams.Page - 1) * pagingParams.Per_Page;
77
+ var filter = Builders<T>.Filter.Empty;
78
+
79
+ var totalRecords = await _dbSet.CountDocumentsAsync(filter);
80
+ var items = await _dbSet
81
+ .Find(filter)
82
+ .Sort(Builders<T>.Sort.Descending("Id")) // Sort by descending Id, adjust field as needed
83
+ .Skip(skipValues)
84
+ .Limit(pagingParams.Per_Page)
85
+ .ToListAsync();
86
+
87
+ return new PagerData<T>
88
+ {
89
+ Items = items,
90
+ TotalRecords = (int)totalRecords
91
+ };
92
+ }
93
+ catch (Exception ex)
94
+ {
95
+ // You can add logging here if needed
96
+ throw Errors.CannotQueryError;
97
+ }
98
+ }
99
+
100
+ public async Task UpdateItemAsync(T item)
101
+ {
102
+ try
103
+ {
104
+ var id = typeof(T).GetProperty("Id")?.GetValue(item);
105
+ if (id == null)
106
+ throw Errors.CannotFindTheItem;
107
+
108
+ await _dbSet.ReplaceOneAsync(Builders<T>.Filter.Eq("Id", id), item);
109
+ }
110
+ catch (Exception ex)
111
+ {
112
+ _logger.LogError(ex, "Error while updating an item.");
113
+ throw Errors.CannotQueryError;
114
+ }
115
+ }
116
+ }
117
+ }
@@ -0,0 +1,132 @@
1
+ using Microsoft.EntityFrameworkCore;
2
+ using Microsoft.Extensions.Logging;
3
+ using Shared.Core.Entities;
4
+ using Shared.Core.Enums;
5
+ using Shared.Core.Exceptions;
6
+ using Shared.Core.Interfaces.SPI;
7
+ using Shared.Core.Shared.Models;
8
+ using System.Linq.Expressions;
9
+
10
+ namespace Shared.Infrastructure.Services.MySQL
11
+ {
12
+ public class MySQLItemInfra<T> : IItemInfra<T> where T : BaseEntity
13
+ {
14
+ public readonly DbContext _dbContext;
15
+ public readonly DbSet<T> _dbSet;
16
+ public ILogger _logger;
17
+ public MySQLItemInfra
18
+ (
19
+ MyDbContext dbContext,
20
+ ILogger<MySQLItemInfra<T>> logger
21
+ )
22
+ {
23
+ _dbContext = dbContext;
24
+ _logger = logger;
25
+ _dbSet = _dbContext.Set<T>();
26
+ }
27
+ public async Task AddItemAsync(T item)
28
+ {
29
+ try
30
+ {
31
+ _dbSet.Add(item);
32
+ await _dbContext.SaveChangesAsync();
33
+ }
34
+ catch (Exception)
35
+ {
36
+ _logger.LogError($"Cannot add an item");
37
+ throw Errors.CannotQueryError;
38
+ }
39
+ }
40
+
41
+ public async Task DeleteItemsAsync(List<Guid> ids)
42
+ {
43
+ try
44
+ {
45
+ List<T> items = _dbSet.Where(p => ids.Contains(p.Id)).ToList();
46
+ items.ForEach(i => i.Status = EntityStatus.Active);
47
+ _dbSet.UpdateRange(items);
48
+ await _dbContext.SaveChangesAsync();
49
+ }
50
+ catch (Exception)
51
+ {
52
+ _logger.LogError($"Cannot delete items");
53
+ throw Errors.CannotQueryError;
54
+ }
55
+ }
56
+
57
+ public virtual async Task<T?> GetItemByIdAsync(Guid id, params Expression<Func<T, object>>[] includes)
58
+ {
59
+ try
60
+ {
61
+ IQueryable<T> query = _dbSet;
62
+
63
+ // Apply includes dynamically
64
+ foreach (var include in includes)
65
+ {
66
+ query = query.Include(include);
67
+ }
68
+
69
+ return await query.FirstOrDefaultAsync(p => p.Id == id);
70
+ }
71
+ catch (Exception ex)
72
+ {
73
+ _logger.LogError(ex, "Cannot get item with ID: {Id}", id);
74
+ throw Errors.CannotQueryError;
75
+ }
76
+ }
77
+
78
+ public virtual async Task<PagerData<T>> GetItemsAsync(
79
+ PagingParams pagingParams,
80
+ params Expression<Func<T, object>>[] includes)
81
+ {
82
+ try
83
+ {
84
+ int skipValues = (pagingParams.Page - 1) * pagingParams.Per_Page;
85
+ IQueryable<T> query = _dbSet
86
+ .Where(p => p.Status == EntityStatus.Active)
87
+ .OrderByDescending(p => p.Id);
88
+
89
+ // Apply includes dynamically
90
+ if (includes != null)
91
+ {
92
+ foreach (var include in includes)
93
+ {
94
+ query = query.Include(include);
95
+ }
96
+ }
97
+
98
+ List<T> items = await query
99
+ .Skip(skipValues)
100
+ .Take(pagingParams.Per_Page)
101
+ .ToListAsync();
102
+
103
+ PagerData<T> pagerData = new PagerData<T>
104
+ {
105
+ Items = items,
106
+ TotalRecords = (await query.ToListAsync()).Count()
107
+ };
108
+
109
+ return pagerData;
110
+ }
111
+ catch (Exception)
112
+ {
113
+ _logger.LogError($"Cannot get items");
114
+ throw Errors.CannotQueryError;
115
+ }
116
+ }
117
+
118
+ public async Task UpdateItemAsync(T item)
119
+ {
120
+ try
121
+ {
122
+ _dbSet.Update(item);
123
+ await _dbContext.SaveChangesAsync();
124
+ }
125
+ catch (Exception)
126
+ {
127
+ _logger.LogError($"Cannot update an item");
128
+ throw Errors.CannotQueryError;
129
+ }
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,36 @@
1
+ using Microsoft.Extensions.Configuration;
2
+ using Microsoft.Extensions.DependencyInjection;
3
+ using Shared.Core.Entities;
4
+ using Shared.Core.Interfaces.SPI;
5
+ using Shared.Infrastructure.Services.Mongo;
6
+ using Shared.Infrastructure.Services.MySQL;
7
+
8
+ namespace Shared.Infrastructure.Services
9
+ {
10
+ public class RepositoryFactory<T> : IRepositoryFactory<T> where T : BaseEntity
11
+ {
12
+ private readonly string _databaseType;
13
+ private readonly IServiceProvider _serviceProvider;
14
+
15
+ public RepositoryFactory(IConfiguration configuration, IServiceProvider serviceProvider)
16
+ {
17
+ _databaseType = configuration["Database:Type"]!;
18
+ _serviceProvider = serviceProvider;
19
+ }
20
+
21
+ public IItemInfra<T> CreateItemRepository()
22
+ {
23
+ var dbType = _databaseType.ToLower();
24
+ var entityType = typeof(T);
25
+
26
+ Type implementationType = dbType switch
27
+ {
28
+ "mysql" => typeof(MySQLItemInfra<>).MakeGenericType(entityType),
29
+ "mongodb" => typeof(MongoItemInfra<>).MakeGenericType(entityType),
30
+ _ => throw new ArgumentException("Invalid database type")
31
+ };
32
+
33
+ return (IItemInfra<T>)ActivatorUtilities.CreateInstance(_serviceProvider, implementationType);
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,28 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+
3
+ <ItemGroup>
4
+ <ProjectReference Include="..\Shared.Core\Shared.Core.csproj" />
5
+ </ItemGroup>
6
+
7
+ <ItemGroup>
8
+ <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.0" />
9
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="9.0.0" />
10
+ <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.0">
11
+ <PrivateAssets>all</PrivateAssets>
12
+ <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
13
+ </PackageReference>
14
+ <PackageReference Include="MongoDB.Driver" Version="3.6.0" />
15
+ <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="9.0.0" />
16
+ </ItemGroup>
17
+
18
+ <ItemGroup>
19
+ <Folder Include="Migrations\" />
20
+ </ItemGroup>
21
+
22
+ <PropertyGroup>
23
+ <TargetFramework>net10.0</TargetFramework>
24
+ <ImplicitUsings>enable</ImplicitUsings>
25
+ <Nullable>enable</Nullable>
26
+ </PropertyGroup>
27
+
28
+ </Project>
@@ -0,0 +1,19 @@
1
+ using Microsoft.Extensions.DependencyInjection;
2
+ using Shared.Core.Interfaces.SPI;
3
+ using Shared.Infrastructure.Services;
4
+
5
+ namespace Shared.Infrastructure
6
+ {
7
+ public static class SharedDependencyInjection
8
+ {
9
+ public static IServiceCollection AddSharedInfrastructure(
10
+ this IServiceCollection services)
11
+ {
12
+ services.AddScoped(
13
+ typeof(IRepositoryFactory<>),
14
+ typeof(RepositoryFactory<>));
15
+
16
+ return services;
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,153 @@
1
+ using AutoMapper;
2
+ using Microsoft.AspNetCore.Authorization;
3
+ using Microsoft.AspNetCore.Http;
4
+ using Microsoft.AspNetCore.Mvc;
5
+ using Microsoft.Extensions.Logging;
6
+ using Shared.Core.Shared.Models;
7
+ using System.Diagnostics;
8
+ using UserModule.Core.Dtos.Admin;
9
+ using UserModule.Core.Entities;
10
+ using UserModule.Core.Interfaces.API;
11
+
12
+ namespace UserModule.API.Controllers.Admin
13
+ {
14
+ /// <summary>
15
+ /// User Controller
16
+ /// </summary>
17
+ [Route("rest/v{version:apiVersion}/users")]
18
+ [Produces("application/json")]
19
+ [ApiController]
20
+ public class UserController : Controller
21
+ {
22
+ private readonly IMapper _mapper;
23
+ private ILogger _logger;
24
+ private readonly IUserService _userService;
25
+
26
+ /// <summary>
27
+ /// Constructor
28
+ /// </summary>
29
+ /// <param name="logger"></param>
30
+ /// <param name="mapper"></param>
31
+ /// <param name="userService"></param>
32
+ public UserController(
33
+ ILogger<UserController> logger,
34
+ IMapper mapper,
35
+ IUserService userService)
36
+ {
37
+ _mapper = mapper;
38
+ _logger = logger;
39
+ _userService = userService;
40
+ }
41
+
42
+ /// <summary>
43
+ /// Get users
44
+ /// </summary>
45
+ /// <param name="pagingParams"></param>
46
+ /// <returns></returns>
47
+ [HttpGet]
48
+ //[Authorize(Roles = "Admin")]
49
+ [ProducesResponseType(typeof(PagerData<UserResponseDto>), StatusCodes.Status200OK)]
50
+ public async Task<IActionResult> GetUsers([FromQuery] PagingParams pagingParams)
51
+ {
52
+ _logger.LogInformation($"Start getting users");
53
+ var stopwatch = Stopwatch.StartNew();
54
+
55
+ PagerData<User> users = await _userService.GetItemsAsync(pagingParams);
56
+ PagerData<UserResponseDto> userResponse = _mapper.Map<PagerData<UserResponseDto>>(users);
57
+
58
+ // Add custom headers
59
+ Response.Headers.Append("X-WP-Total", users.TotalRecords.ToString());
60
+
61
+ stopwatch.Stop();
62
+ _logger.LogInformation($"Getting users done in {stopwatch.ElapsedMilliseconds}");
63
+
64
+ return Ok(userResponse.Items);
65
+ }
66
+
67
+ /// <summary>
68
+ /// Get user by Id
69
+ /// </summary>
70
+ /// <param name="userId"></param>
71
+ /// <returns></returns>
72
+ [HttpGet("{userId}")]
73
+ //[Authorize(Roles = "Admin")]
74
+ [ProducesResponseType(typeof(UserResponseDto), StatusCodes.Status200OK)]
75
+ public async Task<IActionResult> GetUserById(Guid userId)
76
+ {
77
+ _logger.LogInformation($"Start getting a user with Id = {userId}");
78
+ var stopwatch = Stopwatch.StartNew();
79
+
80
+ User user = await _userService.GetItemByIdAsync(userId);
81
+ UserResponseDto userResponseDto = _mapper.Map<UserResponseDto>(user);
82
+
83
+ stopwatch.Stop();
84
+ _logger.LogInformation($"Getting an user done in {stopwatch.ElapsedMilliseconds}");
85
+
86
+ return Ok(userResponseDto);
87
+ }
88
+
89
+ /// <summary>
90
+ /// Update User
91
+ /// </summary>
92
+ /// <param name="userRequestDto"></param>
93
+ /// <returns></returns>
94
+ [HttpPut]
95
+ //[Authorize(Roles = "Admin")]
96
+ [ProducesResponseType(typeof(UserResponseDto), StatusCodes.Status200OK)]
97
+ public async Task<IActionResult> UpdateUser([FromBody] UserRequestDto userRequestDto)
98
+ {
99
+ _logger.LogInformation($"Start update a user");
100
+ var stopwatch = Stopwatch.StartNew();
101
+
102
+ User user = _mapper.Map<User>(userRequestDto);
103
+ await _userService.UpdateItemAsync(user);
104
+
105
+ stopwatch.Stop();
106
+ _logger.LogInformation($"Updating a user done in {stopwatch.ElapsedMilliseconds}");
107
+
108
+ return Ok();
109
+ }
110
+
111
+ /// <summary>
112
+ /// Delete User
113
+ /// </summary>
114
+ /// <param name="userIds"></param>
115
+ /// <returns></returns>
116
+ [HttpDelete]
117
+ [Authorize(Roles = "Admin")]
118
+ [ProducesResponseType(StatusCodes.Status200OK)]
119
+ public async Task<IActionResult> DeleteUser([FromBody] List<Guid> userIds)
120
+ {
121
+ _logger.LogInformation($"Start deleting a User");
122
+ Stopwatch stopwatch = Stopwatch.StartNew();
123
+
124
+ await _userService.DeleteItemsAsync(userIds);
125
+
126
+ stopwatch.Stop();
127
+ _logger.LogInformation($"Deleting a User done in {stopwatch.ElapsedMilliseconds}");
128
+
129
+ return Ok();
130
+ }
131
+
132
+ /// <summary>
133
+ /// Create user
134
+ /// </summary>
135
+ /// <param name="userRequestDto"></param>
136
+ /// <returns></returns>
137
+ [HttpPost]
138
+ [ProducesResponseType(StatusCodes.Status200OK)]
139
+ public async Task<IActionResult> CreateUser([FromBody] UserRequestDto userRequestDto)
140
+ {
141
+ _logger.LogInformation($"Start creating a user");
142
+ var stopwatch = Stopwatch.StartNew();
143
+
144
+ User user = _mapper.Map<User>(userRequestDto);
145
+ await _userService.AddItemAsync(user);
146
+
147
+ stopwatch.Stop();
148
+ _logger.LogInformation($"Creating a user done in {stopwatch.ElapsedMilliseconds}");
149
+
150
+ return Ok();
151
+ }
152
+ }
153
+ }
@@ -0,0 +1,27 @@
1
+ using AutoMapper;
2
+ using Shared.Core.Shared.Models;
3
+ using UserModule.Core.Dtos.Admin;
4
+ using UserModule.Core.Entities;
5
+
6
+ namespace UserModule.API.Mappers
7
+ {
8
+ /// <summary>
9
+ /// DtoUserMappingProfile
10
+ /// </summary>
11
+ public class DtoUserMappingProfile : Profile
12
+ {
13
+ /// <summary>
14
+ /// Constructor
15
+ /// </summary>
16
+ public DtoUserMappingProfile()
17
+ {
18
+ CreateMap<User, UserRequestDto>().ReverseMap();
19
+
20
+ CreateMap<PagerData<User>, PagerData<UserResponseDto>>().ReverseMap();
21
+
22
+ CreateMap<User, UserResponseDto>()
23
+ .ForMember(dest => dest.Role, opt => opt.MapFrom(src => src.Role.ToString()))
24
+ .ReverseMap();
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,26 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+
3
+ <ItemGroup>
4
+ <ProjectReference Include="..\User.Core\UserModule.Core.csproj" />
5
+ <ProjectReference Include="..\Shared.Core\Shared.Core.csproj" />
6
+ </ItemGroup>
7
+
8
+ <ItemGroup>
9
+ <Folder Include="Controllers\Public\" />
10
+ </ItemGroup>
11
+
12
+ <ItemGroup>
13
+ <PackageReference Include="Asp.Versioning.Mvc" Version="8.1.1" />
14
+ <PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.1" />
15
+ <PackageReference Include="AutoMapper" Version="13.0.1" />
16
+ <PackageReference Include="Microsoft.AspNetCore.Authorization" Version="10.0.2" />
17
+ <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.3.9" />
18
+ </ItemGroup>
19
+
20
+ <PropertyGroup>
21
+ <TargetFramework>net10.0</TargetFramework>
22
+ <ImplicitUsings>enable</ImplicitUsings>
23
+ <Nullable>enable</Nullable>
24
+ </PropertyGroup>
25
+
26
+ </Project>
@@ -0,0 +1,12 @@
1
+ using Shared.Core.Dtos.Requests;
2
+
3
+ namespace UserModule.Core.Dtos.Admin
4
+ {
5
+ public class UserRequestDto : BaseRequestDto
6
+ {
7
+ public string? Name { get; set; }
8
+ public string? Email { get; set; }
9
+ public string? Picture { get; set; }
10
+ public string? Role { get; set; }
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ using Shared.Core.Dtos.Responses;
2
+
3
+ namespace UserModule.Core.Dtos.Admin
4
+ {
5
+ public class UserResponseDto : BaseResponseDto
6
+ {
7
+ public string? Name { get; set; }
8
+ public string? Email { get; set; }
9
+ public string? Picture { get; set; }
10
+ public string? Role { get; set; }
11
+ }
12
+ }
@@ -0,0 +1,13 @@
1
+ using Shared.Core.Entities;
2
+ using UserModule.Core.Enums;
3
+
4
+ namespace UserModule.Core.Entities
5
+ {
6
+ public class User : BaseEntity
7
+ {
8
+ public string? Name { get; set; }
9
+ public string? Email { get; set; }
10
+ public string? Picture { get; set; }
11
+ public UserRole Role { get; set; }
12
+ }
13
+ }
@@ -0,0 +1,8 @@
1
+ namespace UserModule.Core.Enums
2
+ {
3
+ public enum UserRole
4
+ {
5
+ User,
6
+ Admin
7
+ }
8
+ }
@@ -0,0 +1,9 @@
1
+ using Shared.Core.Interfaces.API;
2
+ using UserModule.Core.Entities;
3
+
4
+ namespace UserModule.Core.Interfaces.API
5
+ {
6
+ public interface IUserService : IItemService<User>
7
+ {
8
+ }
9
+ }
@@ -0,0 +1,9 @@
1
+ using Shared.Core.Interfaces.SPI;
2
+ using UserModule.Core.Entities;
3
+
4
+ namespace UserModule.Core.Interfaces.SPI
5
+ {
6
+ public interface IUserInfra : IItemInfra<User>
7
+ {
8
+ }
9
+ }
@@ -0,0 +1,20 @@
1
+ using Microsoft.Extensions.Logging;
2
+ using Shared.Core.Interfaces.SPI;
3
+ using Shared.Core.Services;
4
+ using UserModule.Core.Entities;
5
+ using UserModule.Core.Interfaces.API;
6
+ using UserModule.Core.Interfaces.SPI;
7
+
8
+ namespace UserModule.Core.Services
9
+ {
10
+ public class UserService : ItemService<User>, IUserService
11
+ {
12
+ private readonly IUserInfra _userInfra;
13
+ public UserService(ILogger<UserService> logger,
14
+ IRepositoryFactory<User> repositoryFactory,
15
+ IUserInfra userInfra) : base(logger, repositoryFactory)
16
+ {
17
+ _userInfra = userInfra;
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,17 @@
1
+ <Project Sdk="Microsoft.NET.Sdk">
2
+
3
+ <ItemGroup>
4
+ <ProjectReference Include="..\Shared.Core\Shared.Core.csproj" />
5
+ </ItemGroup>
6
+
7
+ <ItemGroup>
8
+ <Folder Include="Dtos\Public\" />
9
+ </ItemGroup>
10
+
11
+ <PropertyGroup>
12
+ <TargetFramework>net10.0</TargetFramework>
13
+ <ImplicitUsings>enable</ImplicitUsings>
14
+ <Nullable>enable</Nullable>
15
+ </PropertyGroup>
16
+
17
+ </Project>
@@ -0,0 +1,27 @@
1
+ using Microsoft.EntityFrameworkCore;
2
+ using Microsoft.EntityFrameworkCore.Metadata.Builders;
3
+ using UserModule.Core.Entities;
4
+
5
+ namespace UserModule.Infrastructure.Database
6
+ {
7
+ public class ItemConfiguration : IEntityTypeConfiguration<User>
8
+ {
9
+ public void Configure(EntityTypeBuilder<User> builder)
10
+ {
11
+ // Table
12
+ builder.ToTable("Users");
13
+
14
+ // Primary key
15
+ builder.HasKey(x => x.Id);
16
+
17
+ // BaseEntity (nếu có)
18
+ builder.Property(x => x.Id)
19
+ .IsRequired();
20
+
21
+ // 👉 Các field khác cấu hình khi entity đã ổn định
22
+ // Ví dụ:
23
+ // builder.Property(x => x.Email).IsRequired().HasMaxLength(255);
24
+ // builder.HasIndex(x => x.Email).IsUnique();
25
+ }
26
+ }
27
+ }