netcore-blueprint 0.0.1 → 0.0.3
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.
- package/BlueprintTemplate/Host.API/Extensions/ApplicationBuilderExtensions.cs +26 -0
- package/BlueprintTemplate/Host.API/Extensions/DatabaseExtensions.cs +37 -0
- package/BlueprintTemplate/Host.API/Extensions/ServiceCollectionExtensions.cs +54 -0
- package/BlueprintTemplate/Host.API/Extensions/ThirdPartyExtensions.cs +30 -0
- package/BlueprintTemplate/Host.API/Host.API.csproj +29 -0
- package/BlueprintTemplate/Host.API/Host.API.csproj.user +6 -0
- package/BlueprintTemplate/Host.API/Host.API.http +6 -0
- package/BlueprintTemplate/Host.API/Program.cs +25 -0
- package/BlueprintTemplate/Host.API/Properties/launchSettings.json +23 -0
- package/BlueprintTemplate/Host.API/appsettings.Development.json +8 -0
- package/BlueprintTemplate/Host.API/appsettings.json +15 -0
- package/BlueprintTemplate/ItemModule.API/Controllers/Public/ItemController.cs +65 -0
- package/BlueprintTemplate/ItemModule.API/ItemModule.API.csproj +26 -0
- package/BlueprintTemplate/ItemModule.API/Mappers/DtoItemMappingProfile.cs +26 -0
- package/BlueprintTemplate/ItemModule.Core/Dtos/Admin/ItemRequestDto.cs +8 -0
- package/BlueprintTemplate/ItemModule.Core/Dtos/Admin/ItemResponseDto.cs +8 -0
- package/BlueprintTemplate/ItemModule.Core/Entities/Item.cs +8 -0
- package/BlueprintTemplate/ItemModule.Core/Interfaces/API/IItemService.cs +9 -0
- package/BlueprintTemplate/ItemModule.Core/Interfaces/SPI/IItemInfra.cs +9 -0
- package/BlueprintTemplate/ItemModule.Core/ItemModule.Core.csproj +18 -0
- package/BlueprintTemplate/ItemModule.Core/Services/ItemService.cs +20 -0
- package/BlueprintTemplate/ItemModule.Infrastructure/Database/ItemConfiguration.cs +22 -0
- package/BlueprintTemplate/ItemModule.Infrastructure/Database/Seeder.cs +21 -0
- package/BlueprintTemplate/ItemModule.Infrastructure/ItemDependencyInjection.cs +27 -0
- package/BlueprintTemplate/ItemModule.Infrastructure/ItemModule.Infrastructure.csproj +14 -0
- package/BlueprintTemplate/ItemModule.Infrastructure/Services/MySQLItemInfra.cs +16 -0
- package/BlueprintTemplate/MyBlueprint.slnx +23 -0
- package/BlueprintTemplate/README.md +22 -0
- package/BlueprintTemplate/Shared.Core/Dtos/Requests/BaseRequestDto.cs +27 -0
- package/BlueprintTemplate/Shared.Core/Dtos/Responses/BaseResponseDto.cs +27 -0
- package/BlueprintTemplate/Shared.Core/Entities/BaseEntity.cs +15 -0
- package/BlueprintTemplate/Shared.Core/Enums/EntityStatus.cs +9 -0
- package/BlueprintTemplate/Shared.Core/Exceptions/Errors.cs +20 -0
- package/BlueprintTemplate/Shared.Core/Interfaces/API/IItemService.cs +14 -0
- package/BlueprintTemplate/Shared.Core/Interfaces/SPI/IItemInfra.cs +14 -0
- package/BlueprintTemplate/Shared.Core/Interfaces/SPI/IModuleSeeder.cs +9 -0
- package/BlueprintTemplate/Shared.Core/Interfaces/SPI/IRepositoryFactory.cs +7 -0
- package/BlueprintTemplate/Shared.Core/Models/Error.cs +69 -0
- package/BlueprintTemplate/Shared.Core/Models/ErrorDetail.cs +8 -0
- package/BlueprintTemplate/Shared.Core/Models/PagerData.cs +8 -0
- package/BlueprintTemplate/Shared.Core/Models/PagingParams.cs +8 -0
- package/BlueprintTemplate/Shared.Core/Services/ItemService.cs +53 -0
- package/BlueprintTemplate/Shared.Core/Shared.Core.csproj +13 -0
- package/BlueprintTemplate/Shared.Infrastructure/DbInitializer.cs +18 -0
- package/BlueprintTemplate/Shared.Infrastructure/Migrations/20260131121133_SeedInitialData.Designer.cs +123 -0
- package/BlueprintTemplate/Shared.Infrastructure/Migrations/20260131121133_SeedInitialData.cs +82 -0
- package/BlueprintTemplate/Shared.Infrastructure/Migrations/MyDbContextModelSnapshot.cs +120 -0
- package/BlueprintTemplate/Shared.Infrastructure/MyDbContext.cs +24 -0
- package/BlueprintTemplate/Shared.Infrastructure/Services/Mongo/MongoItemInfra.cs +117 -0
- package/BlueprintTemplate/Shared.Infrastructure/Services/MySQL/MySQLItemInfra.cs +132 -0
- package/BlueprintTemplate/Shared.Infrastructure/Services/RepositoryFactory.cs +36 -0
- package/BlueprintTemplate/Shared.Infrastructure/Shared.Infrastructure.csproj +28 -0
- package/BlueprintTemplate/Shared.Infrastructure/SharedDependencyInjection.cs +19 -0
- package/BlueprintTemplate/User.API/Controllers/Admin/UserController.cs +153 -0
- package/BlueprintTemplate/User.API/Mappers/DtoUserMappingProfile.cs +27 -0
- package/BlueprintTemplate/User.API/UserModule.API.csproj +26 -0
- package/BlueprintTemplate/User.Core/Dtos/Admin/UserRequestDto.cs +12 -0
- package/BlueprintTemplate/User.Core/Dtos/Admin/UserResponseDto.cs +12 -0
- package/BlueprintTemplate/User.Core/Entities/User.cs +13 -0
- package/BlueprintTemplate/User.Core/Enums/UserRole.cs +8 -0
- package/BlueprintTemplate/User.Core/Interfaces/API/IUserService.cs +9 -0
- package/BlueprintTemplate/User.Core/Interfaces/SPI/IUserInfra.cs +9 -0
- package/BlueprintTemplate/User.Core/Services/UserService.cs +20 -0
- package/BlueprintTemplate/User.Core/UserModule.Core.csproj +17 -0
- package/BlueprintTemplate/User.Infrastructure/Database/ItemConfiguration.cs +27 -0
- package/BlueprintTemplate/User.Infrastructure/Database/Seeder.cs +44 -0
- package/BlueprintTemplate/User.Infrastructure/Services/MySQLUserInfra.cs +16 -0
- package/BlueprintTemplate/User.Infrastructure/UserDependencyInjection.cs +22 -0
- package/BlueprintTemplate/User.Infrastructure/UserModule.Infrastructure.csproj +14 -0
- package/README.md +7 -18
- 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,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
|
+
}
|