stackforge-cli 0.1.3__py3-none-any.whl → 0.1.4__py3-none-any.whl
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.
- stackforge/engines/dotnet/__init__.py +7 -7
- stackforge/engines/dotnet/api_generator.py +313 -312
- stackforge/engines/dotnet/config_generator.py +76 -76
- stackforge/engines/dotnet/csproj_generator.py +82 -82
- stackforge/engines/dotnet/docker_generator.py +63 -63
- stackforge/engines/dotnet/git_generator.py +126 -111
- stackforge/engines/dotnet/layers_generator.py +543 -543
- stackforge/engines/dotnet/program_generator.py +245 -195
- stackforge/engines/dotnet/scaffolder.py +74 -74
- stackforge/project_name.py +34 -34
- stackforge/scaffold.py +90 -90
- stackforge/ui.py +72 -72
- stackforge/version.py +48 -48
- {stackforge_cli-0.1.3.dist-info → stackforge_cli-0.1.4.dist-info}/METADATA +107 -107
- stackforge_cli-0.1.4.dist-info/RECORD +19 -0
- {stackforge_cli-0.1.3.dist-info → stackforge_cli-0.1.4.dist-info}/WHEEL +1 -1
- stackforge_cli-0.1.3.dist-info/RECORD +0 -19
- {stackforge_cli-0.1.3.dist-info → stackforge_cli-0.1.4.dist-info}/entry_points.txt +0 -0
- {stackforge_cli-0.1.3.dist-info → stackforge_cli-0.1.4.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from .scaffolder import scaffold_folders
|
|
2
|
-
from .csproj_generator import generate_csproj
|
|
3
|
-
from .program_generator import generate_configure_services, generate_program_cs
|
|
4
|
-
from .docker_generator import generate_dockerfile, generate_docker_compose
|
|
5
|
-
from .config_generator import generate_env, generate_appsettings, generate_appsettings_development
|
|
6
|
-
from .git_generator import generate_gitignore, generate_github_workflow, git_init
|
|
7
|
-
from .api_generator import generate_api_structure
|
|
1
|
+
from .scaffolder import scaffold_folders
|
|
2
|
+
from .csproj_generator import generate_csproj
|
|
3
|
+
from .program_generator import generate_configure_services, generate_program_cs
|
|
4
|
+
from .docker_generator import generate_dockerfile, generate_docker_compose
|
|
5
|
+
from .config_generator import generate_env, generate_appsettings, generate_appsettings_development
|
|
6
|
+
from .git_generator import generate_gitignore, generate_github_workflow, git_init
|
|
7
|
+
from .api_generator import generate_api_structure
|
|
8
8
|
from .layers_generator import generate_domain_layer, generate_application_layer, generate_infrastructure_layer, generate_persistence_layer
|
|
@@ -1,313 +1,314 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from stackforge import ui
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def generate_api_structure(base: Path, project: str):
|
|
6
|
-
# Folders
|
|
7
|
-
folders = [
|
|
8
|
-
"API/Configurations/Swagger",
|
|
9
|
-
"API/Controllers/Main",
|
|
10
|
-
"API/Helpers",
|
|
11
|
-
"API/Interface",
|
|
12
|
-
"API/Options",
|
|
13
|
-
"API/Properties",
|
|
14
|
-
"API/Services",
|
|
15
|
-
"API/Swagger",
|
|
16
|
-
"API/DTOs",
|
|
17
|
-
]
|
|
18
|
-
|
|
19
|
-
for folder in folders:
|
|
20
|
-
(base / folder).mkdir(parents=True, exist_ok=True)
|
|
21
|
-
|
|
22
|
-
_generate_base_controller(base, project)
|
|
23
|
-
_generate_jwt_options(base, project)
|
|
24
|
-
_generate_ijwt_service(base, project)
|
|
25
|
-
_generate_jwt_service(base, project)
|
|
26
|
-
_generate_enum_schema_filter(base, project)
|
|
27
|
-
_generate_api_roles(base, project)
|
|
28
|
-
_generate_launch_settings(base)
|
|
29
|
-
_generate_login_dto(base, project)
|
|
30
|
-
_generate_account_controller(base, project)
|
|
31
|
-
|
|
32
|
-
ui.file_created("API/ structure and files")
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def _generate_base_controller(base: Path, project: str):
|
|
36
|
-
content = f"""using Microsoft.AspNetCore.Mvc;
|
|
37
|
-
using System.Security.Claims;
|
|
38
|
-
|
|
39
|
-
namespace {project}.API.Controllers
|
|
40
|
-
{{
|
|
41
|
-
[Route("api/[controller]")]
|
|
42
|
-
[ApiController]
|
|
43
|
-
public class BaseApiController : ControllerBase
|
|
44
|
-
{{
|
|
45
|
-
protected Guid GetUserId() => Guid.Parse(User?.FindFirst(ClaimTypes.NameIdentifier)?.Value!);
|
|
46
|
-
|
|
47
|
-
protected string GetCurrentEmail() => User?.FindFirstValue(ClaimTypes.Email)!;
|
|
48
|
-
|
|
49
|
-
protected Guid? GetOrganizationId()
|
|
50
|
-
{{
|
|
51
|
-
var claim = User?.FindFirst("OrganizationId");
|
|
52
|
-
|
|
53
|
-
if (claim == null || !Guid.TryParse(claim.Value, out var orgId))
|
|
54
|
-
return null;
|
|
55
|
-
|
|
56
|
-
return orgId;
|
|
57
|
-
}}
|
|
58
|
-
}}
|
|
59
|
-
}}
|
|
60
|
-
"""
|
|
61
|
-
(base / "API/Controllers/BaseApiController.cs").write_text(content)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def _generate_jwt_options(base: Path, project: str):
|
|
65
|
-
content = f"""namespace {project}.API.Options
|
|
66
|
-
{{
|
|
67
|
-
public class JwtOptions
|
|
68
|
-
{{
|
|
69
|
-
public string Issuer {{ get; set; }} = string.Empty;
|
|
70
|
-
public string Audience {{ get; set; }} = string.Empty;
|
|
71
|
-
public string SecretKey {{ get; set; }} = string.Empty;
|
|
72
|
-
public int ExpiryMinutes {{ get; set; }}
|
|
73
|
-
}}
|
|
74
|
-
}}
|
|
75
|
-
"""
|
|
76
|
-
(base / "API/Options/JwtOptions.cs").write_text(content)
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def _generate_ijwt_service(base: Path, project: str):
|
|
80
|
-
content = f"""namespace {project}.API.Interface
|
|
81
|
-
{{
|
|
82
|
-
public interface IJwtService
|
|
83
|
-
{{
|
|
84
|
-
string GenerateToken(Guid userId, string email);
|
|
85
|
-
}}
|
|
86
|
-
}}
|
|
87
|
-
"""
|
|
88
|
-
(base / "API/Interface/IJwtService.cs").write_text(content)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def _generate_jwt_service(base: Path, project: str):
|
|
92
|
-
content = f"""using {project}.API.Interface;
|
|
93
|
-
using {project}.API.Options;
|
|
94
|
-
using Microsoft.Extensions.Options;
|
|
95
|
-
using Microsoft.IdentityModel.Tokens;
|
|
96
|
-
using System.IdentityModel.Tokens.Jwt;
|
|
97
|
-
using System.Security.Claims;
|
|
98
|
-
using System.Text;
|
|
99
|
-
|
|
100
|
-
namespace {project}.API.Services
|
|
101
|
-
{{
|
|
102
|
-
public class JwtService : IJwtService
|
|
103
|
-
{{
|
|
104
|
-
private readonly JwtOptions _options;
|
|
105
|
-
|
|
106
|
-
public JwtService(IOptions<JwtOptions> options)
|
|
107
|
-
{{
|
|
108
|
-
_options = options.Value;
|
|
109
|
-
}}
|
|
110
|
-
|
|
111
|
-
public string GenerateToken(Guid userId, string email)
|
|
112
|
-
{{
|
|
113
|
-
var claims = new[]
|
|
114
|
-
{{
|
|
115
|
-
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
|
|
116
|
-
new Claim(ClaimTypes.Email, email),
|
|
117
|
-
}};
|
|
118
|
-
|
|
119
|
-
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.SecretKey));
|
|
120
|
-
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
|
121
|
-
|
|
122
|
-
var token = new JwtSecurityToken(
|
|
123
|
-
issuer: _options.Issuer,
|
|
124
|
-
audience: _options.Audience,
|
|
125
|
-
claims: claims,
|
|
126
|
-
expires: DateTime.UtcNow.AddMinutes(_options.ExpiryMinutes),
|
|
127
|
-
signingCredentials: creds);
|
|
128
|
-
|
|
129
|
-
return new JwtSecurityTokenHandler().WriteToken(token);
|
|
130
|
-
}}
|
|
131
|
-
}}
|
|
132
|
-
}}
|
|
133
|
-
"""
|
|
134
|
-
(base / "API/Services/JwtService.cs").write_text(content)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
def _generate_enum_schema_filter(base: Path, project: str):
|
|
138
|
-
content = f"""using Microsoft.OpenApi.Any;
|
|
139
|
-
using Microsoft.OpenApi.Models;
|
|
140
|
-
using Swashbuckle.AspNetCore.SwaggerGen;
|
|
141
|
-
using System.Runtime.Serialization;
|
|
142
|
-
|
|
143
|
-
namespace {project}.API.Swagger
|
|
144
|
-
{{
|
|
145
|
-
public class EnumMemberSchemaFilter : ISchemaFilter
|
|
146
|
-
{{
|
|
147
|
-
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
|
|
148
|
-
{{
|
|
149
|
-
if (!context.Type.IsEnum) return;
|
|
150
|
-
|
|
151
|
-
schema.Enum.Clear();
|
|
152
|
-
foreach (var member in Enum.GetNames(context.Type))
|
|
153
|
-
{{
|
|
154
|
-
var field = context.Type.GetField(member);
|
|
155
|
-
var attr = field?.GetCustomAttributes(typeof(EnumMemberAttribute), false)
|
|
156
|
-
.OfType<EnumMemberAttribute>()
|
|
157
|
-
.FirstOrDefault();
|
|
158
|
-
schema.Enum.Add(new OpenApiString(attr?.Value ?? member));
|
|
159
|
-
}}
|
|
160
|
-
}}
|
|
161
|
-
}}
|
|
162
|
-
}}
|
|
163
|
-
"""
|
|
164
|
-
(base / "API/Swagger/EnumMemberSchemaFilter.cs").write_text(content)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
def _generate_api_roles(base: Path, project: str):
|
|
168
|
-
content = f"""namespace {project}.API.Configurations.Swagger
|
|
169
|
-
{{
|
|
170
|
-
public static class ApiRoles
|
|
171
|
-
{{
|
|
172
|
-
public const string SuperAdmin = "SuperAdmin";
|
|
173
|
-
public const string Admin = "Admin";
|
|
174
|
-
public const string User = "User";
|
|
175
|
-
}}
|
|
176
|
-
}}
|
|
177
|
-
"""
|
|
178
|
-
(base / "API/Configurations/Swagger/ApiRoles.cs").write_text(content)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
def _generate_launch_settings(base: Path):
|
|
182
|
-
content = """{
|
|
183
|
-
"$schema": "https://json.schemastore.org/launchsettings.json",
|
|
184
|
-
"profiles": {
|
|
185
|
-
"http": {
|
|
186
|
-
"commandName": "Project",
|
|
187
|
-
"environmentVariables": {
|
|
188
|
-
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
189
|
-
},
|
|
190
|
-
"dotnetRunMessages": true,
|
|
191
|
-
"applicationUrl": "http://localhost:5000"
|
|
192
|
-
},
|
|
193
|
-
"https": {
|
|
194
|
-
"commandName": "Project",
|
|
195
|
-
"environmentVariables": {
|
|
196
|
-
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
197
|
-
},
|
|
198
|
-
"dotnetRunMessages": true,
|
|
199
|
-
"applicationUrl": "https://localhost:7013;http://localhost:5282"
|
|
200
|
-
},
|
|
201
|
-
"Container (Dockerfile)": {
|
|
202
|
-
"commandName": "Docker",
|
|
203
|
-
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
|
|
204
|
-
"environmentVariables": {
|
|
205
|
-
"ASPNETCORE_HTTPS_PORTS": "8081",
|
|
206
|
-
"ASPNETCORE_HTTP_PORTS": "8080"
|
|
207
|
-
},
|
|
208
|
-
"publishAllPorts": true,
|
|
209
|
-
"useSSL": true
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
"""
|
|
214
|
-
(base / "API/Properties/launchSettings.json").write_text(content)
|
|
215
|
-
|
|
216
|
-
def _generate_login_dto(base: Path, project: str):
|
|
217
|
-
content = f"""namespace {project}.API.DTOs
|
|
218
|
-
{{
|
|
219
|
-
public class LoginRequest
|
|
220
|
-
{{
|
|
221
|
-
public string Email {{ get; set; }} = string.Empty;
|
|
222
|
-
public string Password {{ get; set; }} = string.Empty;
|
|
223
|
-
}}
|
|
224
|
-
|
|
225
|
-
public class LoginResponse
|
|
226
|
-
{{
|
|
227
|
-
public string Token {{ get; set; }} = string.Empty;
|
|
228
|
-
public string Email {{ get; set; }} = string.Empty;
|
|
229
|
-
public string FullName {{ get; set; }} = string.Empty;
|
|
230
|
-
}}
|
|
231
|
-
|
|
232
|
-
public class CurrentUserResponse
|
|
233
|
-
{{
|
|
234
|
-
public Guid Id {{ get; set; }}
|
|
235
|
-
public string Email {{ get; set; }} = string.Empty;
|
|
236
|
-
public string FullName {{ get; set; }} = string.Empty;
|
|
237
|
-
public IList<string> Roles {{ get; set; }} = new List<string>();
|
|
238
|
-
}}
|
|
239
|
-
}}
|
|
240
|
-
"""
|
|
241
|
-
(base / "API/DTOs/AccountDTOs.cs").write_text(content)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
def _generate_account_controller(base: Path, project: str):
|
|
245
|
-
content = f"""using {project}.API.Controllers;
|
|
246
|
-
using {project}.API.DTOs;
|
|
247
|
-
using {project}.API.Interface;
|
|
248
|
-
using {project}.Domain.Entities.Identity;
|
|
249
|
-
using Microsoft.AspNetCore.Authorization;
|
|
250
|
-
using Microsoft.AspNetCore.Identity;
|
|
251
|
-
using Microsoft.AspNetCore.Mvc;
|
|
252
|
-
|
|
253
|
-
namespace {project}.API.Controllers.Main
|
|
254
|
-
{{
|
|
255
|
-
public class AccountController : BaseApiController
|
|
256
|
-
{{
|
|
257
|
-
private readonly UserManager<User> _userManager;
|
|
258
|
-
private readonly SignInManager<User> _signInManager;
|
|
259
|
-
private readonly IJwtService _jwtService;
|
|
260
|
-
|
|
261
|
-
public AccountController(
|
|
262
|
-
UserManager<User> userManager,
|
|
263
|
-
SignInManager<User> signInManager,
|
|
264
|
-
IJwtService jwtService)
|
|
265
|
-
{{
|
|
266
|
-
_userManager = userManager;
|
|
267
|
-
_signInManager = signInManager;
|
|
268
|
-
_jwtService = jwtService;
|
|
269
|
-
}}
|
|
270
|
-
|
|
271
|
-
[
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
[
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
}}
|
|
312
|
-
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from stackforge import ui
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def generate_api_structure(base: Path, project: str):
|
|
6
|
+
# Folders
|
|
7
|
+
folders = [
|
|
8
|
+
"API/Configurations/Swagger",
|
|
9
|
+
"API/Controllers/Main",
|
|
10
|
+
"API/Helpers",
|
|
11
|
+
"API/Interface",
|
|
12
|
+
"API/Options",
|
|
13
|
+
"API/Properties",
|
|
14
|
+
"API/Services",
|
|
15
|
+
"API/Swagger",
|
|
16
|
+
"API/DTOs",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
for folder in folders:
|
|
20
|
+
(base / folder).mkdir(parents=True, exist_ok=True)
|
|
21
|
+
|
|
22
|
+
_generate_base_controller(base, project)
|
|
23
|
+
_generate_jwt_options(base, project)
|
|
24
|
+
_generate_ijwt_service(base, project)
|
|
25
|
+
_generate_jwt_service(base, project)
|
|
26
|
+
_generate_enum_schema_filter(base, project)
|
|
27
|
+
_generate_api_roles(base, project)
|
|
28
|
+
_generate_launch_settings(base)
|
|
29
|
+
_generate_login_dto(base, project)
|
|
30
|
+
_generate_account_controller(base, project)
|
|
31
|
+
|
|
32
|
+
ui.file_created("API/ structure and files")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _generate_base_controller(base: Path, project: str):
|
|
36
|
+
content = f"""using Microsoft.AspNetCore.Mvc;
|
|
37
|
+
using System.Security.Claims;
|
|
38
|
+
|
|
39
|
+
namespace {project}.API.Controllers
|
|
40
|
+
{{
|
|
41
|
+
[Route("api/[controller]")]
|
|
42
|
+
[ApiController]
|
|
43
|
+
public class BaseApiController : ControllerBase
|
|
44
|
+
{{
|
|
45
|
+
protected Guid GetUserId() => Guid.Parse(User?.FindFirst(ClaimTypes.NameIdentifier)?.Value!);
|
|
46
|
+
|
|
47
|
+
protected string GetCurrentEmail() => User?.FindFirstValue(ClaimTypes.Email)!;
|
|
48
|
+
|
|
49
|
+
protected Guid? GetOrganizationId()
|
|
50
|
+
{{
|
|
51
|
+
var claim = User?.FindFirst("OrganizationId");
|
|
52
|
+
|
|
53
|
+
if (claim == null || !Guid.TryParse(claim.Value, out var orgId))
|
|
54
|
+
return null;
|
|
55
|
+
|
|
56
|
+
return orgId;
|
|
57
|
+
}}
|
|
58
|
+
}}
|
|
59
|
+
}}
|
|
60
|
+
"""
|
|
61
|
+
(base / "API/Controllers/BaseApiController.cs").write_text(content)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _generate_jwt_options(base: Path, project: str):
|
|
65
|
+
content = f"""namespace {project}.API.Options
|
|
66
|
+
{{
|
|
67
|
+
public class JwtOptions
|
|
68
|
+
{{
|
|
69
|
+
public string Issuer {{ get; set; }} = string.Empty;
|
|
70
|
+
public string Audience {{ get; set; }} = string.Empty;
|
|
71
|
+
public string SecretKey {{ get; set; }} = string.Empty;
|
|
72
|
+
public int ExpiryMinutes {{ get; set; }}
|
|
73
|
+
}}
|
|
74
|
+
}}
|
|
75
|
+
"""
|
|
76
|
+
(base / "API/Options/JwtOptions.cs").write_text(content)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _generate_ijwt_service(base: Path, project: str):
|
|
80
|
+
content = f"""namespace {project}.API.Interface
|
|
81
|
+
{{
|
|
82
|
+
public interface IJwtService
|
|
83
|
+
{{
|
|
84
|
+
string GenerateToken(Guid userId, string email);
|
|
85
|
+
}}
|
|
86
|
+
}}
|
|
87
|
+
"""
|
|
88
|
+
(base / "API/Interface/IJwtService.cs").write_text(content)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _generate_jwt_service(base: Path, project: str):
|
|
92
|
+
content = f"""using {project}.API.Interface;
|
|
93
|
+
using {project}.API.Options;
|
|
94
|
+
using Microsoft.Extensions.Options;
|
|
95
|
+
using Microsoft.IdentityModel.Tokens;
|
|
96
|
+
using System.IdentityModel.Tokens.Jwt;
|
|
97
|
+
using System.Security.Claims;
|
|
98
|
+
using System.Text;
|
|
99
|
+
|
|
100
|
+
namespace {project}.API.Services
|
|
101
|
+
{{
|
|
102
|
+
public class JwtService : IJwtService
|
|
103
|
+
{{
|
|
104
|
+
private readonly JwtOptions _options;
|
|
105
|
+
|
|
106
|
+
public JwtService(IOptions<JwtOptions> options)
|
|
107
|
+
{{
|
|
108
|
+
_options = options.Value;
|
|
109
|
+
}}
|
|
110
|
+
|
|
111
|
+
public string GenerateToken(Guid userId, string email)
|
|
112
|
+
{{
|
|
113
|
+
var claims = new[]
|
|
114
|
+
{{
|
|
115
|
+
new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
|
|
116
|
+
new Claim(ClaimTypes.Email, email),
|
|
117
|
+
}};
|
|
118
|
+
|
|
119
|
+
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.SecretKey));
|
|
120
|
+
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
|
121
|
+
|
|
122
|
+
var token = new JwtSecurityToken(
|
|
123
|
+
issuer: _options.Issuer,
|
|
124
|
+
audience: _options.Audience,
|
|
125
|
+
claims: claims,
|
|
126
|
+
expires: DateTime.UtcNow.AddMinutes(_options.ExpiryMinutes),
|
|
127
|
+
signingCredentials: creds);
|
|
128
|
+
|
|
129
|
+
return new JwtSecurityTokenHandler().WriteToken(token);
|
|
130
|
+
}}
|
|
131
|
+
}}
|
|
132
|
+
}}
|
|
133
|
+
"""
|
|
134
|
+
(base / "API/Services/JwtService.cs").write_text(content)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _generate_enum_schema_filter(base: Path, project: str):
|
|
138
|
+
content = f"""using Microsoft.OpenApi.Any;
|
|
139
|
+
using Microsoft.OpenApi.Models;
|
|
140
|
+
using Swashbuckle.AspNetCore.SwaggerGen;
|
|
141
|
+
using System.Runtime.Serialization;
|
|
142
|
+
|
|
143
|
+
namespace {project}.API.Swagger
|
|
144
|
+
{{
|
|
145
|
+
public class EnumMemberSchemaFilter : ISchemaFilter
|
|
146
|
+
{{
|
|
147
|
+
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
|
|
148
|
+
{{
|
|
149
|
+
if (!context.Type.IsEnum) return;
|
|
150
|
+
|
|
151
|
+
schema.Enum.Clear();
|
|
152
|
+
foreach (var member in Enum.GetNames(context.Type))
|
|
153
|
+
{{
|
|
154
|
+
var field = context.Type.GetField(member);
|
|
155
|
+
var attr = field?.GetCustomAttributes(typeof(EnumMemberAttribute), false)
|
|
156
|
+
.OfType<EnumMemberAttribute>()
|
|
157
|
+
.FirstOrDefault();
|
|
158
|
+
schema.Enum.Add(new OpenApiString(attr?.Value ?? member));
|
|
159
|
+
}}
|
|
160
|
+
}}
|
|
161
|
+
}}
|
|
162
|
+
}}
|
|
163
|
+
"""
|
|
164
|
+
(base / "API/Swagger/EnumMemberSchemaFilter.cs").write_text(content)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _generate_api_roles(base: Path, project: str):
|
|
168
|
+
content = f"""namespace {project}.API.Configurations.Swagger
|
|
169
|
+
{{
|
|
170
|
+
public static class ApiRoles
|
|
171
|
+
{{
|
|
172
|
+
public const string SuperAdmin = "SuperAdmin";
|
|
173
|
+
public const string Admin = "Admin";
|
|
174
|
+
public const string User = "User";
|
|
175
|
+
}}
|
|
176
|
+
}}
|
|
177
|
+
"""
|
|
178
|
+
(base / "API/Configurations/Swagger/ApiRoles.cs").write_text(content)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def _generate_launch_settings(base: Path):
|
|
182
|
+
content = """{
|
|
183
|
+
"$schema": "https://json.schemastore.org/launchsettings.json",
|
|
184
|
+
"profiles": {
|
|
185
|
+
"http": {
|
|
186
|
+
"commandName": "Project",
|
|
187
|
+
"environmentVariables": {
|
|
188
|
+
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
189
|
+
},
|
|
190
|
+
"dotnetRunMessages": true,
|
|
191
|
+
"applicationUrl": "http://localhost:5000"
|
|
192
|
+
},
|
|
193
|
+
"https": {
|
|
194
|
+
"commandName": "Project",
|
|
195
|
+
"environmentVariables": {
|
|
196
|
+
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
197
|
+
},
|
|
198
|
+
"dotnetRunMessages": true,
|
|
199
|
+
"applicationUrl": "https://localhost:7013;http://localhost:5282"
|
|
200
|
+
},
|
|
201
|
+
"Container (Dockerfile)": {
|
|
202
|
+
"commandName": "Docker",
|
|
203
|
+
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
|
|
204
|
+
"environmentVariables": {
|
|
205
|
+
"ASPNETCORE_HTTPS_PORTS": "8081",
|
|
206
|
+
"ASPNETCORE_HTTP_PORTS": "8080"
|
|
207
|
+
},
|
|
208
|
+
"publishAllPorts": true,
|
|
209
|
+
"useSSL": true
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
"""
|
|
214
|
+
(base / "API/Properties/launchSettings.json").write_text(content)
|
|
215
|
+
|
|
216
|
+
def _generate_login_dto(base: Path, project: str):
|
|
217
|
+
content = f"""namespace {project}.API.DTOs
|
|
218
|
+
{{
|
|
219
|
+
public class LoginRequest
|
|
220
|
+
{{
|
|
221
|
+
public string Email {{ get; set; }} = string.Empty;
|
|
222
|
+
public string Password {{ get; set; }} = string.Empty;
|
|
223
|
+
}}
|
|
224
|
+
|
|
225
|
+
public class LoginResponse
|
|
226
|
+
{{
|
|
227
|
+
public string Token {{ get; set; }} = string.Empty;
|
|
228
|
+
public string Email {{ get; set; }} = string.Empty;
|
|
229
|
+
public string FullName {{ get; set; }} = string.Empty;
|
|
230
|
+
}}
|
|
231
|
+
|
|
232
|
+
public class CurrentUserResponse
|
|
233
|
+
{{
|
|
234
|
+
public Guid Id {{ get; set; }}
|
|
235
|
+
public string Email {{ get; set; }} = string.Empty;
|
|
236
|
+
public string FullName {{ get; set; }} = string.Empty;
|
|
237
|
+
public IList<string> Roles {{ get; set; }} = new List<string>();
|
|
238
|
+
}}
|
|
239
|
+
}}
|
|
240
|
+
"""
|
|
241
|
+
(base / "API/DTOs/AccountDTOs.cs").write_text(content)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _generate_account_controller(base: Path, project: str):
|
|
245
|
+
content = f"""using {project}.API.Controllers;
|
|
246
|
+
using {project}.API.DTOs;
|
|
247
|
+
using {project}.API.Interface;
|
|
248
|
+
using {project}.Domain.Entities.Identity;
|
|
249
|
+
using Microsoft.AspNetCore.Authorization;
|
|
250
|
+
using Microsoft.AspNetCore.Identity;
|
|
251
|
+
using Microsoft.AspNetCore.Mvc;
|
|
252
|
+
|
|
253
|
+
namespace {project}.API.Controllers.Main
|
|
254
|
+
{{
|
|
255
|
+
public class AccountController : BaseApiController
|
|
256
|
+
{{
|
|
257
|
+
private readonly UserManager<User> _userManager;
|
|
258
|
+
private readonly SignInManager<User> _signInManager;
|
|
259
|
+
private readonly IJwtService _jwtService;
|
|
260
|
+
|
|
261
|
+
public AccountController(
|
|
262
|
+
UserManager<User> userManager,
|
|
263
|
+
SignInManager<User> signInManager,
|
|
264
|
+
IJwtService jwtService)
|
|
265
|
+
{{
|
|
266
|
+
_userManager = userManager;
|
|
267
|
+
_signInManager = signInManager;
|
|
268
|
+
_jwtService = jwtService;
|
|
269
|
+
}}
|
|
270
|
+
|
|
271
|
+
[AllowAnonymous]
|
|
272
|
+
[HttpPost("login")]
|
|
273
|
+
public async Task<IActionResult> Login([FromBody] LoginRequest request)
|
|
274
|
+
{{
|
|
275
|
+
var user = await _userManager.FindByEmailAsync(request.Email);
|
|
276
|
+
if (user == null)
|
|
277
|
+
return Unauthorized("Invalid credentials.");
|
|
278
|
+
|
|
279
|
+
var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, false);
|
|
280
|
+
if (!result.Succeeded)
|
|
281
|
+
return Unauthorized("Invalid credentials.");
|
|
282
|
+
|
|
283
|
+
var token = _jwtService.GenerateToken(user.Id, user.Email!);
|
|
284
|
+
|
|
285
|
+
return Ok(new LoginResponse
|
|
286
|
+
{{
|
|
287
|
+
Token = token,
|
|
288
|
+
Email = user.Email!,
|
|
289
|
+
FullName = $"{{user.FirstName}} {{user.LastName}}"
|
|
290
|
+
}});
|
|
291
|
+
}}
|
|
292
|
+
|
|
293
|
+
[Authorize]
|
|
294
|
+
[HttpGet("me")]
|
|
295
|
+
public async Task<IActionResult> Me()
|
|
296
|
+
{{
|
|
297
|
+
var user = await _userManager.FindByIdAsync(GetUserId().ToString());
|
|
298
|
+
if (user == null)
|
|
299
|
+
return NotFound("User not found.");
|
|
300
|
+
|
|
301
|
+
var roles = await _userManager.GetRolesAsync(user);
|
|
302
|
+
|
|
303
|
+
return Ok(new CurrentUserResponse
|
|
304
|
+
{{
|
|
305
|
+
Id = user.Id,
|
|
306
|
+
Email = user.Email!,
|
|
307
|
+
FullName = $"{{user.FirstName}} {{user.LastName}}",
|
|
308
|
+
Roles = roles
|
|
309
|
+
}});
|
|
310
|
+
}}
|
|
311
|
+
}}
|
|
312
|
+
}}
|
|
313
|
+
"""
|
|
313
314
|
(base / "API/Controllers/Main/AccountController.cs").write_text(content)
|