stackforge-cli 0.1.0__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/__init__.py +0 -0
- stackforge/engines/dotnet/__init__.py +8 -0
- stackforge/engines/dotnet/api_generator.py +312 -0
- stackforge/engines/dotnet/config_generator.py +76 -0
- stackforge/engines/dotnet/csproj_generator.py +82 -0
- stackforge/engines/dotnet/docker_generator.py +63 -0
- stackforge/engines/dotnet/git_generator.py +67 -0
- stackforge/engines/dotnet/layers_generator.py +543 -0
- stackforge/engines/dotnet/program_generator.py +194 -0
- stackforge/engines/dotnet/scaffolder.py +71 -0
- stackforge/scaffold.py +82 -0
- stackforge_cli-0.1.0.dist-info/METADATA +46 -0
- stackforge_cli-0.1.0.dist-info/RECORD +16 -0
- stackforge_cli-0.1.0.dist-info/WHEEL +5 -0
- stackforge_cli-0.1.0.dist-info/entry_points.txt +2 -0
- stackforge_cli-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def generate_application_layer(base: Path, project: str):
|
|
5
|
+
folders = [
|
|
6
|
+
"Application/Common/Behaviors",
|
|
7
|
+
"Application/Common/Constants",
|
|
8
|
+
"Application/Common/Exceptions",
|
|
9
|
+
"Application/Common/Models/Serialization",
|
|
10
|
+
"Application/Helpers",
|
|
11
|
+
"Application/Interfaces",
|
|
12
|
+
"Application/Mappings",
|
|
13
|
+
"Application/Services",
|
|
14
|
+
]
|
|
15
|
+
for folder in folders:
|
|
16
|
+
(base / folder).mkdir(parents=True, exist_ok=True)
|
|
17
|
+
|
|
18
|
+
_gen_validation_behavior(base, project)
|
|
19
|
+
_gen_error_messages(base, project)
|
|
20
|
+
_gen_app_exceptions(base, project)
|
|
21
|
+
_gen_not_found_exception(base, project)
|
|
22
|
+
_gen_api_response(base, project)
|
|
23
|
+
_gen_result(base, project)
|
|
24
|
+
_gen_paging_params(base, project)
|
|
25
|
+
_gen_paginated_result(base, project)
|
|
26
|
+
_gen_paged_list(base, project)
|
|
27
|
+
_gen_paged_response(base, project)
|
|
28
|
+
_gen_iso_datetime(base, project)
|
|
29
|
+
|
|
30
|
+
print(" [+] Application/ structure and files")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def generate_domain_layer(base: Path, project: str):
|
|
34
|
+
folders = [
|
|
35
|
+
"Domain/Common",
|
|
36
|
+
"Domain/Entities/Identity",
|
|
37
|
+
"Domain/Enums",
|
|
38
|
+
"Domain/Utils",
|
|
39
|
+
]
|
|
40
|
+
for folder in folders:
|
|
41
|
+
(base / folder).mkdir(parents=True, exist_ok=True)
|
|
42
|
+
|
|
43
|
+
_gen_base_entity(base, project)
|
|
44
|
+
_gen_enum_member_extensions(base, project)
|
|
45
|
+
_gen_role(base, project)
|
|
46
|
+
_gen_user(base, project)
|
|
47
|
+
_gen_user_role(base, project)
|
|
48
|
+
_gen_global_usings(base, project)
|
|
49
|
+
|
|
50
|
+
print(" [+] Domain/ structure and files")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def generate_infrastructure_layer(base: Path, project: str):
|
|
54
|
+
folders = [
|
|
55
|
+
"Infrastructure/BackgroundServices",
|
|
56
|
+
"Infrastructure/Configurations",
|
|
57
|
+
"Infrastructure/Options",
|
|
58
|
+
"Infrastructure/Services",
|
|
59
|
+
]
|
|
60
|
+
for folder in folders:
|
|
61
|
+
(base / folder).mkdir(parents=True, exist_ok=True)
|
|
62
|
+
|
|
63
|
+
print(" [+] Infrastructure/ structure and files")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def generate_persistence_layer(base: Path, project: str):
|
|
67
|
+
folders = [
|
|
68
|
+
"Persistence/Configurations",
|
|
69
|
+
"Persistence/Extensions",
|
|
70
|
+
"Persistence/Migrations",
|
|
71
|
+
"Persistence/Seeders",
|
|
72
|
+
]
|
|
73
|
+
for folder in folders:
|
|
74
|
+
(base / folder).mkdir(parents=True, exist_ok=True)
|
|
75
|
+
|
|
76
|
+
_gen_data_context(base, project)
|
|
77
|
+
_gen_role_seeder(base, project)
|
|
78
|
+
_gen_user_seeder(base, project)
|
|
79
|
+
_gen_user_role_configuration(base, project)
|
|
80
|
+
|
|
81
|
+
print(" [+] Persistence/ structure and files")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# ── Application files ──────────────────────────────────────────────────────────
|
|
85
|
+
|
|
86
|
+
def _gen_validation_behavior(base: Path, project: str):
|
|
87
|
+
content = f"""using FluentValidation;
|
|
88
|
+
using MediatR;
|
|
89
|
+
|
|
90
|
+
namespace {project}.Application.Common.Behaviors
|
|
91
|
+
{{
|
|
92
|
+
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
|
93
|
+
where TRequest : notnull
|
|
94
|
+
{{
|
|
95
|
+
private readonly IEnumerable<IValidator<TRequest>> _validators;
|
|
96
|
+
|
|
97
|
+
public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
|
|
98
|
+
{{
|
|
99
|
+
_validators = validators;
|
|
100
|
+
}}
|
|
101
|
+
|
|
102
|
+
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
|
|
103
|
+
{{
|
|
104
|
+
if (_validators.Any())
|
|
105
|
+
{{
|
|
106
|
+
var context = new ValidationContext<TRequest>(request);
|
|
107
|
+
var validationResults = await Task.WhenAll(_validators.Select(v => v.ValidateAsync(context, cancellationToken)));
|
|
108
|
+
var failures = validationResults.SelectMany(r => r.Errors).Where(f => f != null).ToList();
|
|
109
|
+
if (failures.Count != 0)
|
|
110
|
+
throw new ValidationException(failures);
|
|
111
|
+
}}
|
|
112
|
+
return await next();
|
|
113
|
+
}}
|
|
114
|
+
}}
|
|
115
|
+
}}
|
|
116
|
+
"""
|
|
117
|
+
(base / "Application/Common/Behaviors/ValidationBehavior.cs").write_text(content)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _gen_error_messages(base: Path, project: str):
|
|
121
|
+
content = f"""namespace {project}.Application.Common.Constants
|
|
122
|
+
{{
|
|
123
|
+
public static class ErrorMessages
|
|
124
|
+
{{
|
|
125
|
+
public const string NotFound = "The requested resource was not found.";
|
|
126
|
+
public const string Unauthorized = "You are not authorized to perform this action.";
|
|
127
|
+
public const string BadRequest = "The request is invalid.";
|
|
128
|
+
public const string InternalServerError = "An unexpected error occurred.";
|
|
129
|
+
}}
|
|
130
|
+
}}
|
|
131
|
+
"""
|
|
132
|
+
(base / "Application/Common/Constants/ErrorMessages.cs").write_text(content)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _gen_app_exceptions(base: Path, project: str):
|
|
136
|
+
content = f"""namespace {project}.Application.Common.Exceptions
|
|
137
|
+
{{
|
|
138
|
+
public class AppException : Exception
|
|
139
|
+
{{
|
|
140
|
+
public int StatusCode {{ get; }}
|
|
141
|
+
|
|
142
|
+
public AppException(string message, int statusCode = 400) : base(message)
|
|
143
|
+
{{
|
|
144
|
+
StatusCode = statusCode;
|
|
145
|
+
}}
|
|
146
|
+
}}
|
|
147
|
+
}}
|
|
148
|
+
"""
|
|
149
|
+
(base / "Application/Common/Exceptions/AppExceptions.cs").write_text(content)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _gen_not_found_exception(base: Path, project: str):
|
|
153
|
+
content = f"""namespace {project}.Application.Common.Exceptions
|
|
154
|
+
{{
|
|
155
|
+
public class NotFoundException : Exception
|
|
156
|
+
{{
|
|
157
|
+
public NotFoundException(string name, object key)
|
|
158
|
+
: base($"{{name}} ({{key}}) was not found.")
|
|
159
|
+
{{
|
|
160
|
+
}}
|
|
161
|
+
}}
|
|
162
|
+
}}
|
|
163
|
+
"""
|
|
164
|
+
(base / "Application/Common/Exceptions/NotFoundException.cs").write_text(content)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _gen_api_response(base: Path, project: str):
|
|
168
|
+
content = f"""namespace {project}.Application.Common.Models
|
|
169
|
+
{{
|
|
170
|
+
public class ApiResponse<T>
|
|
171
|
+
{{
|
|
172
|
+
public bool Success {{ get; set; }}
|
|
173
|
+
public string? Message {{ get; set; }}
|
|
174
|
+
public T? Data {{ get; set; }}
|
|
175
|
+
|
|
176
|
+
public static ApiResponse<T> Ok(T data, string message = "Success") =>
|
|
177
|
+
new() {{ Success = true, Message = message, Data = data }};
|
|
178
|
+
|
|
179
|
+
public static ApiResponse<T> Fail(string message) =>
|
|
180
|
+
new() {{ Success = false, Message = message }};
|
|
181
|
+
}}
|
|
182
|
+
}}
|
|
183
|
+
"""
|
|
184
|
+
(base / "Application/Common/Models/ApiResponse.cs").write_text(content)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _gen_result(base: Path, project: str):
|
|
188
|
+
content = f"""namespace {project}.Application.Common.Models
|
|
189
|
+
{{
|
|
190
|
+
public class Result
|
|
191
|
+
{{
|
|
192
|
+
public bool IsSuccess {{ get; }}
|
|
193
|
+
public string? Error {{ get; }}
|
|
194
|
+
|
|
195
|
+
protected Result(bool isSuccess, string? error)
|
|
196
|
+
{{
|
|
197
|
+
IsSuccess = isSuccess;
|
|
198
|
+
Error = error;
|
|
199
|
+
}}
|
|
200
|
+
|
|
201
|
+
public static Result Success() => new(true, null);
|
|
202
|
+
public static Result Failure(string error) => new(false, error);
|
|
203
|
+
}}
|
|
204
|
+
|
|
205
|
+
public class Result<T> : Result
|
|
206
|
+
{{
|
|
207
|
+
public T? Value {{ get; }}
|
|
208
|
+
|
|
209
|
+
protected Result(bool isSuccess, T? value, string? error) : base(isSuccess, error)
|
|
210
|
+
{{
|
|
211
|
+
Value = value;
|
|
212
|
+
}}
|
|
213
|
+
|
|
214
|
+
public static Result<T> Success(T value) => new(true, value, null);
|
|
215
|
+
public static new Result<T> Failure(string error) => new(false, default, error);
|
|
216
|
+
}}
|
|
217
|
+
}}
|
|
218
|
+
"""
|
|
219
|
+
(base / "Application/Common/Models/Result.cs").write_text(content)
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _gen_paging_params(base: Path, project: str):
|
|
223
|
+
content = f"""namespace {project}.Application.Common.Models
|
|
224
|
+
{{
|
|
225
|
+
public class PagingParams
|
|
226
|
+
{{
|
|
227
|
+
public int PageNumber {{ get; set; }} = 1;
|
|
228
|
+
public int PageSize {{ get; set; }} = 10;
|
|
229
|
+
}}
|
|
230
|
+
}}
|
|
231
|
+
"""
|
|
232
|
+
(base / "Application/Common/Models/PagingParams.cs").write_text(content)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _gen_paginated_result(base: Path, project: str):
|
|
236
|
+
content = f"""namespace {project}.Application.Common.Models
|
|
237
|
+
{{
|
|
238
|
+
public class PaginatedResult<T>
|
|
239
|
+
{{
|
|
240
|
+
public List<T> Items {{ get; set; }} = new();
|
|
241
|
+
public int TotalCount {{ get; set; }}
|
|
242
|
+
public int PageNumber {{ get; set; }}
|
|
243
|
+
public int PageSize {{ get; set; }}
|
|
244
|
+
public int TotalPages => (int)Math.Ceiling(TotalCount / (double)PageSize);
|
|
245
|
+
public bool HasPreviousPage => PageNumber > 1;
|
|
246
|
+
public bool HasNextPage => PageNumber < TotalPages;
|
|
247
|
+
}}
|
|
248
|
+
}}
|
|
249
|
+
"""
|
|
250
|
+
(base / "Application/Common/Models/PaginatedResult.cs").write_text(content)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _gen_paged_list(base: Path, project: str):
|
|
254
|
+
content = f"""using Microsoft.EntityFrameworkCore;
|
|
255
|
+
|
|
256
|
+
namespace {project}.Application.Common.Models
|
|
257
|
+
{{
|
|
258
|
+
public class PagedList<T>
|
|
259
|
+
{{
|
|
260
|
+
public List<T> Items {{ get; }}
|
|
261
|
+
public int TotalCount {{ get; }}
|
|
262
|
+
public int PageNumber {{ get; }}
|
|
263
|
+
public int PageSize {{ get; }}
|
|
264
|
+
public int TotalPages => (int)Math.Ceiling(TotalCount / (double)PageSize);
|
|
265
|
+
public bool HasPreviousPage => PageNumber > 1;
|
|
266
|
+
public bool HasNextPage => PageNumber < TotalPages;
|
|
267
|
+
|
|
268
|
+
private PagedList(List<T> items, int totalCount, int pageNumber, int pageSize)
|
|
269
|
+
{{
|
|
270
|
+
Items = items;
|
|
271
|
+
TotalCount = totalCount;
|
|
272
|
+
PageNumber = pageNumber;
|
|
273
|
+
PageSize = pageSize;
|
|
274
|
+
}}
|
|
275
|
+
|
|
276
|
+
public static async Task<PagedList<T>> CreateAsync(IQueryable<T> source, int pageNumber, int pageSize)
|
|
277
|
+
{{
|
|
278
|
+
var totalCount = await source.CountAsync();
|
|
279
|
+
var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync();
|
|
280
|
+
return new PagedList<T>(items, totalCount, pageNumber, pageSize);
|
|
281
|
+
}}
|
|
282
|
+
}}
|
|
283
|
+
}}
|
|
284
|
+
"""
|
|
285
|
+
(base / "Application/Common/Models/PagedList.cs").write_text(content)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _gen_paged_response(base: Path, project: str):
|
|
289
|
+
content = f"""namespace {project}.Application.Common.Models
|
|
290
|
+
{{
|
|
291
|
+
public class PagedResponse<T>
|
|
292
|
+
{{
|
|
293
|
+
public List<T> Items {{ get; set; }} = new();
|
|
294
|
+
public int TotalCount {{ get; set; }}
|
|
295
|
+
public int PageNumber {{ get; set; }}
|
|
296
|
+
public int PageSize {{ get; set; }}
|
|
297
|
+
public int TotalPages {{ get; set; }}
|
|
298
|
+
public bool HasPreviousPage {{ get; set; }}
|
|
299
|
+
public bool HasNextPage {{ get; set; }}
|
|
300
|
+
}}
|
|
301
|
+
}}
|
|
302
|
+
"""
|
|
303
|
+
(base / "Application/Common/Models/PagedResponse.cs").write_text(content)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _gen_iso_datetime(base: Path, project: str):
|
|
307
|
+
content = f"""using System.Text.Json;
|
|
308
|
+
using System.Text.Json.Serialization;
|
|
309
|
+
|
|
310
|
+
namespace {project}.Application.Common.Models.Serialization
|
|
311
|
+
{{
|
|
312
|
+
public class IsoDateTimeConverter : JsonConverter<DateTime>
|
|
313
|
+
{{
|
|
314
|
+
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
315
|
+
=> DateTime.Parse(reader.GetString()!);
|
|
316
|
+
|
|
317
|
+
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
|
|
318
|
+
=> writer.WriteStringValue(value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"));
|
|
319
|
+
}}
|
|
320
|
+
}}
|
|
321
|
+
"""
|
|
322
|
+
(base / "Application/Common/Models/Serialization/IsoDateTime.cs").write_text(content)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
# ── Domain files ───────────────────────────────────────────────────────────────
|
|
326
|
+
|
|
327
|
+
def _gen_base_entity(base: Path, project: str):
|
|
328
|
+
content = f"""namespace {project}.Domain.Common
|
|
329
|
+
{{
|
|
330
|
+
public abstract class BaseEntity
|
|
331
|
+
{{
|
|
332
|
+
public Guid Id {{ get; set; }} = Guid.NewGuid();
|
|
333
|
+
public DateTime CreatedAt {{ get; set; }} = DateTime.UtcNow;
|
|
334
|
+
public DateTime UpdatedAt {{ get; set; }} = DateTime.UtcNow;
|
|
335
|
+
}}
|
|
336
|
+
}}
|
|
337
|
+
"""
|
|
338
|
+
(base / "Domain/Common/BaseEntity.cs").write_text(content)
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def _gen_enum_member_extensions(base: Path, project: str):
|
|
342
|
+
content = f"""using System.Runtime.Serialization;
|
|
343
|
+
using System.Reflection;
|
|
344
|
+
|
|
345
|
+
namespace {project}.Domain.Common
|
|
346
|
+
{{
|
|
347
|
+
public static class EnumMemberExtensions
|
|
348
|
+
{{
|
|
349
|
+
public static string ToEnumMemberValue<T>(this T value) where T : Enum
|
|
350
|
+
{{
|
|
351
|
+
return typeof(T)
|
|
352
|
+
.GetField(value.ToString())
|
|
353
|
+
?.GetCustomAttribute<EnumMemberAttribute>()
|
|
354
|
+
?.Value ?? value.ToString();
|
|
355
|
+
}}
|
|
356
|
+
}}
|
|
357
|
+
}}
|
|
358
|
+
"""
|
|
359
|
+
(base / "Domain/Common/EnumMemberExtensions.cs").write_text(content)
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def _gen_role(base: Path, project: str):
|
|
363
|
+
content = f"""using Microsoft.AspNetCore.Identity;
|
|
364
|
+
|
|
365
|
+
namespace {project}.Domain.Entities.Identity
|
|
366
|
+
{{
|
|
367
|
+
public class Role : IdentityRole<Guid>
|
|
368
|
+
{{
|
|
369
|
+
public ICollection<UserRole> UserRoles {{ get; set; }} = new List<UserRole>();
|
|
370
|
+
}}
|
|
371
|
+
}}
|
|
372
|
+
"""
|
|
373
|
+
(base / "Domain/Entities/Identity/Role.cs").write_text(content)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def _gen_user(base: Path, project: str):
|
|
377
|
+
content = f"""using Microsoft.AspNetCore.Identity;
|
|
378
|
+
|
|
379
|
+
namespace {project}.Domain.Entities.Identity
|
|
380
|
+
{{
|
|
381
|
+
public class User : IdentityUser<Guid>
|
|
382
|
+
{{
|
|
383
|
+
public string FirstName {{ get; set; }} = string.Empty;
|
|
384
|
+
public string LastName {{ get; set; }} = string.Empty;
|
|
385
|
+
public DateTime CreatedAt {{ get; set; }} = DateTime.UtcNow;
|
|
386
|
+
public DateTime UpdatedAt {{ get; set; }} = DateTime.UtcNow;
|
|
387
|
+
public ICollection<UserRole> UserRoles {{ get; set; }} = new List<UserRole>();
|
|
388
|
+
}}
|
|
389
|
+
}}
|
|
390
|
+
"""
|
|
391
|
+
(base / "Domain/Entities/Identity/User.cs").write_text(content)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def _gen_user_role(base: Path, project: str):
|
|
395
|
+
content = f"""using Microsoft.AspNetCore.Identity;
|
|
396
|
+
|
|
397
|
+
namespace {project}.Domain.Entities.Identity
|
|
398
|
+
{{
|
|
399
|
+
public class UserRole : IdentityUserRole<Guid>
|
|
400
|
+
{{
|
|
401
|
+
public virtual User User {{ get; set; }} = null!;
|
|
402
|
+
public virtual Role Role {{ get; set; }} = null!;
|
|
403
|
+
}}
|
|
404
|
+
}}
|
|
405
|
+
"""
|
|
406
|
+
(base / "Domain/Entities/Identity/UserRole.cs").write_text(content)
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def _gen_global_usings(base: Path, project: str):
|
|
410
|
+
content = f"""global using {project}.Domain.Common;
|
|
411
|
+
global using {project}.Domain.Entities;
|
|
412
|
+
"""
|
|
413
|
+
(base / "Domain/GlobalUsings.cs").write_text(content)
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
# ── Persistence files ──────────────────────────────────────────────────────────
|
|
417
|
+
|
|
418
|
+
def _gen_data_context(base: Path, project: str):
|
|
419
|
+
identity_db_context = "IdentityDbContext<"
|
|
420
|
+
content = f"""using {project}.Domain.Entities.Identity;
|
|
421
|
+
using Humanizer;
|
|
422
|
+
using Microsoft.AspNetCore.Identity;
|
|
423
|
+
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
|
424
|
+
using Microsoft.EntityFrameworkCore;
|
|
425
|
+
using System.Reflection;
|
|
426
|
+
|
|
427
|
+
namespace {project}.Persistence
|
|
428
|
+
{{
|
|
429
|
+
public class DataContext : {identity_db_context}
|
|
430
|
+
User,
|
|
431
|
+
Role,
|
|
432
|
+
Guid,
|
|
433
|
+
IdentityUserClaim<Guid>,
|
|
434
|
+
UserRole,
|
|
435
|
+
IdentityUserLogin<Guid>,
|
|
436
|
+
IdentityRoleClaim<Guid>,
|
|
437
|
+
IdentityUserToken<Guid>>
|
|
438
|
+
{{
|
|
439
|
+
public DataContext(DbContextOptions<DataContext> options) : base(options)
|
|
440
|
+
{{
|
|
441
|
+
}}
|
|
442
|
+
|
|
443
|
+
protected override void OnModelCreating(ModelBuilder builder)
|
|
444
|
+
{{
|
|
445
|
+
base.OnModelCreating(builder);
|
|
446
|
+
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
|
|
447
|
+
foreach (var entityType in builder.Model.GetEntityTypes())
|
|
448
|
+
{{
|
|
449
|
+
var table = entityType.GetTableName();
|
|
450
|
+
if (table!.StartsWith("AspNet"))
|
|
451
|
+
entityType.SetTableName(table.Substring(6).Underscore());
|
|
452
|
+
}}
|
|
453
|
+
}}
|
|
454
|
+
}}
|
|
455
|
+
}}
|
|
456
|
+
"""
|
|
457
|
+
(base / "Persistence/DataContext.cs").write_text(content)
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def _gen_role_seeder(base: Path, project: str):
|
|
461
|
+
content = f"""using {project}.Domain.Entities.Identity;
|
|
462
|
+
using Microsoft.AspNetCore.Identity;
|
|
463
|
+
|
|
464
|
+
namespace {project}.Persistence.Seeders
|
|
465
|
+
{{
|
|
466
|
+
public static class RoleSeeder
|
|
467
|
+
{{
|
|
468
|
+
public static async Task SeedAsync(RoleManager<Role> roleManager)
|
|
469
|
+
{{
|
|
470
|
+
string[] roles = {{ "SuperAdmin", "Admin", "User" }};
|
|
471
|
+
|
|
472
|
+
foreach (var role in roles)
|
|
473
|
+
{{
|
|
474
|
+
if (!await roleManager.RoleExistsAsync(role))
|
|
475
|
+
await roleManager.CreateAsync(new Role {{ Name = role }});
|
|
476
|
+
}}
|
|
477
|
+
}}
|
|
478
|
+
}}
|
|
479
|
+
}}
|
|
480
|
+
"""
|
|
481
|
+
(base / "Persistence/Seeders/RoleSeeder.cs").write_text(content)
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
def _gen_user_seeder(base: Path, project: str):
|
|
485
|
+
content = f"""using {project}.Domain.Entities.Identity;
|
|
486
|
+
using Microsoft.AspNetCore.Identity;
|
|
487
|
+
|
|
488
|
+
namespace {project}.Persistence.Seeders
|
|
489
|
+
{{
|
|
490
|
+
public static class UserSeeder
|
|
491
|
+
{{
|
|
492
|
+
public static async Task SeedAsync(UserManager<User> userManager)
|
|
493
|
+
{{
|
|
494
|
+
var superAdmin = await userManager.FindByEmailAsync("super_admin@{project.lower()}.com");
|
|
495
|
+
|
|
496
|
+
if (superAdmin == null)
|
|
497
|
+
{{
|
|
498
|
+
var user = new User
|
|
499
|
+
{{
|
|
500
|
+
UserName = "super_admin@{project.lower()}.com",
|
|
501
|
+
Email = "super_admin@{project.lower()}.com",
|
|
502
|
+
FirstName = "Super",
|
|
503
|
+
LastName = "Admin",
|
|
504
|
+
EmailConfirmed = true,
|
|
505
|
+
}};
|
|
506
|
+
|
|
507
|
+
await userManager.CreateAsync(user, "Pa$$w0rd");
|
|
508
|
+
await userManager.AddToRoleAsync(user, "SuperAdmin");
|
|
509
|
+
}}
|
|
510
|
+
}}
|
|
511
|
+
}}
|
|
512
|
+
}}
|
|
513
|
+
"""
|
|
514
|
+
(base / "Persistence/Seeders/UserSeeder.cs").write_text(content)
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
def _gen_user_role_configuration(base: Path, project: str):
|
|
518
|
+
content = f"""using {project}.Domain.Entities.Identity;
|
|
519
|
+
using Microsoft.EntityFrameworkCore;
|
|
520
|
+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
|
521
|
+
|
|
522
|
+
namespace {project}.Persistence.Configurations
|
|
523
|
+
{{
|
|
524
|
+
public class UserRoleConfiguration : IEntityTypeConfiguration<UserRole>
|
|
525
|
+
{{
|
|
526
|
+
public void Configure(EntityTypeBuilder<UserRole> builder)
|
|
527
|
+
{{
|
|
528
|
+
builder.HasKey(ur => new {{ ur.UserId, ur.RoleId }});
|
|
529
|
+
|
|
530
|
+
builder.HasOne(ur => ur.User)
|
|
531
|
+
.WithMany(u => u.UserRoles)
|
|
532
|
+
.HasForeignKey(ur => ur.UserId)
|
|
533
|
+
.IsRequired();
|
|
534
|
+
|
|
535
|
+
builder.HasOne(ur => ur.Role)
|
|
536
|
+
.WithMany(r => r.UserRoles)
|
|
537
|
+
.HasForeignKey(ur => ur.RoleId)
|
|
538
|
+
.IsRequired();
|
|
539
|
+
}}
|
|
540
|
+
}}
|
|
541
|
+
}}
|
|
542
|
+
"""
|
|
543
|
+
(base / "Persistence/Configurations/UserRoleConfiguration.cs").write_text(content)
|