From 77ded0bd234d0a1c10cbeb635dc2703f43c8dd28 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Tue, 3 Jan 2023 10:06:37 +0100 Subject: [PATCH 1/4] Remove old dotnet templates Remove old dotnet templates --- .../templates/crud_openapi_net/context.xml | 14 -- .../templates/crud_openapi_net/templates.xml | 49 ------- .../Devon4Net.Application.WebAPI/Startup.cs | 79 ---------- .../appsettings.Development.json | 117 --------------- ...bles.component#cap_first}Controller.cs.ftl | 137 ------------------ ...ables.component#cap_first}Converter.cs.ftl | 30 ---- ...me#replace('Dto', '')#cap_first}Dto.cs.ftl | 30 ---- ...ce('Dto', '')#cap_first}ResponseDto.cs.ftl | 30 ---- ...yName#cap_first}NotCreatedException.cs.ftl | 41 ------ ...yName#cap_first}NotDeletedException.cs.ftl | 41 ------ ...ityName#cap_first}NotFoundException.cs.ftl | 41 ------ ...riables.component#cap_first}Service.cs.ftl | 95 ------------ ...riables.component#cap_first}Service.cs.ftl | 43 ------ ...les.entityName#cap_first}Repository.cs.ftl | 77 ---------- .../Domain/Database/CobigenContext.cs | 39 ----- .../${variables.entityName#cap_first}.cs.ftl | 31 ---- ...les.entityName#cap_first}Repository.cs.ftl | 42 ------ 17 files changed, 936 deletions(-) delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/context.xml delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates.xml delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Startup.cs delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/appsettings.Development.json delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Controller/${variables.component#cap_first}Controller.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Converter/${variables.component#cap_first}Converter.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}Dto.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}ResponseDto.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotCreatedException.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotDeletedException.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotFoundException.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Service/${variables.component#cap_first}Service.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Service/I${variables.component#cap_first}Service.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Data/Repositories/${variables.entityName#cap_first}Repository.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/Database/CobigenContext.cs delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/Entities/${variables.entityName#cap_first}.cs.ftl delete mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/RepositoryInterfaces/I${variables.entityName#cap_first}Repository.cs.ftl diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/context.xml b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/context.xml deleted file mode 100644 index 3e37f15141..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/context.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates.xml b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates.xml deleted file mode 100644 index a40e0890c1..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Startup.cs b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Startup.cs deleted file mode 100644 index 0bbf7cd4bc..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Startup.cs +++ /dev/null @@ -1,79 +0,0 @@ -using Devon4Net.Application.WebAPI.Configuration; -using Devon4Net.Domain.UnitOfWork.Common; -using Devon4Net.Domain.UnitOfWork.Enums; -using Devon4Net.WebAPI.Implementation.Configure; -using Devon4Net.WebAPI.Implementation.Domain.Database; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -namespace Devon4Net.Application.WebAPI -{ - /// - /// devonfw startup - /// - public class Startup - { - private IConfiguration Configuration { get; } - - /// - /// Configuration variable with all settings file loaded - /// - /// - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - /// - /// This method gets called by the runtime. Use this method to add services to the container. - /// - /// - public void ConfigureServices(IServiceCollection services) - { - - services.ConfigureDevonFw(Configuration); - SetupDatabase(services); - services.SetupDevonDependencyInjection(); - services.AddMvc(option => option.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_3_0); - services.AddControllers(); - services.AddOptions(); - } - - private void SetupDatabase(IServiceCollection services) - { - services.SetupDatabase(Configuration, "Default", DatabaseType.InMemory); - services.SetupDatabase(Configuration, "Employee", DatabaseType.InMemory); - services.SetupDatabase(Configuration, "Cobigen", DatabaseType.InMemory); - } - - /// - /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - /// - /// app net param - /// environment param - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseHsts(); - } - - app.ConfigureDevonFw(); - app.UseMvc(); - app.UseHttpsRedirection(); - app.UseStaticFiles(); - app.UseRouting(); - app.UseAuthorization(); - app.UseAuthentication(); - app.UseEndpoints(endpoints => endpoints.MapControllers()); - } - } -} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/appsettings.Development.json b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/appsettings.Development.json deleted file mode 100644 index 75381f06f4..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/appsettings.Development.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "ConnectionStrings": { - "Default": "Todos", - "Employee": "Employee", - "Cobigen": "Cobigen" - }, - "Logging": { - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - }, - "Swagger": { - "Version": "v1", - "Title": "devon4net API", - "Description": "devon4net API Contract", - "Terms": "https://www.devonfw.com/terms-of-use/", - "Contact": { - "Name": "devonfw", - "Email": "icsddevonfwsupport.apps2@capgemini.com", - "Url": "https://www.devonfw.com" - }, - "License": { - "Name": "devonfw - Terms of Use", - "Url": "https://www.devonfw.com/terms-of-use/" - }, - "Endpoint": { - "Name": "V1 Docs", - "Url": "/swagger/v1/swagger.json", - "UrlUi": "swagger", - "RouteTemplate": "swagger/v1/{documentName}/swagger.json" - } - }, - "JWT": { - "Audience": "devon4Net", - "Issuer": "devon4Net", - "TokenExpirationTime": 60, - "ValidateIssuerSigningKey": true, - "ValidateLifetime": true, - "ClockSkew": 5, - "Security": { - "SecretKeyLengthAlgorithm": "A256KW", - "SecretKeyEncryptionAlgorithm": "A128CBC-HS256", - "SecretKey": "tMFjgSOahNU5Cm4WV7ncY6EeARwqpb1x", - "Certificate": "localhost.pfx", - "CertificatePassword": "localhost", - "CertificateEncryptionAlgorithm": "RS256" - } - }, - "Cors": [] - //[ - // { - // "CorsPolicy": "CorsPolicy1", - // "Origins": "http://example.com,http://www.contoso.com", - // "Headers": "accept,content-type,origin,x-custom-header", - // "Methods": "GET,POST,HEAD", - // "AllowCredentials": true - // }, - // { - // "CorsPolicy": "CorsPolicy2", - // "Origins": "http://example.com,http://www.contoso.com", - // "Headers": "accept,content-type,origin,x-custom-header", - // "Methods": "GET,POST,HEAD", - // "AllowCredentials": true - // } - //] - , - "CircuitBreaker": { - "CheckCertificate": true, - "Endpoints": [ - { - "Name": "SampleService", - "BaseAddress": "https://localhost:5001/", - "Headers": { - }, - "WaitAndRetrySeconds": [ - 0.0001, - 0.0005, - 0.001 - ], - "DurationOfBreak": 0.0005, - "UseCertificate": true, - "Certificate": "localhost.pfx", - "CertificatePassword": "localhost", - "SslProtocol": "3072" //TLS12 - } - ] - }, - "Headers": { - "AccessControlExposeHeader": "Authorization", - "StrictTransportSecurityHeader": "", - "XFrameOptionsHeader": "DENY", - "XssProtectionHeader": "1;mode=block", - "XContentTypeOptionsHeader": "nosniff", - "ContentSecurityPolicyHeader": "", - "PermittedCrossDomainPoliciesHeader": "", - "ReferrerPolicyHeader": "" - }, - "Log": { - "UseAOPTrace": false, - "LogLevel": "Debug", - "SqliteDatabase": "logs/log.db", - "LogFile": "logs/{0}_devonfw.log", - "SeqLogServerHost": "http://127.0.0.1:5341", - "GrayLog": { - "GrayLogHost": "127.0.0.1", - "GrayLogPort": "12201", - "GrayLogProtocol": "UDP", - "UseSecureConnection": true, - "UseAsyncLogging": true, - "RetryCount": 5, - "RetryIntervalMs": 15, - "MaxUdpMessageSize": 8192 - } - } -} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Controller/${variables.component#cap_first}Controller.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Controller/${variables.component#cap_first}Controller.cs.ftl deleted file mode 100644 index a2741d23c0..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Controller/${variables.component#cap_first}Controller.cs.ftl +++ /dev/null @@ -1,137 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using Devon4Net.Infrastructure.Log; -using Microsoft.AspNetCore.Mvc; -using Devon4Net.WebAPI.Implementation.Business.${variables.component?cap_first}Management.Service; -using Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Dto; - -namespace Devon4Net.WebAPI.Implementation.Business.${variables.component?cap_first}Management.Controller -{ - /// - /// ${variables.component?cap_first} controller - /// - [ApiController] - public class ${variables.component?cap_first}Controller : ControllerBase - { - private readonly I${variables.component?cap_first}Service _${variables.component?cap_first}Service; - - /// - /// Constructor - /// - /// - public ${variables.component?cap_first}Controller(I${variables.component?cap_first}Service ${variables.component}Service) - { - _${variables.component?cap_first}Service = ${variables.component}Service; - } - - /// - /// Get ${variables.entityName?cap_first} - /// - /// - /// Ok. - /// Bad request. Parser data error. - /// Forbidden. Authorization error. - /// Internal Server Error. The search process ended with error. - [HttpGet] - [Route("/${variables.entityName?lower_case}/{id}/")] - [ProducesResponseType(typeof(${variables.entityName?cap_first}Dto), 200)] - [ProducesResponseType(400)] - [ProducesResponseType(404)] - [ProducesResponseType(500)] - public async Task Get${variables.entityName?cap_first}(long id) - { - Devon4NetLogger.Debug("Executing Get${variables.entityName?cap_first} from controller ${variables.component?cap_first}Controller"); - return Ok(await _${variables.component?cap_first}Service.Get${variables.entityName?cap_first}ById(id).ConfigureAwait(false)); - } - - /// - /// Create ${variables.entityName?cap_first} - /// - /// - /// Ok. - /// Bad request. Parser data error. - /// Forbidden. Authorization error. - /// Internal Server Error. The search process ended with error. - [HttpPost] - [Route("/${variables.entityName?lower_case}/")] - [ProducesResponseType(typeof(${variables.entityName?cap_first}Dto), 200)] - [ProducesResponseType(400)] - [ProducesResponseType(404)] - [ProducesResponseType(500)] - public async Task Save${variables.entityName?cap_first}([FromBody]${variables.entityName?cap_first}Dto ${variables.entityName?uncap_first}Dto) - { - Devon4NetLogger.Debug("Executing Save${variables.entityName?cap_first} from controller ${variables.component?cap_first}Controller"); - return Ok(await _${variables.component?cap_first}Service.Create${variables.entityName?cap_first}(${variables.entityName?uncap_first}Dto).ConfigureAwait(false)); - } - - /// - /// Delete ${variables.entityName?cap_first} - /// - /// - /// Ok. - /// Bad request. Parser data error. - /// Forbidden. Authorization error. - /// Internal Server Error. The search process ended with error. - [HttpDelete] - [Route("/${variables.entityName?lower_case}/{id}/")] - [ProducesResponseType(typeof(long), 200)] - [ProducesResponseType(400)] - [ProducesResponseType(404)] - [ProducesResponseType(500)] - public async Task Delete${variables.entityName?cap_first}(long id) - { - Devon4NetLogger.Debug("Executing Get${variables.entityName?cap_first} from controller ${variables.component?cap_first}Controller"); - return Ok(await _${variables.component?cap_first}Service.Delete${variables.entityName?cap_first}ById(id).ConfigureAwait(false)); - } - - /// - /// Get all ${variables.entityName?cap_first} - /// - /// Ok. - /// Bad request. Parser data error. - /// Forbidden. Authorization error. - /// Internal Server Error. The search process ended with error. - [HttpGet] - [Route("/${variables.entityName?lower_case}/search/")] - [ProducesResponseType(typeof(List<${variables.entityName?cap_first}Dto>), 200)] - [ProducesResponseType(400)] - [ProducesResponseType(404)] - [ProducesResponseType(500)] - public async Task FindAll${variables.entityName?cap_first}s() - { - Devon4NetLogger.Debug("Executing FindAll${variables.entityName?cap_first} from controller ${variables.component?cap_first}Controller"); - return Ok(await _${variables.component?cap_first}Service.FindAll${variables.entityName?cap_first}s().ConfigureAwait(false)); - } - <#assign pathInUse = "/" + variables.entityName?lower_case + "/{id}/,/" + variables.entityName?lower_case + "/search/"> - <#list model.component.paths as path> - <#list path.operations as operation> - <#list operation.parameters as parameter> - <#if !DevonfwUtil.isCrudOperation(operation.operationId!null, variables.entityName?cap_first)> - <#if !pathInUse?contains(path.pathURI)> - - /// - /// - /// int<#elseif parameter.type == "number">long"> - /// Ok. - /// Bad request. Parser data error. - /// Forbidden. Authorization error. - /// Internal Server Error. The search process ended with error. - [Http${operation.type?cap_first}] - [Route("${path.pathURI}")] - [ProducesResponseType(200)] - [ProducesResponseType(400)] - [ProducesResponseType(404)] - [ProducesResponseType(500)] - public IActionResult ${OpenApiUtil.printServiceOperationName(operation, path.pathURI)?cap_first} (<#if parameter.isEntity>${parameter.type}Dto<#elseif parameter.type == "integer">int<#elseif parameter.type == "number">long ${parameter.name}<#if parameter.isEntity>Dto<#if parameter?has_next>, ) - { - Devon4NetLogger.Debug("Executing ${OpenApiUtil.printServiceOperationName(operation, path.pathURI)?cap_first} from controller ${variables.component?cap_first}Controller"); - throw new NotImplementedException(); - } - - - - - - } -} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Converter/${variables.component#cap_first}Converter.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Converter/${variables.component#cap_first}Converter.cs.ftl deleted file mode 100644 index 235760c964..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Converter/${variables.component#cap_first}Converter.cs.ftl +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using Devon4Net.WebAPI.Implementation.Domain.Entities; -using Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Dto; - -namespace Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Converter -{ - /// - /// ${variables.entityName?cap_first}Converter - /// - public static class ${variables.entityName?cap_first}Converter - { - /// - /// ModelToDto ${variables.entityName?cap_first} transformation - /// - /// - /// - public static ${variables.entityName?cap_first}ResponseDto ModelToDto(${variables.entityName?cap_first} item) - { - if(item == null) return new ${variables.entityName?cap_first}ResponseDto(); - - return new ${variables.entityName?cap_first}ResponseDto - { - ${variables.entityName}Id = item.${variables.entityName}Id, - <#list model.properties as property> - ${property.name?cap_first} = item.${property.name?cap_first}<#if property?is_last><#else>, - - }; - } - } -} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}Dto.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}Dto.cs.ftl deleted file mode 100644 index 2c81ffebed..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}Dto.cs.ftl +++ /dev/null @@ -1,30 +0,0 @@ -using System; - -namespace Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Dto -{ - /// - /// ${variables.entityName?cap_first}Dto definition - /// - public class ${variables.entityName?cap_first}Dto - { - <#list model.properties as property> - <#if property.isCollection> - /// - /// the ${property.name?cap_first} - /// - public <#if property.type == "number">long<#elseif property.type == "integer">int<#elseif property.isEntity>${property.type}Dto<#else>${property.type}[] <#if property.type?contains("Dto")>${property.name?cap_first}Dto<#else>${property.name?cap_first} { get; set; } - <#if property?has_next> - - - <#else> - /// - /// the ${property.name?cap_first} - /// - public <#if property.type == "number">long<#elseif property.type == "integer">int<#elseif property.isEntity>${property.type}Dto<#else>${property.type} <#if property.type?contains("Dto")>${property.name?cap_first}Dto<#else>${property.name?cap_first} { get; set; } - - <#if property?has_next> - - - - } -} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}ResponseDto.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}ResponseDto.cs.ftl deleted file mode 100644 index 14c884b4e9..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}ResponseDto.cs.ftl +++ /dev/null @@ -1,30 +0,0 @@ -using System; - -namespace Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Dto -{ - /// - /// ${variables.entityName?cap_first}ResponseDto definition - /// - public class ${variables.entityName?replace("Dto", "")?cap_first}ResponseDto - { - /// - /// the ${variables.entityName?cap_first}Id - /// - public long ${variables.entityName?cap_first}Id { get; set; } - <#list model.properties as property> - <#if property.isCollection> - - /// - /// the ${property.name?cap_first} - /// - public <#if property.type == "number">long<#elseif property.type == "integer">int<#elseif property.isEntity>${property.type}Dto<#else>${property.type}[] <#if property.type?contains("Dto")>${property.name?cap_first}Dto<#else>${property.name?cap_first} { get; set; } - <#else> - - /// - /// the ${property.name?cap_first} - /// - public <#if property.type == "number">long<#elseif property.type == "integer">int<#elseif property.isEntity>${property.type}Dto<#else>${property.type} <#if property.type?contains("Dto")>${property.name?cap_first}Dto<#else>${property.name?cap_first} { get; set; } - - - } -} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotCreatedException.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotCreatedException.cs.ftl deleted file mode 100644 index 900ae42072..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotCreatedException.cs.ftl +++ /dev/null @@ -1,41 +0,0 @@ -using Devon4Net.Infrastructure.Common.Exceptions; -using Microsoft.AspNetCore.Http; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Exceptions -{ - /// - /// Custom exception ${variables.entityName?cap_first}NotCreatedException - /// - [Serializable] - public class ${variables.entityName?cap_first}NotCreatedException : Exception, IWebApiException - { - /// - /// The forced http status code to be fired on the exception manager - /// - public int StatusCode => StatusCodes.Status400BadRequest; - - /// - /// Show the message on the response? - /// - public bool ShowMessage => true; - - /// - /// Initializes a new instance of the class. - /// - public ${variables.entityName?cap_first}NotCreatedException() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public ${variables.entityName?cap_first}NotCreatedException(string message) - : base(message) - { - } - } -} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotDeletedException.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotDeletedException.cs.ftl deleted file mode 100644 index 81ea7089a2..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotDeletedException.cs.ftl +++ /dev/null @@ -1,41 +0,0 @@ -using Devon4Net.Infrastructure.Common.Exceptions; -using Microsoft.AspNetCore.Http; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Exceptions -{ - /// - /// Custom exception ${variables.entityName?cap_first}NotDeletedException - /// - [Serializable] - public class ${variables.entityName?cap_first}NotDeletedException : Exception, IWebApiException - { - /// - /// The forced http status code to be fired on the exception manager - /// - public int StatusCode => StatusCodes.Status400BadRequest; - - /// - /// Show the message on the response? - /// - public bool ShowMessage => true; - - /// - /// Initializes a new instance of the class. - /// - public ${variables.entityName?cap_first}NotDeletedException() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public ${variables.entityName?cap_first}NotDeletedException(string message) - : base(message) - { - } - } -} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotFoundException.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotFoundException.cs.ftl deleted file mode 100644 index a7a8ddc5fc..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotFoundException.cs.ftl +++ /dev/null @@ -1,41 +0,0 @@ -using Devon4Net.Infrastructure.Common.Exceptions; -using Microsoft.AspNetCore.Http; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Exceptions -{ - /// - /// Custom exception ${variables.entityName?cap_first}NotFoundException - /// - [Serializable] - public class ${variables.entityName?cap_first}NotFoundException : Exception, IWebApiException - { - /// - /// The forced http status code to be fired on the exception manager - /// - public int StatusCode => StatusCodes.Status404NotFound; - - /// - /// Show the message on the response? - /// - public bool ShowMessage => true; - - /// - /// Initializes a new instance of the class. - /// - public ${variables.entityName?cap_first}NotFoundException() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public ${variables.entityName?cap_first}NotFoundException(string message) - : base(message) - { - } - } -} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Service/${variables.component#cap_first}Service.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Service/${variables.component#cap_first}Service.cs.ftl deleted file mode 100644 index 34f5d4f85e..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Service/${variables.component#cap_first}Service.cs.ftl +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; -using Devon4Net.Domain.UnitOfWork.Service; -using Devon4Net.Domain.UnitOfWork.UnitOfWork; -using Devon4Net.Infrastructure.Log; -using Devon4Net.WebAPI.Implementation.Domain.Entities; -using Devon4Net.WebAPI.Implementation.Domain.Database; -using Devon4Net.WebAPI.Implementation.Domain.RepositoryInterfaces; -using Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Exceptions; -using Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Dto; -using Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Converter; - -namespace Devon4Net.WebAPI.Implementation.Business.${variables.component?cap_first}Management.Service -{ - /// - /// ${variables.component?cap_first} service implementation - /// - public class ${variables.component?cap_first}Service : Service, I${variables.component?cap_first}Service - { - private readonly I${variables.entityName?cap_first}Repository _${variables.entityName?cap_first}Repository; - - /// - /// Constructor - /// - /// - public ${variables.component?cap_first}Service(IUnitOfWork uoW) : base(uoW) - { - _${variables.entityName?cap_first}Repository = uoW.Repository(); - } - - /// - /// Get${variables.entityName?cap_first}ById - /// - /// - /// ${variables.entityName?cap_first}ResponseDto - public async Task<${variables.entityName?cap_first}ResponseDto> Get${variables.entityName?cap_first}ById(long id) - { - Devon4NetLogger.Debug($"Get${variables.entityName?cap_first}ById method from service ${variables.entityName?cap_first}Service with value : {id}"); - var ${variables.entityName?uncap_first} = await _${variables.entityName}Repository.Get${variables.entityName?cap_first}ById(id).ConfigureAwait(false); - - if(${variables.entityName?uncap_first} == null) - { - throw new ${variables.entityName?cap_first}NotFoundException($"the ${variables.entityName?cap_first} with id:{id} does not exist"); - } - - return ${variables.entityName?cap_first}Converter.ModelToDto(${variables.entityName?uncap_first}); - } - - /// - /// Create${variables.entityName?cap_first} - /// - /// - /// ${variables.entityName?cap_first}ResponseDto - public async Task<${variables.entityName?cap_first}ResponseDto> Create${variables.entityName?cap_first}(${variables.entityName?cap_first}Dto ${variables.entityName?uncap_first}Dto) - { - Devon4NetLogger.Debug($"Set${variables.entityName?cap_first} method from service ${variables.entityName?cap_first}Service"); - var created${variables.entityName?cap_first} = await _${variables.entityName}Repository.Set${variables.entityName?cap_first}(<#list model.properties as property>${variables.entityName?uncap_first}Dto.${property.name?cap_first}<#if property?has_next>, ).ConfigureAwait(false); - - return ${variables.entityName?cap_first}Converter.ModelToDto(created${variables.entityName?cap_first}); - } - - /// - /// Delete${variables.entityName?cap_first}ById - /// - /// - /// deleted id - public async Task Delete${variables.entityName?cap_first}ById(long id) - { - Devon4NetLogger.Debug($"Delete${variables.entityName?cap_first}ById method from service ${variables.entityName?cap_first}Service with value : {id}"); - var ${variables.entityName?uncap_first} = await _${variables.entityName}Repository.Get${variables.entityName?cap_first}ById(id).ConfigureAwait(false); - - if (${variables.entityName?uncap_first} == null) - { - throw new ${variables.entityName?cap_first}NotFoundException($"The provided Id {id} does not exists"); - } - - return await _${variables.entityName}Repository.Delete${variables.entityName?cap_first}ById(id).ConfigureAwait(false); - } - - /// - /// FindAll${variables.entityName?cap_first}s - /// - /// - /// List of ${variables.entityName?cap_first}ResponseDto - public async Task> FindAll${variables.entityName?cap_first}s(Expression> predicate = null) - { - Devon4NetLogger.Debug("Get${variables.entityName?cap_first} method from service ${variables.entityName?cap_first}Service"); - var ${variables.entityName?uncap_first}s = await _${variables.entityName}Repository.Get${variables.entityName?cap_first}s().ConfigureAwait(false); - return ${variables.entityName?uncap_first}s.Select(${variables.entityName?cap_first}Converter.ModelToDto); - } - } -} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Service/I${variables.component#cap_first}Service.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Service/I${variables.component#cap_first}Service.cs.ftl deleted file mode 100644 index 634d814824..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Business/${variables.component#cap_first}Management/Service/I${variables.component#cap_first}Service.cs.ftl +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Threading.Tasks; -using Devon4Net.WebAPI.Implementation.Domain.Entities; -using Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Dto; - -namespace Devon4Net.WebAPI.Implementation.Business.${variables.component?cap_first}Management.Service -{ - /// - /// I${variables.component?cap_first}Service - /// - public interface I${variables.component?cap_first}Service - { - /// - /// Get${variables.entityName?cap_first}ById - /// - /// - /// ${variables.entityName?cap_first}ResponseDto - Task<${variables.entityName?cap_first}ResponseDto> Get${variables.entityName?cap_first}ById(long id); - - /// - /// Create${variables.entityName?cap_first} - /// - /// - /// ${variables.entityName?cap_first}ResponseDto - Task<${variables.entityName?cap_first}ResponseDto> Create${variables.entityName?cap_first}(${variables.entityName?cap_first}Dto ${variables.entityName?uncap_first}Dto); - - /// - /// Delete${variables.entityName?cap_first}ById - /// - /// - /// deleted id - Task Delete${variables.entityName?cap_first}ById(long id); - - /// - /// FindAll${variables.entityName?cap_first}s - /// - /// - /// List of ${variables.entityName?cap_first}ResponseDto - Task> FindAll${variables.entityName?cap_first}s(Expression> predicate = null); - } -} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Data/Repositories/${variables.entityName#cap_first}Repository.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Data/Repositories/${variables.entityName#cap_first}Repository.cs.ftl deleted file mode 100644 index f22caf68f8..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Data/Repositories/${variables.entityName#cap_first}Repository.cs.ftl +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Threading.Tasks; -using Devon4Net.Domain.UnitOfWork.Repository; -using Devon4Net.Infrastructure.Log; -using Devon4Net.WebAPI.Implementation.Domain.Database; -using Devon4Net.WebAPI.Implementation.Domain.Entities; -using Devon4Net.WebAPI.Implementation.Domain.RepositoryInterfaces; -using Devon4Net.WebAPI.Implementation.Business.${variables.entityName?cap_first}Management.Exceptions; - -namespace Devon4Net.WebAPI.Implementation.Data.Repositories -{ - /// - /// ${variables.entityName?cap_first} Repository - /// - public class ${variables.entityName?cap_first}Repository : Repository<${variables.entityName?cap_first}>, I${variables.entityName?cap_first}Repository - { - /// - /// ${variables.entityName?cap_first}Repository Constructor - /// - public ${variables.entityName?cap_first}Repository(CobigenContext context) : base(context) - { - } - - /// - /// Get all ${variables.entityName?cap_first} - /// - /// - /// "List of ${variables.entityName?cap_first}" - public async Task> Get${variables.entityName?cap_first}s(Expression> predicate = null) - { - Devon4NetLogger.Debug("Get${variables.entityName?cap_first} method from ${variables.entityName?cap_first}Repository ${variables.entityName?cap_first}Service"); - return await Get().ConfigureAwait(false); - } - - /// - /// Get${variables.entityName?cap_first}ById - /// - /// - /// "${variables.entityName?cap_first}" - public async Task<${variables.entityName?cap_first}> Get${variables.entityName?cap_first}ById(long id) - { - Devon4NetLogger.Information("Replace GetFirstOrDefault() to Get() with the needed expresion"); - return await GetFirstOrDefault(s=> s.${variables.entityName?cap_first}Id == id).ConfigureAwait(false); - } - - /// - /// Set${variables.entityName?cap_first} - /// - /// "${variables.entityName?cap_first}" - public async Task<${variables.entityName?cap_first}> Set${variables.entityName?cap_first}(<#list model.properties as property><#if property.isCollection><#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type}[] ${property.name?uncap_first}<#if property?has_next>, <#else><#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type} ${property.name?uncap_first}<#if property?has_next>, ) - { - Devon4NetLogger.Debug($"Set${variables.entityName?cap_first} method from repository ${variables.entityName?cap_first}Service"); - Devon4NetLogger.Information("Replace input parameter Create(new ${variables.entityName?cap_first}()) with the object that is needed to be created"); - return await Create(new ${variables.entityName?cap_first}{<#list model.properties as property>${property.name?cap_first} = ${property.name?uncap_first}<#if property?has_next>, }).ConfigureAwait(false); - } - - /// - /// Delete${variables.entityName?cap_first}ById - /// - /// - /// "deleted id" - public async Task Delete${variables.entityName?cap_first}ById(long id) - { - Devon4NetLogger.Information("Add Expresion to delete"); - var deleted = await Delete(s => s.${variables.entityName?cap_first}Id == id).ConfigureAwait(false); - - if (deleted) - { - return id; - } - - throw new ${variables.entityName?cap_first}NotDeletedException($"The ${variables.entityName?cap_first} entity {id} has not been deleted."); - } - } -} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/Database/CobigenContext.cs b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/Database/CobigenContext.cs deleted file mode 100644 index ee6924c048..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/Database/CobigenContext.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Devon4Net.WebAPI.Implementation.Domain.Entities; -using Microsoft.EntityFrameworkCore; - -namespace Devon4Net.WebAPI.Implementation.Domain.Database -{ - /// - /// Cobigen database context definition - /// - public class CobigenContext : DbContext - { - /// - /// Cobigen context definition - /// - /// - public CobigenContext(DbContextOptions options) - : base(options) - { - } - - /// - /// Any extra configuration should be here - /// - /// - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - } - - /// - /// Model rules definition - /// - /// - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - //TO-DO: Create here your model and entity requirements - //Please read the following documentation to get more information: - //https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext - } - } -} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/Entities/${variables.entityName#cap_first}.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/Entities/${variables.entityName#cap_first}.cs.ftl deleted file mode 100644 index 2e1f422fb0..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/Entities/${variables.entityName#cap_first}.cs.ftl +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Devon4Net.WebAPI.Implementation.Domain.Entities -{ - /// - /// Entity class for ${variables.entityName} - /// - public class ${variables.entityName} - { - /// - /// Id - /// - public long ${variables.entityName?cap_first}Id { get; set; } - <#list model.properties as property> - <#if property.isCollection> - - /// - /// ${property.name} - /// - public <#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type?replace("Dto", "")}[] ${property.name?cap_first} { get; set; } - <#else> - - /// - /// ${property.name} - /// - public <#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type?replace("Dto", "")} ${property.name?cap_first} { get; set; } - - - } -} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/RepositoryInterfaces/I${variables.entityName#cap_first}Repository.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/RepositoryInterfaces/I${variables.entityName#cap_first}Repository.cs.ftl deleted file mode 100644 index 2968e288fe..0000000000 --- a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.WebAPI.Implementation/Domain/RepositoryInterfaces/I${variables.entityName#cap_first}Repository.cs.ftl +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Threading.Tasks; -using Devon4Net.Domain.UnitOfWork.Repository; -using Devon4Net.WebAPI.Implementation.Domain.Entities; - -namespace Devon4Net.WebAPI.Implementation.Domain.RepositoryInterfaces -{ - /// - /// ${variables.entityName?cap_first}Repository interface - /// - public interface I${variables.entityName?cap_first}Repository : IRepository<${variables.entityName?cap_first}> - { - /// - /// Get${variables.entityName?cap_first} - /// - /// - /// "List of ${variables.entityName?cap_first}" - Task> Get${variables.entityName?cap_first}s(Expression> predicate = null); - - /// - /// Get${variables.entityName?cap_first}ById - /// - /// - /// "${variables.entityName?cap_first}" - Task<${variables.entityName?cap_first}> Get${variables.entityName?cap_first}ById(long id); - - /// - /// Set${variables.entityName?cap_first} - /// - /// "${variables.entityName?cap_first}" - Task<${variables.entityName?cap_first}> Set${variables.entityName?cap_first}(<#list model.properties as property><#if property.isCollection><#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type}[] ${property.name?uncap_first}<#if property?has_next>, <#else><#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type} ${property.name?uncap_first}<#if property?has_next>, ); - - /// - /// Delete${variables.entityName?cap_first}ById - /// - /// - /// "deleted id" - Task Delete${variables.entityName?cap_first}ById(long id); - } -} \ No newline at end of file From 64efa1a773747da504666e33678639713f3c00d3 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Tue, 3 Jan 2023 10:07:19 +0100 Subject: [PATCH 2/4] Update new dotnet templates Update new dotnet templates --- .../templates/crud_openapi_net/context.xml | 14 ++ .../templates/crud_openapi_net/templates.xml | 48 +++++ ...bles.component#cap_first}Controller.cs.ftl | 135 ++++++++++++ ...ables.component#cap_first}Converter.cs.ftl | 62 ++++++ ...me#replace('Dto', '')#cap_first}Dto.cs.ftl | 39 ++++ ...yName#cap_first}NotCreatedException.cs.ftl | 41 ++++ ...yName#cap_first}NotDeletedException.cs.ftl | 41 ++++ ...ityName#cap_first}NotFoundException.cs.ftl | 41 ++++ ...riables.component#cap_first}Service.cs.ftl | 96 +++++++++ ...riables.component#cap_first}Service.cs.ftl | 40 ++++ .../Configuration/DevonConfiguration.cs | 105 ++++++++++ ...les.entityName#cap_first}Repository.cs.ftl | 74 +++++++ .../Domain/Database/CobigenContext.cs | 39 ++++ .../${variables.entityName#cap_first}.cs.ftl | 31 +++ ...les.entityName#cap_first}Repository.cs.ftl | 39 ++++ .../appsettings.Development.json | 196 ++++++++++++++++++ 16 files changed, 1041 insertions(+) create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/context.xml create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates.xml create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Controller/${variables.component#cap_first}Controller.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Converter/${variables.component#cap_first}Converter.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}Dto.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotCreatedException.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotDeletedException.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotFoundException.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Service/${variables.component#cap_first}Service.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Service/I${variables.component#cap_first}Service.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Configuration/DevonConfiguration.cs create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Data/Repositories/${variables.entityName#cap_first}Repository.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/Database/CobigenContext.cs create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/Entities/${variables.entityName#cap_first}.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/RepositoryInterfaces/I${variables.entityName#cap_first}Repository.cs.ftl create mode 100644 cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/appsettings.Development.json diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/context.xml b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/context.xml new file mode 100644 index 0000000000..3e37f15141 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/context.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates.xml b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates.xml new file mode 100644 index 0000000000..fb0566ce7c --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Controller/${variables.component#cap_first}Controller.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Controller/${variables.component#cap_first}Controller.cs.ftl new file mode 100644 index 0000000000..9e360e6be6 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Controller/${variables.component#cap_first}Controller.cs.ftl @@ -0,0 +1,135 @@ +using Devon4Net.Application.WebAPI.Business.${variables.component?cap_first}Management.Service; +using Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Dto; +using Devon4Net.Infrastructure.Common; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.Mvc; + +namespace Devon4Net.Application.WebAPI.Business.${variables.component?cap_first}Management.Controller +{ + /// + /// ${variables.component?cap_first} controller + /// + [ApiController] + public class ${variables.component?cap_first}Controller : ControllerBase + { + private readonly I${variables.component?cap_first}Service _${variables.component?cap_first}Service; + + /// + /// Constructor + /// + /// + public ${variables.component?cap_first}Controller(I${variables.component?cap_first}Service ${variables.component}Service) + { + _${variables.component?cap_first}Service = ${variables.component}Service; + } + + /// + /// Get ${variables.entityName?cap_first} + /// + /// + /// Ok. + /// Bad request. Parser data error. + /// Forbidden. Authorization error. + /// Internal Server Error. The search process ended with error. + [HttpGet] + [Route("/${variables.entityName?lower_case}/{id}/")] + [ProducesResponseType(typeof(${variables.entityName?cap_first}Dto), 200)] + [ProducesResponseType(400)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task Get${variables.entityName?cap_first}(long id) + { + Devon4NetLogger.Debug("Executing Get${variables.entityName?cap_first} from controller ${variables.component?cap_first}Controller"); + return Ok(await _${variables.component?cap_first}Service.Get${variables.entityName?cap_first}ById(id).ConfigureAwait(false)); + } + + /// + /// Create ${variables.entityName?cap_first} + /// + /// + /// Ok. + /// Bad request. Parser data error. + /// Forbidden. Authorization error. + /// Internal Server Error. The search process ended with error. + [HttpPost] + [Route("/${variables.entityName?lower_case}/")] + [ProducesResponseType(typeof(${variables.entityName?cap_first}Dto), 200)] + [ProducesResponseType(400)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task Save${variables.entityName?cap_first}([FromBody]${variables.entityName?cap_first}Dto ${variables.entityName?uncap_first}Dto) + { + Devon4NetLogger.Debug("Executing Save${variables.entityName?cap_first} from controller ${variables.component?cap_first}Controller"); + return Ok(await _${variables.component?cap_first}Service.Create${variables.entityName?cap_first}(${variables.entityName?uncap_first}Dto).ConfigureAwait(false)); + } + + /// + /// Delete ${variables.entityName?cap_first} + /// + /// + /// Ok. + /// Bad request. Parser data error. + /// Forbidden. Authorization error. + /// Internal Server Error. The search process ended with error. + [HttpDelete] + [Route("/${variables.entityName?lower_case}/{id}/")] + [ProducesResponseType(typeof(long), 200)] + [ProducesResponseType(400)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task Delete${variables.entityName?cap_first}(long id) + { + Devon4NetLogger.Debug("Executing Get${variables.entityName?cap_first} from controller ${variables.component?cap_first}Controller"); + return Ok(await _${variables.component?cap_first}Service.Delete${variables.entityName?cap_first}ById(id).ConfigureAwait(false)); + } + + /// + /// Get all ${variables.entityName?cap_first} + /// + /// Ok. + /// Bad request. Parser data error. + /// Forbidden. Authorization error. + /// Internal Server Error. The search process ended with error. + [HttpGet] + [Route("/${variables.entityName?lower_case}/search/")] + [ProducesResponseType(typeof(List<${variables.entityName?cap_first}Dto>), 200)] + [ProducesResponseType(400)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task FindAll${variables.entityName?cap_first}s() + { + Devon4NetLogger.Debug("Executing FindAll${variables.entityName?cap_first} from controller ${variables.component?cap_first}Controller"); + return Ok(await _${variables.component?cap_first}Service.FindAll${variables.entityName?cap_first}s().ConfigureAwait(false)); + } + <#assign pathInUse = "/" + variables.entityName?lower_case + "/{id}/,/" + variables.entityName?lower_case + "/search/"> + <#list model.component.paths as path> + <#list path.operations as operation> + <#list operation.parameters as parameter> + <#if !DevonfwUtil.isCrudOperation(operation.operationId!null, variables.entityName?cap_first)> + <#if !pathInUse?contains(path.pathURI)> + + /// + /// + /// int<#elseif parameter.type == "number">long"> + /// Ok. + /// Bad request. Parser data error. + /// Forbidden. Authorization error. + /// Internal Server Error. The search process ended with error. + [Http${operation.type?cap_first}] + [Route("${path.pathURI}")] + [ProducesResponseType(200)] + [ProducesResponseType(400)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public IActionResult ${OpenApiUtil.printServiceOperationName(operation, path.pathURI)?cap_first} (<#if parameter.isEntity>${parameter.type}Dto<#elseif parameter.type == "integer">int<#elseif parameter.type == "number">long ${parameter.name}<#if parameter.isEntity>Dto<#if parameter?has_next>, ) + { + Devon4NetLogger.Debug("Executing ${OpenApiUtil.printServiceOperationName(operation, path.pathURI)?cap_first} from controller ${variables.component?cap_first}Controller"); + throw new NotImplementedException(); + } + + + + + + } +} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Converter/${variables.component#cap_first}Converter.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Converter/${variables.component#cap_first}Converter.cs.ftl new file mode 100644 index 0000000000..4c96615894 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Converter/${variables.component#cap_first}Converter.cs.ftl @@ -0,0 +1,62 @@ +using Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Dto; +using Devon4Net.Application.WebAPI.Domain.Entities; +<#list model.properties as property> +<#if property.type != "string" && property.type != "number" && property.type != "boolean"> +using Devon4Net.Application.WebAPI.Business.${property.name?cap_first}Management.Converter; + + + +namespace Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Converter +{ + /// + /// ${variables.entityName?cap_first}Converter + /// + public static class ${variables.entityName?cap_first}Converter + { + /// + /// EntityToDto ${variables.entityName?cap_first} transformation + /// + /// + /// + public static ${variables.entityName?cap_first}Dto EntityToDto(${variables.entityName?cap_first} item) + { + if(item == null) return new ${variables.entityName?cap_first}Dto(); + + return new ${variables.entityName?cap_first}Dto + { + ${variables.entityName}Id = item.${variables.entityName}Id, + <#list model.properties as property> + <#if property.type != "string" && property.type != "number" && property.type != "boolean"> + ${property.name?cap_first} = item.${property.name?cap_first}.Select(x => ${property.name?cap_first}Converter.EntityToDto(x)).ToArray()<#if property?is_last><#else>, + <#else> + ${property.name?cap_first} = item.${property.name?cap_first}<#if property?is_last><#else>, + + + }; + } + + /// + /// DtoToEntity ${variables.entityName?cap_first} transformation + /// + /// + /// + public static ${variables.entityName?cap_first} DtoToEntity(${variables.entityName?cap_first}Dto item) + { + if (item == null) return new ${variables.entityName?cap_first}(); + + return new ${variables.entityName?cap_first} + { + ${variables.entityName}Id = item.${variables.entityName}Id, + <#list model.properties as property> + <#if property.type != "string" && property.type != "number" && property.type != "boolean"> + ${property.name?cap_first} = item.${property.name?cap_first}.Select(x => ${property.name?cap_first}Converter.DtoToEntity(x)).ToArray()<#if property?is_last><#else>, + <#else> + ${property.name?cap_first} = item.${property.name?cap_first}<#if property?is_last><#else>, + + + }; + } + + + } +} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}Dto.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}Dto.cs.ftl new file mode 100644 index 0000000000..51221e5a19 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Dto/${variables.entityName#replace('Dto', '')#cap_first}Dto.cs.ftl @@ -0,0 +1,39 @@ +<#list model.properties as property> +<#if property.type != "string" && property.type != "number" && property.type != "boolean"> +using Devon4Net.Application.WebAPI.Business.${property.name?cap_first}Management.Dto; + + + +namespace Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Dto +{ + /// + /// ${variables.entityName?cap_first}Dto definition + /// + public class ${variables.entityName?cap_first}Dto + { + /// + /// the ${variables.entityName?cap_first}Id + /// + public long ${variables.entityName?cap_first}Id { get; set; } + + <#list model.properties as property> + <#if property.isCollection> + /// + /// the ${property.name?cap_first} + /// + public <#if property.type == "number">long<#elseif property.type == "integer">int<#elseif property.isEntity>${property.type}Dto<#else>${property.type}[] <#if property.type?contains("Dto")>${property.name?cap_first}Dto<#else>${property.name?cap_first} { get; set; } + <#if property?has_next> + + + <#else> + /// + /// the ${property.name?cap_first} + /// + public <#if property.type == "number">long<#elseif property.type == "integer">int<#elseif property.isEntity>${property.type}Dto<#else>${property.type} <#if property.type?contains("Dto")>${property.name?cap_first}Dto<#else>${property.name?cap_first} { get; set; } + + <#if property?has_next> + + + + } +} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotCreatedException.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotCreatedException.cs.ftl new file mode 100644 index 0000000000..beb942c173 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotCreatedException.cs.ftl @@ -0,0 +1,41 @@ +using Devon4Net.Infrastructure.Common.Exceptions; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Exceptions +{ + /// + /// Custom exception ${variables.entityName?cap_first}NotCreatedException + /// + [Serializable] + public class ${variables.entityName?cap_first}NotCreatedException : Exception, IWebApiException + { + /// + /// The forced http status code to be fired on the exception manager + /// + public int StatusCode => StatusCodes.Status400BadRequest; + + /// + /// Show the message on the response? + /// + public bool ShowMessage => true; + + /// + /// Initializes a new instance of the class. + /// + public ${variables.entityName?cap_first}NotCreatedException() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public ${variables.entityName?cap_first}NotCreatedException(string message) + : base(message) + { + } + } +} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotDeletedException.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotDeletedException.cs.ftl new file mode 100644 index 0000000000..8c0613555a --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotDeletedException.cs.ftl @@ -0,0 +1,41 @@ +using Devon4Net.Infrastructure.Common.Exceptions; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Exceptions +{ + /// + /// Custom exception ${variables.entityName?cap_first}NotDeletedException + /// + [Serializable] + public class ${variables.entityName?cap_first}NotDeletedException : Exception, IWebApiException + { + /// + /// The forced http status code to be fired on the exception manager + /// + public int StatusCode => StatusCodes.Status400BadRequest; + + /// + /// Show the message on the response? + /// + public bool ShowMessage => true; + + /// + /// Initializes a new instance of the class. + /// + public ${variables.entityName?cap_first}NotDeletedException() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public ${variables.entityName?cap_first}NotDeletedException(string message) + : base(message) + { + } + } +} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotFoundException.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotFoundException.cs.ftl new file mode 100644 index 0000000000..d9d27022eb --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Exceptions/${variables.entityName#cap_first}NotFoundException.cs.ftl @@ -0,0 +1,41 @@ +using Devon4Net.Infrastructure.Common.Exceptions; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Exceptions +{ + /// + /// Custom exception ${variables.entityName?cap_first}NotFoundException + /// + [Serializable] + public class ${variables.entityName?cap_first}NotFoundException : Exception, IWebApiException + { + /// + /// The forced http status code to be fired on the exception manager + /// + public int StatusCode => StatusCodes.Status404NotFound; + + /// + /// Show the message on the response? + /// + public bool ShowMessage => true; + + /// + /// Initializes a new instance of the class. + /// + public ${variables.entityName?cap_first}NotFoundException() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + public ${variables.entityName?cap_first}NotFoundException(string message) + : base(message) + { + } + } +} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Service/${variables.component#cap_first}Service.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Service/${variables.component#cap_first}Service.cs.ftl new file mode 100644 index 0000000000..8a5d9ec87e --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Service/${variables.component#cap_first}Service.cs.ftl @@ -0,0 +1,96 @@ +using Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Exceptions; +using Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Dto; +using Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Converter; +<#list model.properties as property> +<#if property.type != "string" && property.type != "number" && property.type != "boolean"> +using Devon4Net.Application.WebAPI.Business.${property.name?cap_first}Management.Converter; + + +using Devon4Net.Application.WebAPI.Domain.Database; +using Devon4Net.Application.WebAPI.Domain.Entities; +using Devon4Net.Application.WebAPI.Domain.RepositoryInterfaces; +using Devon4Net.Domain.UnitOfWork.Service; +using Devon4Net.Domain.UnitOfWork.UnitOfWork; +using Devon4Net.Infrastructure.Common; +using System.Linq.Expressions; + +namespace Devon4Net.Application.WebAPI.Business.${variables.component?cap_first}Management.Service +{ + /// + /// ${variables.component?cap_first} service implementation + /// + public class ${variables.component?cap_first}Service : Service, I${variables.component?cap_first}Service + { + private readonly I${variables.entityName?cap_first}Repository _${variables.entityName?cap_first}Repository; + + /// + /// Constructor + /// + /// + public ${variables.component?cap_first}Service(IUnitOfWork uoW) : base(uoW) + { + _${variables.entityName?cap_first}Repository = uoW.Repository(); + } + + /// + /// Get${variables.entityName?cap_first}ById + /// + /// + /// ${variables.entityName?cap_first}Dto + public async Task<${variables.entityName?cap_first}Dto> Get${variables.entityName?cap_first}ById(long id) + { + Devon4NetLogger.Debug($"Get${variables.entityName?cap_first}ById method from service ${variables.entityName?cap_first}Service with value : {id}"); + var ${variables.entityName?uncap_first} = await _${variables.entityName}Repository.Get${variables.entityName?cap_first}ById(id).ConfigureAwait(false); + + if(${variables.entityName?uncap_first} == null) + { + throw new ${variables.entityName?cap_first}NotFoundException($"the ${variables.entityName?cap_first} with id:{id} does not exist"); + } + + return ${variables.entityName?cap_first}Converter.EntityToDto(${variables.entityName?uncap_first}); + } + + /// + /// Create${variables.entityName?cap_first} + /// + /// + /// ${variables.entityName?cap_first}Dto + public async Task<${variables.entityName?cap_first}Dto> Create${variables.entityName?cap_first}(${variables.entityName?cap_first}Dto ${variables.entityName?uncap_first}Dto) + { + Devon4NetLogger.Debug("Set${variables.entityName?cap_first} method from service ${variables.entityName?cap_first}Service"); + var created${variables.entityName?cap_first} = await _${variables.entityName}Repository.Set${variables.entityName?cap_first}(<#list model.properties as property>${variables.entityName?uncap_first}Dto.${property.name?cap_first}<#if property.type != "string" && property.type != "number" && property.type != "boolean">.Select(x => ${property.name?cap_first}Converter.DtoToEntity(x)).ToArray()<#if property?is_last><#else>,).ConfigureAwait(false); + + return ${variables.entityName?cap_first}Converter.EntityToDto(created${variables.entityName?cap_first}); + } + + /// + /// Delete${variables.entityName?cap_first}ById + /// + /// + /// deleted id + public async Task Delete${variables.entityName?cap_first}ById(long id) + { + Devon4NetLogger.Debug($"Delete${variables.entityName?cap_first}ById method from service ${variables.entityName?cap_first}Service with value : {id}"); + var ${variables.entityName?uncap_first} = await _${variables.entityName}Repository.Get${variables.entityName?cap_first}ById(id).ConfigureAwait(false); + + if (${variables.entityName?uncap_first} == null) + { + throw new ${variables.entityName?cap_first}NotFoundException($"The provided Id {id} does not exists"); + } + + return await _${variables.entityName}Repository.Delete${variables.entityName?cap_first}ById(id).ConfigureAwait(false); + } + + /// + /// FindAll${variables.entityName?cap_first}s + /// + /// + /// List of ${variables.entityName?cap_first}Dto + public async Task> FindAll${variables.entityName?cap_first}s(Expression> predicate = null) + { + Devon4NetLogger.Debug("Get${variables.entityName?cap_first} method from service ${variables.entityName?cap_first}Service"); + var ${variables.entityName?uncap_first}s = await _${variables.entityName}Repository.Get${variables.entityName?cap_first}s().ConfigureAwait(false); + return ${variables.entityName?uncap_first}s.Select(${variables.entityName?cap_first}Converter.EntityToDto); + } + } +} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Service/I${variables.component#cap_first}Service.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Service/I${variables.component#cap_first}Service.cs.ftl new file mode 100644 index 0000000000..8030db4934 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Business/${variables.component#cap_first}Management/Service/I${variables.component#cap_first}Service.cs.ftl @@ -0,0 +1,40 @@ +using Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Dto; +using Devon4Net.Application.WebAPI.Domain.Entities; +using System.Linq.Expressions; + +namespace Devon4Net.Application.WebAPI.Business.${variables.component?cap_first}Management.Service +{ + /// + /// I${variables.component?cap_first}Service + /// + public interface I${variables.component?cap_first}Service + { + /// + /// Get${variables.entityName?cap_first}ById + /// + /// + /// ${variables.entityName?cap_first}Dto + Task<${variables.entityName?cap_first}Dto> Get${variables.entityName?cap_first}ById(long id); + + /// + /// Create${variables.entityName?cap_first} + /// + /// + /// ${variables.entityName?cap_first}Dto + Task<${variables.entityName?cap_first}Dto> Create${variables.entityName?cap_first}(${variables.entityName?cap_first}Dto ${variables.entityName?uncap_first}Dto); + + /// + /// Delete${variables.entityName?cap_first}ById + /// + /// + /// deleted id + Task Delete${variables.entityName?cap_first}ById(long id); + + /// + /// FindAll${variables.entityName?cap_first}s + /// + /// + /// List of ${variables.entityName?cap_first}Dto + Task> FindAll${variables.entityName?cap_first}s(Expression> predicate = null); + } +} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Configuration/DevonConfiguration.cs b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Configuration/DevonConfiguration.cs new file mode 100644 index 0000000000..14b53e9312 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Configuration/DevonConfiguration.cs @@ -0,0 +1,105 @@ +using Devon4Net.Application.WebAPI.Business.EmployeeManagement.Dto; +using Devon4Net.Application.WebAPI.Business.EmployeeManagement.Validators; +using Devon4Net.Application.WebAPI.Business.MediatRManagement.Commands; +using Devon4Net.Application.WebAPI.Business.MediatRManagement.Dto; +using Devon4Net.Application.WebAPI.Business.MediatRManagement.Handlers; +using Devon4Net.Application.WebAPI.Business.MediatRManagement.Queries; +using Devon4Net.Application.WebAPI.Business.RabbitMqManagement.Handlers; +using Devon4Net.Application.WebAPI.Business.TodoManagement.Dto; +using Devon4Net.Application.WebAPI.Business.TodoManagement.Validators; +using Devon4Net.Application.WebAPI.Domain.Database; +using Devon4Net.Domain.UnitOfWork.Common; +using Devon4Net.Domain.UnitOfWork.Enums; +using Devon4Net.Infrastructure.Common.Constants; +using Devon4Net.Infrastructure.FluentValidation; +using Devon4Net.Infrastructure.JWT.Common; +using Devon4Net.Infrastructure.MediatR.Options; +using Devon4Net.Infrastructure.MediatR.Samples.Handler; +using Devon4Net.Infrastructure.MediatR.Samples.Model; +using Devon4Net.Infrastructure.MediatR.Samples.Query; +using Devon4Net.Infrastructure.RabbitMQ; +using Devon4Net.Infrastructure.RabbitMQ.Options; +using Devon4Net.Infrastructure.RabbitMQ.Samples.Handllers; +using FluentValidation; +using MediatR; +using Microsoft.Extensions.Options; +using System.Security.Claims; + +namespace Devon4Net.Application.WebAPI.Configuration +{ + /// + /// DevonConfiguration class + /// + public static class DevonConfiguration + { + /// + /// Sets up the service dependency injection + /// For example: + /// services.AddTransient"ITodoService, TodoService"(); + /// services.AddTransient"ITodoRepository, TodoRepository"(); + /// Put your DI declarations here + /// + /// + /// + public static void SetupCustomDependencyInjection(this IServiceCollection services, IConfiguration configuration) + { + SetupDatabase(services, configuration); + SetupJwtPolicies(services); + SetupFluentValidators(services); + + using var serviceProvider = services.BuildServiceProvider(); + + var mediatR = serviceProvider.GetService>(); + var rabbitMq = serviceProvider.GetService>(); + + if (rabbitMq?.Value != null && rabbitMq.Value.EnableRabbitMq) + { + SetupRabbitHandlers(services); + } + + if (mediatR?.Value != null && mediatR.Value.EnableMediatR) + { + SetupMediatRHandlers(services); + } + } + + private static void SetupRabbitHandlers(IServiceCollection services) + { + services.AddRabbitMqHandler(true); + services.AddRabbitMqHandler(true); + } + + private static void SetupMediatRHandlers(IServiceCollection services) + { + services.AddTransient(typeof(IRequestHandler), typeof(GetUserhandler)); + services.AddTransient(typeof(IRequestHandler), typeof(GetTodoHandler)); + services.AddTransient(typeof(IRequestHandler), typeof(CreateTodoHandler)); + } + + private static void SetupFluentValidators(IServiceCollection services) + { + services.AddFluentValidation< IValidator, TodosFluentValidator>(); + services.AddFluentValidation, EmployeeFluentValidator>(); + } + + /// + /// Setup here your database connections. + /// To use RabbitMq message backup declare the 'RabbitMqBackupContext' database setup + /// PE: services.SetupDatabase<RabbitMqBackupContext>($"Data Source={FileOperations.GetFileFullPath("RabbitMqBackupSqLite.db")}", DatabaseType.Sqlite); + /// Please add the connection strings to enable the backup messaging for MediatR abd RabbitMq using MediatRBackupContext and RabbitMqBackupContext + /// + /// + /// + private static void SetupDatabase(IServiceCollection services, IConfiguration configuration) + { + services.SetupDatabase(configuration, "Default", DatabaseType.InMemory).ConfigureAwait(false); + services.SetupDatabase(configuration, "Employee", DatabaseType.InMemory).ConfigureAwait(false); + services.SetupDatabase(configuration, "Cobigen", DatabaseType.InMemory); + } + + private static void SetupJwtPolicies(IServiceCollection services) + { + services.AddJwtPolicy(AuthConst.DevonSamplePolicy, ClaimTypes.Role, AuthConst.DevonSampleUserRole); + } + } +} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Data/Repositories/${variables.entityName#cap_first}Repository.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Data/Repositories/${variables.entityName#cap_first}Repository.cs.ftl new file mode 100644 index 0000000000..d5194e31ce --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Data/Repositories/${variables.entityName#cap_first}Repository.cs.ftl @@ -0,0 +1,74 @@ +using Devon4Net.Application.WebAPI.Business.${variables.entityName?cap_first}Management.Exceptions; +using Devon4Net.Application.WebAPI.Domain.Database; +using Devon4Net.Application.WebAPI.Domain.Entities; +using Devon4Net.Application.WebAPI.Domain.RepositoryInterfaces; +using Devon4Net.Domain.UnitOfWork.Repository; +using Devon4Net.Infrastructure.Common; +using System.Linq.Expressions; + +namespace Devon4Net.Application.WebAPI.Data.Repositories +{ + /// + /// ${variables.entityName?cap_first} Repository + /// + public class ${variables.entityName?cap_first}Repository : Repository<${variables.entityName?cap_first}>, I${variables.entityName?cap_first}Repository + { + /// + /// ${variables.entityName?cap_first}Repository Constructor + /// + public ${variables.entityName?cap_first}Repository(CobigenContext context) : base(context) + { + } + + /// + /// Get all ${variables.entityName?cap_first} + /// + /// + /// "List of ${variables.entityName?cap_first}" + public async Task> Get${variables.entityName?cap_first}s(Expression> predicate = null) + { + Devon4NetLogger.Debug("Get${variables.entityName?cap_first} method from ${variables.entityName?cap_first}Repository ${variables.entityName?cap_first}Service"); + return await Get().ConfigureAwait(false); + } + + /// + /// Get${variables.entityName?cap_first}ById + /// + /// + /// "${variables.entityName?cap_first}" + public async Task<${variables.entityName?cap_first}> Get${variables.entityName?cap_first}ById(long id) + { + Devon4NetLogger.Information("Replace GetFirstOrDefault() to Get() with the needed expresion"); + return await GetFirstOrDefault(s=> s.${variables.entityName?cap_first}Id == id).ConfigureAwait(false); + } + + /// + /// Set${variables.entityName?cap_first} + /// + /// "${variables.entityName?cap_first}" + public async Task<${variables.entityName?cap_first}> Set${variables.entityName?cap_first}(<#list model.properties as property><#if property.isCollection><#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type}[] ${property.name?uncap_first}<#if property?has_next>, <#else><#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type} ${property.name?uncap_first}<#if property?has_next>, ) + { + Devon4NetLogger.Debug($"Set${variables.entityName?cap_first} method from repository ${variables.entityName?cap_first}Service"); + Devon4NetLogger.Information("Replace input parameter Create(new ${variables.entityName?cap_first}()) with the object that is needed to be created"); + return await Create(new ${variables.entityName?cap_first}{<#list model.properties as property>${property.name?cap_first} = ${property.name?uncap_first}<#if property?has_next>, }).ConfigureAwait(false); + } + + /// + /// Delete${variables.entityName?cap_first}ById + /// + /// + /// "deleted id" + public async Task Delete${variables.entityName?cap_first}ById(long id) + { + Devon4NetLogger.Information("Add Expresion to delete"); + var deleted = await Delete(s => s.${variables.entityName?cap_first}Id == id).ConfigureAwait(false); + + if (deleted) + { + return id; + } + + throw new ${variables.entityName?cap_first}NotDeletedException($"The ${variables.entityName?cap_first} entity {id} has not been deleted."); + } + } +} diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/Database/CobigenContext.cs b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/Database/CobigenContext.cs new file mode 100644 index 0000000000..2e905e8305 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/Database/CobigenContext.cs @@ -0,0 +1,39 @@ +using Devon4Net.Application.WebAPI.Domain.Entities; +using Microsoft.EntityFrameworkCore; + +namespace Devon4Net.Application.WebAPI.Domain.Database +{ + /// + /// Cobigen database context definition + /// + public class CobigenContext : DbContext + { + /// + /// Cobigen context definition + /// + /// + public CobigenContext(DbContextOptions options) + : base(options) + { + } + + /// + /// Any extra configuration should be here + /// + /// + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + } + + /// + /// Model rules definition + /// + /// + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + //TO-DO: Create here your model and entity requirements + //Please read the following documentation to get more information: + //https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext + } + } +} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/Entities/${variables.entityName#cap_first}.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/Entities/${variables.entityName#cap_first}.cs.ftl new file mode 100644 index 0000000000..1a09a48be4 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/Entities/${variables.entityName#cap_first}.cs.ftl @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; + +namespace Devon4Net.Application.WebAPI.Domain.Entities +{ + /// + /// Entity class for ${variables.entityName} + /// + public class ${variables.entityName} + { + /// + /// Id + /// + public long ${variables.entityName?cap_first}Id { get; set; } + <#list model.properties as property> + <#if property.isCollection> + + /// + /// ${property.name} + /// + public <#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type?replace("Dto", "")}[] ${property.name?cap_first} { get; set; } + <#else> + + /// + /// ${property.name} + /// + public <#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type?replace("Dto", "")} ${property.name?cap_first} { get; set; } + + + } +} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/RepositoryInterfaces/I${variables.entityName#cap_first}Repository.cs.ftl b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/RepositoryInterfaces/I${variables.entityName#cap_first}Repository.cs.ftl new file mode 100644 index 0000000000..dadd3efc52 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/Domain/RepositoryInterfaces/I${variables.entityName#cap_first}Repository.cs.ftl @@ -0,0 +1,39 @@ +using Devon4Net.Domain.UnitOfWork.Repository; +using Devon4Net.Application.WebAPI.Domain.Entities; +using System.Linq.Expressions; + +namespace Devon4Net.Application.WebAPI.Domain.RepositoryInterfaces +{ + /// + /// ${variables.entityName?cap_first}Repository interface + /// + public interface I${variables.entityName?cap_first}Repository : IRepository<${variables.entityName?cap_first}> + { + /// + /// Get${variables.entityName?cap_first} + /// + /// + /// "List of ${variables.entityName?cap_first}" + Task> Get${variables.entityName?cap_first}s(Expression> predicate = null); + + /// + /// Get${variables.entityName?cap_first}ById + /// + /// + /// "${variables.entityName?cap_first}" + Task<${variables.entityName?cap_first}> Get${variables.entityName?cap_first}ById(long id); + + /// + /// Set${variables.entityName?cap_first} + /// + /// "${variables.entityName?cap_first}" + Task<${variables.entityName?cap_first}> Set${variables.entityName?cap_first}(<#list model.properties as property><#if property.isCollection><#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type}[] ${property.name?uncap_first}<#if property?has_next>, <#else><#if property.type == "number">long<#elseif property.type == "integer">int<#else>${property.type} ${property.name?uncap_first}<#if property?has_next>, ); + + /// + /// Delete${variables.entityName?cap_first}ById + /// + /// + /// "deleted id" + Task Delete${variables.entityName?cap_first}ById(long id); + } +} \ No newline at end of file diff --git a/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/appsettings.Development.json b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/appsettings.Development.json new file mode 100644 index 0000000000..0615819b58 --- /dev/null +++ b/cobigen-templates/templates-devon4j/src/main/templates/crud_openapi_net/templates/Devon4Net.Application.WebAPI/appsettings.Development.json @@ -0,0 +1,196 @@ +{ + "devonfw": { + "UseDetailedErrorsKey": true, + "UseIIS": false, + "UseSwagger": true, + "UseXsrf": true, + "UseModelStateValidation": true, + "Environment": "Development", + "ForceUseHttpsRedirection": false, + "Kestrel": { + "UseHttps": false, + "HttpProtocol": "Http1AndHttp2", + "ApplicationPort": 8085, + "SslProtocol": "none", + "ExtraSettings": { + "KeepAliveTimeout": 120, + "MaxConcurrentConnections": 100, + "MaxConcurrentUpgradedConnections": 100, + "MaxRequestBodySize": 28.6, + "Http2MaxStreamsPerConnection": 100, + "Http2InitialConnectionWindowSize": 131072, + "Http2InitialStreamWindowSize": 98304, + "AllowSynchronousIO": true + } + } + }, + "ConnectionStrings": { + "Default": "Todos", + "Employee": "Employee", + "Cobigen": "Cobigen", + "RabbitMqBackup": "", + "MediatRBackup": "" + }, + "JWT": { + "Audience": "devon4Net", + "Issuer": "devon4Net", + "TokenExpirationTime": 60, + "ValidateIssuer": true, + "ValidateIssuerSigningKey": true, + "ValidateLifetime": true, + "RequireSignedTokens": true, + "RequireExpirationTime": true, + "RequireAudience": true, + "ClockSkew": 5, + "Security": { + "SecretKeyEncryptionAlgorithm": "", + "SecretKey": "", + "Certificate": "", + "CertificatePassword": "", + "CertificateEncryptionAlgorithm": "", + "RefreshTokenEncryptionAlgorithm": "" + } + }, + "Certificates": { + "ServerCertificate": { + "Certificate": "", + "CertificatePassword": "" + }, + "ClientCertificate": { + "DisableClientCertificateCheck": true, + "RequireClientCertificate": false, + "CheckCertificateRevocation": true, + "ClientCertificates": { + "Whitelist": [] + } + } + }, + "ExtraSettingsFiles": [], + + "KillSwitch": { + "UseKillSwitch": false, + "EnableRequests": false, + "HttpStatusCode": 403 + }, + "Logging": { + "UseLogFile": true, + "UseSQLiteDb": true, + "UseGraylog": false, + "UseAOPTrace": false, + "LogLevel": { + "Default": "Debug", + "Microsoft.AspNetCore": "Debug" + }, + "SqliteDatabase": "", + "LogFile": "", + "SeqLogServerHost": "", + "GrayLog": { + "GrayLogHost": "", + "GrayLogPort": "12201", + "GrayLogProtocol": "UDP", + "MaxUdpMessageSize": 8192 + } + }, + "Cors": [], + "Swagger": { + "Version": "v1", + "Title": "devon4net API", + "Description": "devon4net API Contract", + "Terms": "https://www.devonfw.com/terms-of-use/", + "Contact": { + "Name": "devonfw", + "Email": "sample@mail.com", + "Url": "https://www.devonfw.com" + }, + "License": { + "Name": "devonfw - Terms of Use", + "Url": "https://www.devonfw.com/terms-of-use/" + }, + "Endpoint": { + "Name": "V1 Docs", + "Url": "/swagger/v1/swagger.json", + "UrlUi": "swagger", + "RouteTemplate": "swagger/v1/{documentName}/swagger.json" + } + }, + "CircuitBreaker": { + "CheckCertificate": false, + "Endpoints": [ + { + "Name": "DestinationA", + "BaseAddress": "PUT THE IP ADDRESS HERE", + "Headers": { + }, + "WaitAndRetrySeconds": [ + 0.0001, + 0.0005, + 0.001 + ], + "DurationOfBreak": 0.0005, + "UseCertificate": false, + "Certificate": "", + "CertificatePassword": "", + "SslProtocol": "Tls13", + "CompressionSupport": true, + "AllowAutoRedirect": true + }, + { + "Name": "DestinationB", + "BaseAddress": "PUT THE IP ADDRESS HERE", + "Headers": { + }, + "WaitAndRetrySeconds": [ + 0.0001, + 0.0005, + 0.001 + ], + "DurationOfBreak": 0.0005, + "UseCertificate": false, + "Certificate": "", + "CertificatePassword": "", + "SslProtocol": "Tls13", + "CompressionSupport": true, + "AllowAutoRedirect": true + } + ] + }, + "LiteDb": { + "EnableLiteDb": true, + "DatabaseLocation": "devon4net.db" + }, + "MediatR": { + "EnableMediatR": true, + "Backup": { + "UseLocalBackup": true, + "DatabaseName": "devon4netMessageBackup.db" + } + }, + "RabbitMq": { + "EnableRabbitMq": true, + "Hosts": [ + { + "Host": "", + "Port": 5672, + "Ssl": false, + "SslServerName": "", + "SslCertPath": "", + "SslCertPassPhrase": "", + "SslPolicyErrors": "RemoteCertificateNotAvailable" + } + ], + "VirtualHost": "/", + "UserName": "", + "Password": "", + "Product": "", + "RequestedHeartbeat": 10, + "PrefetchCount": 50, + "PublisherConfirms": false, + "PersistentMessages": true, + "Platform": "localhost", + "Timeout": 10, + "Backup": { + "UseLocalBackup": false, + "DatabaseName": "devon4netMessageBackup.db" + } + } +} From bbf2d8bc73f1da07300303ca7124b5cf81c703b7 Mon Sep 17 00:00:00 2001 From: JosepFe Date: Tue, 3 Jan 2023 10:13:10 +0100 Subject: [PATCH 3/4] Update dotnet templates images Update dotnet templates images --- .../devon4net/CobigenContextLocation.png | Bin 12401 -> 23940 bytes .../devon4net/OpenAPI_file_root_folder.png | Bin 26673 -> 4724 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/documentation/images/howtos/devon4net/CobigenContextLocation.png b/documentation/images/howtos/devon4net/CobigenContextLocation.png index 9744124a3fae96ff1601e31410de75769518adb3..06e8136b4d3b74e62abf50eaeac69ed0cdc9c1e6 100644 GIT binary patch literal 23940 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 literal 12401 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 literal 26673 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 z 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 Date: Tue, 3 Jan 2023 10:14:31 +0100 Subject: [PATCH 4/4] Update dotnet template howto Update dotnet template howto --- documentation/howto_devon4net.asciidoc | 237 +++++++++++++++---------- 1 file changed, 140 insertions(+), 97 deletions(-) diff --git a/documentation/howto_devon4net.asciidoc b/documentation/howto_devon4net.asciidoc index 396f06bb48..53b2911059 100644 --- a/documentation/howto_devon4net.asciidoc +++ b/documentation/howto_devon4net.asciidoc @@ -1,97 +1,140 @@ -:toc: macro -toc::[] -:icons: font -:iconfont-remote!: -:iconfont-name: font-awesome -:stylesdir: css - -== [navy]#devon4net CobiGen Guide# - -=== [navy]#Overview# - -In this guide we will explain how to generate a new `WebAPI` project from an OpenAPI 3.0.0 specification. This means that we are going to use a “contract first” strategy. This is going to be possible due to these type of files that contain all the information about entities, operations, etc… - -In order to make it work we are using https://github.com/devonfw/cobigen[CobiGen], a powerful tool for generating source code. CobiGen allows users to generate all the structure and code of the components, helping to save a lot of time otherwise wasted on repetitive tasks. - -=== [navy]#Getting things ready# - -==== [navy]#devonfw-IDE# - -First, we will install the devonfw-IDE. It is a tool that will setup your IDE within minutes. Please follow the install guide https://github.com/devonfw/ide/blob/master/documentation/setup.asciidoc[here]. - -==== [navy]#devon4net Templates# - -We are going to use the template of devon4net as a base to generate all the code, so what we have to do now is to download said template using the following steps. - -First of all you have to set up all the environment for .NET, you can do this using https://devon4net.github.io/environment.html[the following tutorial]. Next we are going to create a new folder where we want to have the `WebAPI` project, lastly we are going to open the terminal there. - -Type the following: - - `dotnet new -i Devon4Net.WebAPI.Template` - -and then: - - `dotnet new Devon4NetAPI` - -==== [navy]#OpenAPI File# - -In order to let CobiGen generate all the files, we first have to make some modifications to our OpenAPI file. - -It is obligatory to put the _“x-rootpackage”_ tag to indicate where CobiGen will place the generated files as well as the _"x-component"_ tags for each component, keep in mind that due to CobiGen's limitations each component *_must_* have its own entity. - -You can read more information about how to configure your OpenAPI file and a working example https://github.com/devonfw/cobigen/wiki/cobigen-openapiplugin#full-example[here]. - -=== [navy]#Generating files# - -CobiGen allow us to generate the files in two different ways. One of them is using Eclipse which it can be done by using the its graphical interface. The other way to generate the code is using the CobiGen CLI tool. - -==== [navy]#Generating files through Eclipse# -In order to generate the files using Eclipse we need to follow some simple steps. - -First we are going to import our basic devon4net `WebAPI` Project into Eclipse. to do so open Eclipse with the “eclipse-main.bat” file that can be found in the devon distribution root folder. Once we are inside of Eclipse we go to *File > Open projects from file system...* and, under "Directory", search for your project. - -image::images/howtos/devon4net/Project_selection.png["CobiGen", width=="600", link=="images/howtos/devon4net/Project_selection.png"] - -Next we copy our OpenAPI file into the root folder of the project. - -image::images/howtos/devon4net/OpenAPI_file_root_folder.png["CobiGen", width=="300", link=="images/howtos/devon4net/OpenAPI_file_root_folder.png"] - -And then we right click on OpenAPI file and then select *CobiGen > Generate...* It will display a window like this: - -image::images/howtos/devon4net/cobigen_generate0.png["CobiGen", width=="800", link=="images/howtos/devon4net/cobigen_generate0.png"] - -To select all .NET features choose *CRUD devon4net Server* otherwise you can select only those that interest you. - -image::images/howtos/devon4net/cobigen_generate1.png["CobiGen", width=="800", link=="images/howtos/devon4net/cobigen_generate1.png] - -Ones you select all the files that you want to generate, click on the _“Finish”_ button to generate all the source code. - -==== [navy]#Generating files through CobiGen CLI# - -In order to generate the files using the CobiGen CLI it is needed to do the following steps: - -1. Go to devonfw distribution folder -2. Run *console.bat*, this will open a console. -3. Go to the folder you downloaded the *devon4net template* and your *yml* file. -4. Run the command: - - `cobigen generate {yourOpenAPIFile}.yml` - -5. A list of increments will be printed so that you can start the generation. It has to be selected *CRUD devon4net Server* increment. - -=== [navy]#Configuration# - -==== [navy]#Data base# - - -CobiGen is generating an empty context that has to be filled with manually in order to be able to work with the database. The context can be found in `*[Project_Name]/Devon4Net.WebAPI.Implementation/Domain/Database/CobigenContext.cs*`. - -image::images/howtos/devon4net/CobigenContextLocation.png["CobiGen", width=="350", link=="images/howtos/devon4net/CobigenContextLocation.png] - -==== [navy]#Run the application# - -After the configuration of the database, open a terminal in path: `*[Project_Name]/Devon4Net.Application.WebAPI*` and then type: - - `dotnet run` - -This will deploy our application in our localhost with the port 8082, so when you click https://localhost:8082/swagger/index.html[here] (https://localhost:8082/swagger) you can see, in swagger, all the services and the data model. +:toc: macro +toc::[] +:icons: font +:iconfont-remote!: +:iconfont-name: font-awesome +:stylesdir: css + +== [navy]#devon4net CobiGen Guide# + +=== [navy]#Overview# + +In this guide we will explain how to generate a new `WebAPI` project from an OpenAPI 3.0.0 specification. This means that we are going to use a “contract first” strategy. This is going to be possible due to these type of files that contain all the information about entities, operations, etc. + +In order to make it work we are using https://github.com/devonfw/cobigen[CobiGen], a powerful tool for generating source code. CobiGen allows users to generate all the structure and code of the components, helping to save a lot of time otherwise wasted on repetitive tasks. + +=== [navy]#Getting things ready# + +==== [navy]#devonfw-IDE# + +First, we will install the devonfw-IDE. It is a tool that will setup your IDE within minutes. Please follow the install guide https://github.com/devonfw/ide/blob/master/documentation/setup.asciidoc[here]. + +==== [navy]#devon4net Templates# + +We are going to use the template of devon4net as a base to generate all the code, so what we have to do now is to download said template using the following steps. + +First of all you have to set up all the environment for .NET, you can do this using https://devon4net.github.io/environment.html[the following tutorial]. Next we are going to create a new folder where we want to have the `WebAPI` project, lastly we are going to open the terminal there. + +Type the following: + + dotnet new -i Devon4Net.WebAPI.Template + +and then: + + dotnet new Devon4NetAPI + +==== [navy]#OpenAPI File# + +In order to let CobiGen generate all the files, we first have to make some modifications to our OpenAPI file. + +It is obligatory to put the _“x-rootpackage”_ tag to indicate where CobiGen will place the generated files as well as the _"x-component"_ tags for each component, keep in mind that due to CobiGen's limitations each component *_must_* have its own entity. + +You can read more information about how to configure your OpenAPI file and a working example https://github.com/devonfw/cobigen/wiki/cobigen-openapiplugin#full-example[here]. + +==== [navy]#Restrictions in the OpenApi file# + +In the **components/schema** section, whenever reference is made to another entity, it must be written in the singular. + +Below are two examples, one valid and one invalid, of how collections of other entities should be referenced.For this example, look at the _Sale_ property in the _Shop_ component. + +**Valid Example** + + components: + schemas: + Shop: + x-component: shopmanagement + description: Entity definition of Shop + type: object + properties: + shopExample: + type: string + maxLength: 100 + minLength: 5 + uniqueItems: true + sale: + type: array # Many to One relationship + items: + $ref: '#/components/schemas/Sale' + +**Invalid example** + + components: + schemas: + Shop: + x-component: shopmanagement + description: Entity definition of Shop + type: object + properties: + shopExample: + type: string + maxLength: 100 + minLength: 5 + uniqueItems: true + sales: + type: array # Many to One relationship + items: + $ref: '#/components/schemas/Sale' + +=== [navy]#Generating files# + +CobiGen allow us to generate the files in two different ways. One of them is using Eclipse which it can be done by using the its graphical interface. The other way to generate the code is using the CobiGen CLI tool. + +==== [navy]#Generating files through Eclipse# +In order to generate the files using Eclipse we need to follow some simple steps. + +First we are going to import our basic devon4net `WebAPI` Project into Eclipse. to do so open Eclipse with the “eclipse-main.bat” file that can be found in the devon distribution root folder. Once we are inside of Eclipse we go to *File > Open projects from file system...* and, under "Directory", search for your project. + +image::images/howtos/devon4net/Project_selection.png["CobiGen", width=="600", link=="images/howtos/devon4net/Project_selection.png"] + +Next we copy our OpenAPI file into the root folder of the project. + +image::images/howtos/devon4net/OpenAPI_file_root_folder.png["CobiGen", width=="300", link=="images/howtos/devon4net/OpenAPI_file_root_folder.png"] + +And then we right click on OpenAPI file and then select *CobiGen > Generate...* It will display a window like this: + +image::images/howtos/devon4net/cobigen_generate0.png["CobiGen", width=="800", link=="images/howtos/devon4net/cobigen_generate0.png"] + +To select all .NET features choose *CRUD devon4net Server* otherwise you can select only those that interest you. + +image::images/howtos/devon4net/cobigen_generate1.png["CobiGen", width=="800", link=="images/howtos/devon4net/cobigen_generate1.png] + +Ones you select all the files that you want to generate, click on the _“Finish”_ button to generate all the source code. + +==== [navy]#Generating files through CobiGen CLI# + +In order to generate the files using the CobiGen CLI it is needed to do the following steps: + +1. Go to devonfw distribution folder +2. Run *console.bat*, this will open a console. +3. Go to the folder you downloaded the *devon4net template* and your *yml* file. +4. Run the command: + + cobigen generate {yourOpenAPIFile}.yml + +5. A list of increments will be printed so that you can start the generation. It has to be selected *CRUD devon4net Server* increment. + +=== [navy]#Configuration# + +==== [navy]#Data base# + +CobiGen is generating an empty context that has to be filled with manually in order to be able to work with the database. The context can be found in `*[Project_Name]/Devon4Net.Application.WebAPI/Domain/Database/CobigenContext.cs*`. + +image::images/howtos/devon4net/CobigenContextLocation.png["CobiGen", width=="350", link=="images/howtos/devon4net/CobigenContextLocation.png] + +==== [navy]#Run the application# + +After the configuration of the database, open a terminal in path: `*[Project_Name]/Devon4Net.Application.WebAPI*` and then type: + + dotnet run + +This will deploy our application in our localhost with the port 8085, so when you click https://localhost:8085/swagger/index.html[here] (https://localhost:8085/swagger) you can see, in swagger, all the services and the data model. \ No newline at end of file