diff --git a/console/YANLib.Benchmarks/YANLib.Benchmarks.csproj b/console/YANLib.Benchmarks/YANLib.Benchmarks.csproj index 09466ba2..c346cb20 100644 --- a/console/YANLib.Benchmarks/YANLib.Benchmarks.csproj +++ b/console/YANLib.Benchmarks/YANLib.Benchmarks.csproj @@ -1,19 +1,19 @@ - - Exe - net6.0 - enable - enable - + + Exe + net6.0 + enable + enable + - - - - + + + + - - - + + + diff --git a/docker-compose.dcproj b/docker-compose.dcproj index 968c7b3d..f8b0df74 100644 --- a/docker-compose.dcproj +++ b/docker-compose.dcproj @@ -18,6 +18,9 @@ + + + diff --git a/docker-compose.yml b/docker-compose.yml index c020658f..aab161aa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -107,7 +107,7 @@ services: depends_on: - elasticsearch restart: unless-stopped - + rabbitmq: image: rabbitmq:3-management container_name: rabbitmq @@ -119,8 +119,6 @@ services: RABBITMQ_DEFAULT_PASS: ${RABBITMQ_DEFAULT_PASS:-} networks: - yan - depends_on: - - logstash restart: unless-stopped zookeeper: @@ -132,8 +130,6 @@ services: - ALLOW_ANONYMOUS_LOGIN=yes networks: - yan - depends_on: - - logstash restart: unless-stopped kafka: @@ -183,6 +179,7 @@ networks: volumes: setup: elasticsearch: + es-ingest: # Run with # docker-compose \ diff --git a/es-ingest/.dockerignore b/es-ingest/.dockerignore new file mode 100644 index 00000000..37eef9d5 --- /dev/null +++ b/es-ingest/.dockerignore @@ -0,0 +1,6 @@ +# Ignore Docker build files +Dockerfile +.dockerignore + +# Ignore OS artifacts +**/.DS_Store diff --git a/es-ingest/Dockerfile b/es-ingest/Dockerfile new file mode 100644 index 00000000..22528c6d --- /dev/null +++ b/es-ingest/Dockerfile @@ -0,0 +1,7 @@ +ARG ELASTIC_VERSION + +# https://www.docker.elastic.co/ +FROM docker.elastic.co/elasticsearch/elasticsearch:${ELASTIC_VERSION} + +# Add your elasticsearch plugins setup here +# Example: RUN elasticsearch-plugin install analysis-icu diff --git a/es-ingest/config/elasticsearch.yml b/es-ingest/config/elasticsearch.yml new file mode 100644 index 00000000..edebb87d --- /dev/null +++ b/es-ingest/config/elasticsearch.yml @@ -0,0 +1,18 @@ +--- +## Default Elasticsearch configuration from Elasticsearch base image. +## https://github.com/elastic/elasticsearch/blob/main/distribution/docker/src/docker/config/elasticsearch.yml +# +cluster.name: docker-cluster-neo +network.host: 0.0.0.0 + +## X-Pack settings +## see https://www.elastic.co/guide/en/elasticsearch/reference/current/security-settings.html +# +xpack.license.self_generated.type: trial +xpack.security.enabled: true + +# server.publicBaseUrl: https://my-elasticsearch-cluster.example.com + +## Set the built-in users' passwords. +# Run the following command from the Elasticsearch directory: +# ./bin/elasticsearch-setup-passwords interactive diff --git a/extensions/curator/curator-compose.yml b/extensions/curator/curator-compose.yml index fc137e62..65ae2bab 100644 --- a/extensions/curator/curator-compose.yml +++ b/extensions/curator/curator-compose.yml @@ -4,10 +4,11 @@ services: curator: build: context: extensions/curator/ + container_name: curator init: true volumes: - - ./config/curator.yml:/.curator/curator.yml:ro,Z - - ./config/delete_log_files_curator.yml:/.curator/delete_log_files_curator.yml:ro,Z + - ./extensions/curator/config/curator.yml:/.curator/curator.yml:ro,Z + - ./extensions/curator/config/delete_log_files_curator.yml:/.curator/delete_log_files_curator.yml:ro,Z environment: ELASTIC_PASSWORD: ${ELASTIC_PASSWORD:-} networks: diff --git a/extensions/enterprise-search/config/enterprise-search.yml b/extensions/enterprise-search/config/enterprise-search.yml index a1f098dd..a1beab23 100644 --- a/extensions/enterprise-search/config/enterprise-search.yml +++ b/extensions/enterprise-search/config/enterprise-search.yml @@ -6,7 +6,7 @@ ## --------------------- REQUIRED --------------------- # Encryption keys to protect application secrets. -secret_management.encryption_keys: +secret_management.encryption_keys: [680f94e568c90364bedf927b2f0f49609702d3eab9098688585a375b14274546] # example: #- 680f94e568c90364bedf927b2f0f49609702d3eab9098688585a375b14274546 diff --git a/extensions/enterprise-search/enterprise-search-compose.yml b/extensions/enterprise-search/enterprise-search-compose.yml index c4d422d0..3b11d2e5 100644 --- a/extensions/enterprise-search/enterprise-search-compose.yml +++ b/extensions/enterprise-search/enterprise-search-compose.yml @@ -6,8 +6,9 @@ services: context: extensions/enterprise-search/ args: ELASTIC_VERSION: ${ELASTIC_VERSION} + container_name: enterprise-search volumes: - - ./config/enterprise-search.yml:/usr/share/enterprise-search/config/enterprise-search.yml:ro,Z + - ./extensions/enterprise-search/config/enterprise-search.yml:/usr/share/enterprise-search/config/enterprise-search.yml:ro,Z environment: JAVA_OPTS: -Xms2g -Xmx2g ENT_SEARCH_DEFAULT_PASSWORD: 'changeme' diff --git a/extensions/filebeat/filebeat-compose.yml b/extensions/filebeat/filebeat-compose.yml index 84e3d1ba..2eb56c14 100644 --- a/extensions/filebeat/filebeat-compose.yml +++ b/extensions/filebeat/filebeat-compose.yml @@ -8,6 +8,7 @@ services: ELASTIC_VERSION: ${ELASTIC_VERSION} # Run as 'root' instead of 'filebeat' (uid 1000) to allow reading # 'docker.sock' and the host's filesystem. + container_name: filebeat user: root command: # Log to stderr. @@ -17,7 +18,7 @@ services: # see: https://www.elastic.co/guide/en/beats/libbeat/current/config-file-permissions.html - --strict.perms=false volumes: - - ./config/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro,Z + - ./extensions/filebeat/config/filebeat.yml:/usr/share/filebeat/filebeat.yml:ro,Z - type: bind source: /var/lib/docker/containers target: /var/lib/docker/containers diff --git a/extensions/fleet/agent-apmserver-compose.yml b/extensions/fleet/agent-apmserver-compose.yml index 0cda861b..4d338bad 100644 --- a/extensions/fleet/agent-apmserver-compose.yml +++ b/extensions/fleet/agent-apmserver-compose.yml @@ -10,6 +10,7 @@ services: context: extensions/fleet/ args: ELASTIC_VERSION: ${ELASTIC_VERSION} + container_name: apm-server volumes: - apm-server:/usr/share/elastic-agent/state:Z environment: diff --git a/extensions/fleet/fleet-compose.yml b/extensions/fleet/fleet-compose.yml index 89a3ebc1..61369e5d 100644 --- a/extensions/fleet/fleet-compose.yml +++ b/extensions/fleet/fleet-compose.yml @@ -6,6 +6,7 @@ services: context: extensions/fleet/ args: ELASTIC_VERSION: ${ELASTIC_VERSION} + container_name: fleet-server volumes: - fleet-server:/usr/share/elastic-agent/state:Z environment: diff --git a/extensions/heartbeat/heartbeat-compose.yml b/extensions/heartbeat/heartbeat-compose.yml index 6ad85c8e..e31d6b74 100644 --- a/extensions/heartbeat/heartbeat-compose.yml +++ b/extensions/heartbeat/heartbeat-compose.yml @@ -6,6 +6,7 @@ services: context: extensions/heartbeat/ args: ELASTIC_VERSION: ${ELASTIC_VERSION} + container_name: heartbeat command: # Log to stderr. - -e @@ -14,7 +15,7 @@ services: # see: https://www.elastic.co/guide/en/beats/libbeat/current/config-file-permissions.html - --strict.perms=false volumes: - - ./config/heartbeat.yml:/usr/share/heartbeat/heartbeat.yml:ro,Z + - ./extensions/heartbeat/config/heartbeat.yml:/usr/share/heartbeat/heartbeat.yml:ro,Z environment: HEARTBEAT_INTERNAL_PASSWORD: ${HEARTBEAT_INTERNAL_PASSWORD:-} BEATS_SYSTEM_PASSWORD: ${BEATS_SYSTEM_PASSWORD:-} diff --git a/extensions/logspout/logspout-compose.yml b/extensions/logspout/logspout-compose.yml index a05603ee..f0ef1004 100644 --- a/extensions/logspout/logspout-compose.yml +++ b/extensions/logspout/logspout-compose.yml @@ -4,6 +4,7 @@ services: logspout: build: context: extensions/logspout + container_name: logspout volumes: - type: bind source: /var/run/docker.sock diff --git a/extensions/metricbeat/config/metricbeat.yml b/extensions/metricbeat/config/metricbeat.yml index 1c2b6cb8..33a1c54d 100644 --- a/extensions/metricbeat/config/metricbeat.yml +++ b/extensions/metricbeat/config/metricbeat.yml @@ -18,7 +18,7 @@ metricbeat.autodiscover: metricbeat.modules: - module: elasticsearch hosts: [ http://elasticsearch:9200 ] - username: monitoring_internal + username: elastic password: ${MONITORING_INTERNAL_PASSWORD} xpack.enabled: true period: 10s @@ -30,7 +30,7 @@ metricbeat.modules: enabled: true - module: kibana hosts: [ http://kibana:5601 ] - username: monitoring_internal + username: elastic password: ${MONITORING_INTERNAL_PASSWORD} xpack.enabled: true period: 10s diff --git a/extensions/metricbeat/metricbeat-compose.yml b/extensions/metricbeat/metricbeat-compose.yml index c55a5e50..7a91e5de 100644 --- a/extensions/metricbeat/metricbeat-compose.yml +++ b/extensions/metricbeat/metricbeat-compose.yml @@ -8,6 +8,7 @@ services: ELASTIC_VERSION: ${ELASTIC_VERSION} # Run as 'root' instead of 'metricbeat' (uid 1000) to allow reading # 'docker.sock' and the host's filesystem. + container_name: metricbeat user: root command: # Log to stderr. @@ -20,7 +21,7 @@ services: # from within a container. - --system.hostfs=/hostfs volumes: - - ./config/metricbeat.yml:/usr/share/metricbeat/metricbeat.yml:ro,Z + - ./extensions/metricbeat/config/metricbeat.yml:/usr/share/metricbeat/metricbeat.yml:ro,Z - type: bind source: / target: /hostfs diff --git a/host/YANLib.HttpApi.Host/YANLib.HttpApi.Host.csproj b/host/YANLib.HttpApi.Host/YANLib.HttpApi.Host.csproj index 52dba7cf..16036593 100644 --- a/host/YANLib.HttpApi.Host/YANLib.HttpApi.Host.csproj +++ b/host/YANLib.HttpApi.Host/YANLib.HttpApi.Host.csproj @@ -1,52 +1,51 @@ - + - - net6.0 - YANLib - true - YANLib-4681b4fd-151f-4221-84a4-929d86723e4c - Linux - ..\.. - ..\..\docker-compose.dcproj - + + net6.0 + YANLib + true + YANLib-4681b4fd-151f-4221-84a4-929d86723e4c + Linux + ..\.. + ..\..\docker-compose.dcproj + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - + + + + + + - - - - - + + + + + diff --git a/host/YANLib.HttpApi.Host/YANLibHttpApiHostModule.cs b/host/YANLib.HttpApi.Host/YANLibHttpApiHostModule.cs index cff997b3..686cf640 100644 --- a/host/YANLib.HttpApi.Host/YANLibHttpApiHostModule.cs +++ b/host/YANLib.HttpApi.Host/YANLibHttpApiHostModule.cs @@ -19,11 +19,14 @@ using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Autofac; using Volo.Abp.Caching.StackExchangeRedis; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore.SqlServer; using Volo.Abp.Http.Client; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.Swashbuckle; using YANLib.EntityFrameworkCore; +using YANLib.Utilities; using static Elastic.Apm.Agent; using static System.StringSplitOptions; @@ -37,6 +40,7 @@ namespace YANLib; typeof(AbpAspNetCoreMvcUiLeptonXLiteThemeModule), typeof(AbpAspNetCoreSerilogModule), typeof(AbpSwashbuckleModule), + typeof(AbpEntityFrameworkCoreSqlServerModule), typeof(AbpCachingStackExchangeRedisModule), typeof(AbpHttpClientModule) )] @@ -45,6 +49,8 @@ public class YANLibHttpApiHostModule : AbpModule public override void ConfigureServices(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); + context.Services.AddElasticsearch(configuration); + Configure(o => o.UseSqlServer()); ConfigureConventionalControllers(); ConfigureLocalization(); ConfigureCors(context, configuration); diff --git a/host/YANLib.HttpApi.Host/appsettings.Development.json b/host/YANLib.HttpApi.Host/appsettings.Development.json index 6ef7dfb9..4d4c738d 100644 --- a/host/YANLib.HttpApi.Host/appsettings.Development.json +++ b/host/YANLib.HttpApi.Host/appsettings.Development.json @@ -1,4 +1,7 @@ { + "ConnectionStrings": { + "Default": "Server=localhost;Database=YANLIB;User ID=sa;Password=admin123@" + }, "Redis": { "Configuration": "localhost,password=admin123@" }, @@ -12,7 +15,7 @@ } }, "EventBus": { - "ClientName": "PublisherDev", + "ClientName": "SampleDev", "ExchangeName": "YanlibDev" } }, @@ -29,9 +32,17 @@ "TopicName": "yan.lib" } }, + "Elasticsearch": { + "Indices": { + "Sample": "yanlib_sample_index_dev" + }, + "Url": "http://localhost:9200/", + "Username": "elastic", + "Password": "admin123" + }, "RemoteServices": { "TestApi": { - "BaseUrl": "http://test-api.local/" + "BaseUrl": "http://sample-api.local/" } }, "Serilog": { @@ -90,7 +101,7 @@ "ElasticApm": { "ServiceName": "YANLib", "SecretToken": "YXBtOmFkbWluMTIz", - "ServerUrl": "http://apm-server:8200", + "ServerUrl": "http://localhost:8200", "Environment": "Development", "CaptureBody": "all", "LogLevel": "Trace" diff --git a/host/YANLib.HttpApi.Host/appsettings.Production.json b/host/YANLib.HttpApi.Host/appsettings.Production.json index 21a99aeb..e98b8886 100644 --- a/host/YANLib.HttpApi.Host/appsettings.Production.json +++ b/host/YANLib.HttpApi.Host/appsettings.Production.json @@ -1,4 +1,7 @@ { + "ConnectionStrings": { + "Default": "Server=localhost;Database=YANLIB;User ID=sa;Password=admin123@" + }, "Redis": { "Configuration": "localhost,password=admin123@" }, @@ -12,7 +15,7 @@ } }, "EventBus": { - "ClientName": "PublisherProd", + "ClientName": "SampleProd", "ExchangeName": "YanlibProd" } }, @@ -26,12 +29,20 @@ }, "EventBus": { "GroupId": "YanlibProd", - "TopicName": "yan.prod" + "TopicName": "yan.lib" } }, + "Elasticsearch": { + "Indices": { + "Sample": "yanlib_sample_index_prod" + }, + "Url": "http://elasticsearch:9200/", + "Username": "elastic", + "Password": "admin123" + }, "RemoteServices": { "TestApi": { - "BaseUrl": "http://test-api.local/" + "BaseUrl": "http://sample-api.local/" } }, "Serilog": { diff --git a/host/YANLib.HttpApi.Host/appsettings.json b/host/YANLib.HttpApi.Host/appsettings.json index 6d1ea785..d10788bf 100644 --- a/host/YANLib.HttpApi.Host/appsettings.json +++ b/host/YANLib.HttpApi.Host/appsettings.json @@ -5,7 +5,7 @@ "RedirectAllowedUrls": "" }, "ConnectionStrings": { - "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=YANLib;Trusted_Connection=True" + "Default": "Server=localhost;Database=YANLIB;User ID=sa;Password=admin123@" }, "AuthServer": { "Authority": "https://localhost:44380", diff --git a/logstash/pipeline/logstash.conf b/logstash/pipeline/logstash.conf index 10cb04c6..3c441cd9 100644 --- a/logstash/pipeline/logstash.conf +++ b/logstash/pipeline/logstash.conf @@ -7,6 +7,11 @@ input { port => 50000 } + udp { + port => 50000 + codec => json + } + file { path => "/usr/share/logstash/logs/*.log" sincedb_path => "/dev/null" diff --git a/src/YANLib.Application.Contracts/Common/RedisConstant.cs b/src/YANLib.Application.Contracts/Common/RedisConstant.cs new file mode 100644 index 00000000..4d8adf0f --- /dev/null +++ b/src/YANLib.Application.Contracts/Common/RedisConstant.cs @@ -0,0 +1,10 @@ +namespace YANLib.Common; + +public readonly struct RedisConstant +{ + public const string YANLIB_PREF = "yanlib"; + public const string SMP_PREF = "sample"; + public const string DEV_TYPE_PREF = "developtype"; + + public static readonly string DEV_TYPE_GRP = $"{YANLIB_PREF}:{SMP_PREF}:{DEV_TYPE_PREF}"; +} diff --git a/src/YANLib.Application.Contracts/DTOs/DeveloperTypeRedis.cs b/src/YANLib.Application.Contracts/DTOs/DeveloperTypeRedis.cs new file mode 100644 index 00000000..f6f7bdce --- /dev/null +++ b/src/YANLib.Application.Contracts/DTOs/DeveloperTypeRedis.cs @@ -0,0 +1,11 @@ +using System; + +namespace YANLib.DTOs; + +public sealed class DeveloperTypeRedis +{ + public string Name { get; set; } + public bool IsActive { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime? ModifiedDate { get; set; } +} diff --git a/src/YANLib.Application.Contracts/Dtos/JsonDto.cs b/src/YANLib.Application.Contracts/Dtos/JsonDto.cs deleted file mode 100644 index 6b0e780a..00000000 --- a/src/YANLib.Application.Contracts/Dtos/JsonDto.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace YANLib.Dtos; - -public class JsonDto -{ - public Guid Id { get; set; } -} diff --git a/src/YANLib.Application.Contracts/Dtos/RedisDto.cs b/src/YANLib.Application.Contracts/Dtos/RedisDto.cs deleted file mode 100644 index bed1d38d..00000000 --- a/src/YANLib.Application.Contracts/Dtos/RedisDto.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace YANLib.Dtos; - -public class RedisDto -{ - public int Id { get; set; } - public string Name { get; set; } -} diff --git a/src/YANLib.Application.Contracts/EsIndexs/DeveloperIndex.cs b/src/YANLib.Application.Contracts/EsIndexs/DeveloperIndex.cs new file mode 100644 index 00000000..e17a5354 --- /dev/null +++ b/src/YANLib.Application.Contracts/EsIndexs/DeveloperIndex.cs @@ -0,0 +1,23 @@ +using Nest; +using System; +using System.Collections.Generic; +using YANLib.Responses; + +namespace YANLib.EsIndexs; + +public sealed class DeveloperIndex +{ + public string Id { get; set; } + public Guid DeveloperId { get; set; } + [Keyword] + public string Name { get; set; } + public string IdCard { get; set; } + public bool IsActive { get; set; } + public int Version { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime? ModifiedDate { get; set; } + [Nested] + public DeveloperTypeResponse DeveloperType { get; set; } + [Nested] + public List Certificates { get; set; } +} diff --git a/src/YANLib.Application.Contracts/EsServices/ISampleEsService.cs b/src/YANLib.Application.Contracts/EsServices/ISampleEsService.cs new file mode 100644 index 00000000..da43e0ed --- /dev/null +++ b/src/YANLib.Application.Contracts/EsServices/ISampleEsService.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using YANLib.EsIndexs; + +namespace YANLib.EsServices; + +public interface ISampleEsService +{ + public ValueTask Get(string id); + public ValueTask Set(DeveloperIndex data); + public ValueTask SetBulk(List datas); + public ValueTask DeleteAll(); +} diff --git a/src/YANLib.Application.Contracts/Requests/CertificateFullRequest.cs b/src/YANLib.Application.Contracts/Requests/CertificateFullRequest.cs new file mode 100644 index 00000000..580f335f --- /dev/null +++ b/src/YANLib.Application.Contracts/Requests/CertificateFullRequest.cs @@ -0,0 +1,10 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace YANLib.Requests; + +public sealed class CertificateFullRequest : CertificateRequest +{ + [Required] + public Guid Id { get; set; } +} diff --git a/src/YANLib.Application.Contracts/Requests/CertificateRequest.cs b/src/YANLib.Application.Contracts/Requests/CertificateRequest.cs new file mode 100644 index 00000000..4f8b2a56 --- /dev/null +++ b/src/YANLib.Application.Contracts/Requests/CertificateRequest.cs @@ -0,0 +1,13 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace YANLib.Requests; + +public class CertificateRequest +{ + [Required] + public string Name { get; set; } + public float? GPA { get; set; } + [Required] + public Guid DeveloperId { get; set; } +} diff --git a/src/YANLib.Application.Contracts/Requests/DeveloperRequest.cs b/src/YANLib.Application.Contracts/Requests/DeveloperRequest.cs new file mode 100644 index 00000000..460ade52 --- /dev/null +++ b/src/YANLib.Application.Contracts/Requests/DeveloperRequest.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace YANLib.Requests; + +public sealed class DeveloperRequest +{ + [Required] + public string Name { get; set; } + [Required] + public string IdCard { get; set; } + [Required] + public int DeveloperTypeCode { get; set; } + public List Certificates { get; set; } +} diff --git a/src/YANLib.Application.Contracts/Requests/DeveloperTypeRequest.cs b/src/YANLib.Application.Contracts/Requests/DeveloperTypeRequest.cs new file mode 100644 index 00000000..7c032193 --- /dev/null +++ b/src/YANLib.Application.Contracts/Requests/DeveloperTypeRequest.cs @@ -0,0 +1,12 @@ +using System.ComponentModel.DataAnnotations; + +namespace YANLib.Requests; + +public sealed class DeveloperTypeRequest +{ + [Required] + public int Code { get; set; } + [Required] + public string Name { get; set; } + public bool IsActive { get; set; } = true; +} diff --git a/src/YANLib.Application.Contracts/Requests/SampleRequest.cs b/src/YANLib.Application.Contracts/Requests/SampleRequest.cs new file mode 100644 index 00000000..ead5b438 --- /dev/null +++ b/src/YANLib.Application.Contracts/Requests/SampleRequest.cs @@ -0,0 +1,8 @@ +using System; + +namespace YANLib.Requests; + +public sealed class SampleRequest +{ + public Guid Id { get; set; } +} diff --git a/src/YANLib.Application.Contracts/Responses/CertificateResponse.cs b/src/YANLib.Application.Contracts/Responses/CertificateResponse.cs new file mode 100644 index 00000000..17530a15 --- /dev/null +++ b/src/YANLib.Application.Contracts/Responses/CertificateResponse.cs @@ -0,0 +1,13 @@ +using System; + +namespace YANLib.Responses; + +public sealed record CertificateResponse +{ + public Guid Id { get; set; } + public string Name { get; set; } + public float? GPA { get; set; } + public Guid DeveloperId { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime? ModifiedDate { get; set; } +} diff --git a/src/YANLib.Application.Contracts/Responses/DeveloperResponse.cs b/src/YANLib.Application.Contracts/Responses/DeveloperResponse.cs new file mode 100644 index 00000000..09f8369b --- /dev/null +++ b/src/YANLib.Application.Contracts/Responses/DeveloperResponse.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; + +namespace YANLib.Responses; + +public sealed record DeveloperResponse +{ + public Guid Id { get; set; } + public string Name { get; set; } + public string IdCard { get; set; } + public bool IsActive { get; set; } + public int Version { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime? ModifiedDate { get; set; } + public DeveloperTypeResponse DeveloperType { get; set; } + public List Certificates { get; set; } +} diff --git a/src/YANLib.Application.Contracts/Responses/DeveloperTypeResponse.cs b/src/YANLib.Application.Contracts/Responses/DeveloperTypeResponse.cs new file mode 100644 index 00000000..be8ff8cd --- /dev/null +++ b/src/YANLib.Application.Contracts/Responses/DeveloperTypeResponse.cs @@ -0,0 +1,12 @@ +using System; + +namespace YANLib.Responses; + +public sealed record DeveloperTypeResponse +{ + public int Code { get; set; } + public string Name { get; set; } + public bool IsActive { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime? ModifiedDate { get; set; } +} diff --git a/src/YANLib.Application.Contracts/Services/ICertificateService.cs b/src/YANLib.Application.Contracts/Services/ICertificateService.cs new file mode 100644 index 00000000..a344cd48 --- /dev/null +++ b/src/YANLib.Application.Contracts/Services/ICertificateService.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using YANLib.Requests; +using YANLib.Responses; + +namespace YANLib.Services; + +public interface ICertificateService : IApplicationService +{ + public ValueTask Get(Guid id); + public ValueTask Insert(CertificateRequest request); + public ValueTask Update(CertificateFullRequest request); + public ValueTask> GetByDeveloperId(Guid developerId); +} diff --git a/src/YANLib.Application.Contracts/Services/IDeveloperTypeService.cs b/src/YANLib.Application.Contracts/Services/IDeveloperTypeService.cs new file mode 100644 index 00000000..64afb0df --- /dev/null +++ b/src/YANLib.Application.Contracts/Services/IDeveloperTypeService.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using YANLib.Requests; +using YANLib.Responses; + +namespace YANLib.Services; + +public interface IDeveloperTypeService : IApplicationService +{ + public ValueTask> GetAll(); + public ValueTask Get(int code); + public ValueTask Insert(DeveloperTypeRequest request); + public ValueTask Update(DeveloperTypeRequest request); + public ValueTask SyncDbToRedis(); +} diff --git a/src/YANLib.Application.Contracts/YANLib.Application.Contracts.csproj b/src/YANLib.Application.Contracts/YANLib.Application.Contracts.csproj index 3893c8fe..8bb5f057 100644 --- a/src/YANLib.Application.Contracts/YANLib.Application.Contracts.csproj +++ b/src/YANLib.Application.Contracts/YANLib.Application.Contracts.csproj @@ -1,19 +1,20 @@ - + - - net6.0 - YANLib - + + net6.0 + YANLib + - - - - + + + + + - - - + + + diff --git a/src/YANLib.Application.Redis/Services/Implements/RedisService.cs b/src/YANLib.Application.Redis/Services/Implements/DeveloperTypeRedisService.cs similarity index 64% rename from src/YANLib.Application.Redis/Services/Implements/RedisService.cs rename to src/YANLib.Application.Redis/Services/Implements/DeveloperTypeRedisService.cs index 012cf3ce..6752f207 100644 --- a/src/YANLib.Application.Redis/Services/Implements/RedisService.cs +++ b/src/YANLib.Application.Redis/Services/Implements/DeveloperTypeRedisService.cs @@ -2,25 +2,25 @@ using StackExchange.Redis; using Volo.Abp; using YANLib.Application.Redis.ConnectionFactory; -using YANLib.Dtos; -using YANLib.Exceptions; +using YANLib.DTOs; using static System.Text.Encoding; using static System.Threading.Tasks.Task; -using static YANLib.Exceptions.ExceptionMessage; +using static YANLib.YANLibConsts; +using static YANLib.YANLibDomainErrorCodes; namespace YANLib.Application.Redis.Services.Implements; -public class RedisService : IRedisService +public class DeveloperTypeRedisService : IRedisService { #region Fields - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IRedisConnectionFactory _connectionFactory; private readonly ConnectionMultiplexer _connectionMultiplexer; private readonly IDatabase _database; #endregion #region Constructors - public RedisService(ILogger logger, IRedisConnectionFactory connectionFactory) + public DeveloperTypeRedisService(ILogger logger, IRedisConnectionFactory connectionFactory) { _logger = logger; _connectionFactory = connectionFactory; @@ -30,78 +30,89 @@ public RedisService(ILogger logger, IRedisConnectionFactory connec #endregion #region Implements - public async ValueTask Get(string group, string key) + public async ValueTask Get(string group, string key) { try { if (group.IsWhiteSpaceOrNull() || key.IsWhiteSpaceOrNull()) { - throw new BusinessException(code: ExceptionCode.BAD_REQUEST, message: BAD_REQUEST); + throw new BusinessException(BAD_REQUEST); } + var val = await _database.HashGetAsync((RedisKey)group.ToLowerInvariant(), (RedisValue)key.ToLowerInvariant()); - return val.HasValue ? UTF8.GetString(val!).Deserialize() : default; + + return val.HasValue ? UTF8.GetString(val!).Deserialize() : default; } catch (Exception ex) { - _logger.LogError(ex, "GetRedisService-Exception: {Group} ; {Key}", group, key); + _logger.LogError(ex, "GetDeveloperTypeRedisService-Exception: {Group} - {Key}", group, key); throw; } } - public async ValueTask?> GetBulk(string group, params string[] keys) + public async ValueTask?> GetBulk(string group, params string[] keys) { try { if (group.IsWhiteSpaceOrNull() || keys.AllWhiteSpaceOrNull()) { - throw new BusinessException(code: ExceptionCode.BAD_REQUEST, message: BAD_REQUEST); + throw new BusinessException(BAD_REQUEST); } - var rslts = new Dictionary(); + + var rslts = new Dictionary(); var semSlim = new SemaphoreSlim(1); + await WhenAll(keys.Select(async k => { - var val = await _database.HashGetAsync((RedisKey)group.ToLowerInvariant(), (RedisValue)k.ToLowerInvariant()); - if (val.HasValue) + await semSlim.WaitAsync(); + + try { - await semSlim.WaitAsync(); - try - { - rslts.Add(k, UTF8.GetString(val!).Deserialize()); - } - finally + var val = await _database.HashGetAsync((RedisKey)group.ToLowerInvariant(), (RedisValue)k.ToLowerInvariant()); + + if (val.HasValue) { - _ = semSlim.Release(); + rslts.Add(k, UTF8.GetString(val!).Deserialize()); } } + finally + { + _ = semSlim.Release(); + } })); + return rslts; } catch (Exception ex) { - _logger.LogError(ex, "GetBulkRedisService-Exception: {Group} ; {Keys}", group, string.Join(", ", keys)); + _logger.LogError(ex, "GetBulkDeveloperTypeRedisService-Exception: {Group} - {Keys}", group, string.Join(", ", keys)); throw; } } - public async ValueTask?> GetAll(string group) + public async ValueTask?> GetAll(string group) { try { if (group.IsWhiteSpaceOrNull()) { - throw new BusinessException(code: ExceptionCode.BAD_REQUEST, message: BAD_REQUEST); + throw new BusinessException(BAD_REQUEST); } - var rslts = new Dictionary(); + + var rslts = new Dictionary(); var semSlim = new SemaphoreSlim(1); + await WhenAll((await _database.HashGetAllAsync(group.ToLowerInvariant())).Where(e => e.Name.HasValue && e.Value.HasValue).Select(async x => { var val = x.Value; + if (val.HasValue) { await semSlim.WaitAsync(); + try { - rslts.Add(x.Name.ToString(), UTF8.GetString(val!).Deserialize()); + rslts.Add(x.Name.ToString(), UTF8.GetString(val!).Deserialize()); } finally { @@ -109,45 +120,49 @@ await WhenAll((await _database.HashGetAllAsync(group.ToLowerInvariant())).Where( } } })); + return rslts; } catch (Exception ex) { - _logger.LogError(ex, "GetAllRedisService-Exception: {Group}", group); + _logger.LogError(ex, "GetAllDeveloperTypeRedisService-Exception: {Group}", group); throw; } } - public async ValueTask Set(string group, string key, JsonDto value) + public async ValueTask Set(string group, string key, DeveloperTypeRedis value) { var jsonVal = value.CamelSerialize(); + try { return group.IsWhiteSpaceOrNull() || key.IsWhiteSpaceOrNull() || value is null - ? throw new BusinessException(code: ExceptionCode.BAD_REQUEST, message: BAD_REQUEST) - : await Delete(group, key) && await _database.HashSetAsync((RedisKey)group.ToLowerInvariant(), (RedisValue)key.ToLowerInvariant(), jsonVal); + ? throw new BusinessException(BAD_REQUEST) + : await _database.HashSetAsync((RedisKey)group.ToLowerInvariant(), (RedisValue)key.ToLowerInvariant(), jsonVal); } catch (Exception ex) { - _logger.LogError(ex, "SetRedisService-Exception: {Group} ; {Key} ; {Value}", group, key, jsonVal); + _logger.LogError(ex, "SetDeveloperTypeRedisService-Exception: {Group} - {Key} - {Value}", group, key, jsonVal); throw; } } - public async ValueTask SetBulk(string group, IDictionary fields) + public async ValueTask SetBulk(string group, IDictionary fields) { try { if (group.IsWhiteSpaceOrNull() || fields.IsEmptyOrNull()) { - throw new BusinessException(code: ExceptionCode.BAD_REQUEST, message: BAD_REQUEST); + throw new BusinessException(BAD_REQUEST); } + await _database.HashSetAsync(group.ToLowerInvariant(), fields.Select(p => new HashEntry(p.Key.ToLowerInvariant(), p.Value.CamelSerialize())).ToArray()); + return true; } catch (Exception ex) { - _logger.LogError(ex, "SetBulkRedisService-Exception: {Group} ; {Fields}", group, fields.CamelSerialize()); + _logger.LogError(ex, "SetBulkDeveloperTypeRedisService-Exception: {Group} - {Fields}", group, fields.CamelSerialize()); throw; } } @@ -156,13 +171,11 @@ public async ValueTask Delete(string group, string key) { try { - return group.IsWhiteSpaceOrNull() || key.IsWhiteSpaceOrNull() - ? throw new BusinessException(code: ExceptionCode.BAD_REQUEST, message: BAD_REQUEST) - : await _database.HashDeleteAsync((RedisKey)group.ToLowerInvariant(), (RedisValue)key.ToLowerInvariant()); + return group.IsWhiteSpaceOrNull() || key.IsWhiteSpaceOrNull() ? throw new BusinessException(BAD_REQUEST) : await _database.HashDeleteAsync((RedisKey)group.ToLowerInvariant(), (RedisValue)key.ToLowerInvariant()); } catch (Exception ex) { - _logger.LogError(ex, "DeleteRedisService-Exception: {Group} ; {Key}", group, key); + _logger.LogError(ex, "DeleteDeveloperTypeRedisService-Exception: {Group} - {Key}", group, key); throw; } } @@ -173,13 +186,16 @@ public async ValueTask DeleteBulk(string group, params string[] keys) { if (group.IsWhiteSpaceOrNull() || keys.AllWhiteSpaceOrNull()) { - throw new BusinessException(code: ExceptionCode.BAD_REQUEST, message: BAD_REQUEST); + throw new BusinessException(BAD_REQUEST); } + var rslt = true; var semSlim = new SemaphoreSlim(1); + await WhenAll(keys.Where(k => k.IsNotWhiteSpaceAndNull()).Select(async k => { await semSlim.WaitAsync(); + try { rslt = rslt && await _database.HashDeleteAsync((RedisKey)group.ToLowerInvariant(), (RedisValue)k.ToLowerInvariant()); @@ -189,11 +205,12 @@ await WhenAll(keys.Where(k => k.IsNotWhiteSpaceAndNull()).Select(async k => _ = semSlim.Release(); } })); + return rslt; } catch (Exception ex) { - _logger.LogError(ex, "DeleteBulkRedisService-Exception: {Group} ; {Keys}", group, string.Join(", ", keys)); + _logger.LogError(ex, "DeleteBulkDeveloperTypeRedisService-Exception: {Group} - {Keys}", group, string.Join(", ", keys)); throw; } } @@ -204,36 +221,43 @@ public async ValueTask DeleteAll(string group) { if (group.IsWhiteSpaceOrNull()) { - throw new BusinessException(code: ExceptionCode.BAD_REQUEST, message: BAD_REQUEST); + throw new BusinessException(BAD_REQUEST); } + var dic = await GetAll(group); + return dic!.IsEmptyOrNull() || await DeleteBulk(group, dic!.Select(p => p.Key).ToArray()); } catch (Exception ex) { - _logger.LogError(ex, "DeleteAllRedisService-Exception: {Group}", group); + _logger.LogError(ex, "DeleteAllDeveloperTypeRedisService-Exception: {Group}", group); throw; } } - public async ValueTask?>?> GetGroup(string groupPreffix) + public async ValueTask?>?> GetGroup(string groupPreffix) { try { var redisRslt = await GetGroupKeys(groupPreffix); + if (redisRslt is not null) { var keys = (RedisKey[])redisRslt!; - var rslts = new Dictionary?>(); + var rslts = new Dictionary?>(); + if (keys.IsNotEmptyAndNull()) { var semSlim = new SemaphoreSlim(1); + await WhenAll(keys.Select(async k => { var dic = await GetAll(k!); + if (dic!.IsNotEmptyAndNull()) { await semSlim.WaitAsync(); + try { rslts.Add(k.ToString().Split(":").Reverse().FirstOrDefault() ?? string.Empty, dic!); @@ -245,13 +269,15 @@ await WhenAll(keys.Select(async k => } })); } + return rslts; } + return default; } catch (Exception ex) { - _logger.LogError(ex, "GetGroupRedisService-Exception: {GroupPreffix}", groupPreffix); + _logger.LogError(ex, "GetGroupDeveloperTypeRedisService-Exception: {GroupPreffix}", groupPreffix); throw; } } @@ -261,16 +287,19 @@ public async ValueTask DeleteGroup(string groupPreffix) try { var redisRslt = await GetGroupKeys(groupPreffix); + if (redisRslt is not null) { var keys = (RedisKey[])redisRslt!; + return keys.IsEmptyOrNull() || await _database.KeyDeleteAsync(keys) > 0; } - return false; + + return default; } catch (Exception ex) { - _logger.LogError(ex, "DeleteGroupRedisService-Exception: {GroupPreffix}", groupPreffix); + _logger.LogError(ex, "DeleteGroupDeveloperTypeRedisService-Exception: {GroupPreffix}", groupPreffix); throw; } } @@ -281,13 +310,11 @@ private async ValueTask GetGroupKeys(string groupPreffix) { try { - return groupPreffix.IsWhiteSpaceOrNull() - ? throw new BusinessException(code: ExceptionCode.BAD_REQUEST, message: BAD_REQUEST) - : await _database.ExecuteAsync("KEYS", $"{groupPreffix}*"); + return groupPreffix.IsWhiteSpaceOrNull() ? throw new BusinessException(BAD_REQUEST) : await _database.ExecuteAsync(RedisKeyCommand, $"{groupPreffix}*"); } catch (Exception ex) { - _logger.LogError(ex, "GetGroupKeysRedisService-Exception: {GroupPreffix}", groupPreffix); + _logger.LogError(ex, "GetGroupKeysDeveloperTypeRedisService-Exception: {GroupPreffix}", groupPreffix); throw; } } diff --git a/src/YANLib.Application.Redis/YANLib.Application.Redis.csproj b/src/YANLib.Application.Redis/YANLib.Application.Redis.csproj index 77079306..bf7d8994 100644 --- a/src/YANLib.Application.Redis/YANLib.Application.Redis.csproj +++ b/src/YANLib.Application.Redis/YANLib.Application.Redis.csproj @@ -1,19 +1,19 @@ - - net6.0 - enable - enable - + + net6.0 + enable + enable + - - - + + + - - - - - + + + + + diff --git a/src/YANLib.Application.Redis/YANLibApplicationRedisModule.cs b/src/YANLib.Application.Redis/YANLibApplicationRedisModule.cs index 5ae61328..555a28cc 100644 --- a/src/YANLib.Application.Redis/YANLibApplicationRedisModule.cs +++ b/src/YANLib.Application.Redis/YANLibApplicationRedisModule.cs @@ -1,4 +1,10 @@ -using Volo.Abp.Modularity; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.Abp.Modularity; +using YANLib.Application.Redis.ConnectionFactory; +using YANLib.Application.Redis.Services; +using YANLib.Application.Redis.Services.Implements; +using YANLib.DTOs; namespace YANLib.Application.Redis; @@ -8,4 +14,13 @@ namespace YANLib.Application.Redis; )] public class YANLibApplicationRedisModule : AbpModule { + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + Configure(o => o.RedisConnectionString = configuration["Redis:Configuration"]); + _ = context.Services.AddSingleton, DeveloperTypeRedisService>(); + } + + public override void OnApplicationShutdown(ApplicationShutdownContext context) => context.ServiceProvider.GetRequiredService().Connection().CloseAsync(); } diff --git a/src/YANLib.Application/EsServices/SampleEsService.cs b/src/YANLib.Application/EsServices/SampleEsService.cs new file mode 100644 index 00000000..8780b003 --- /dev/null +++ b/src/YANLib.Application/EsServices/SampleEsService.cs @@ -0,0 +1,116 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Nest; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using YANLib.EsIndexs; +using YANLib.Utilities; +using static System.Threading.Tasks.Task; +using static YANLib.YANLibConsts; + +namespace YANLib.EsServices; + +public class SampleEsService : YANLibAppService, ISampleEsService +{ + private readonly ILogger _logger; + private readonly IElasticClient _elasticClient; + private readonly IConfiguration _configuration; + + public SampleEsService(ILogger logger, IElasticClient elasticClient, IConfiguration configuration) + { + _logger = logger; + _elasticClient = elasticClient; + _configuration = configuration; + } + + public async ValueTask Get(string id) + { + try + { + return (await _elasticClient.GetAsync(id)).Source ?? default; + } + catch (Exception ex) + { + _logger.LogError(ex, "GetSampleEsService-Exception: {Id}", id); + throw; + } + } + + public async ValueTask Set(DeveloperIndex data) + { + data.Id = data.IdCard; + + try + { + var res = await _elasticClient.IndexDocumentAsync(data); + + if (!res.IsValid) + { + _logger.LogError("SetSampleEsService-Failed: {Id} - {ServerError}", res.Id, res.ServerError.CamelSerialize()); + + return default; + } + + return true; + } + catch (Exception ex) + { + _logger.LogError(ex, "SetSampleEsService-Exception: {Data}", data.CamelSerialize()); + throw; + } + } + + public async ValueTask SetBulk(List datas) + { + try + { + var index = _configuration.GetSection(IdxSample)?.Value; + + if (index.IsWhiteSpaceOrNull()) + { + return false; + } + + var reqs = new BulkDescriptor(); + + foreach (var data in datas.OrderBy(x => x.CreatedDate)) + { + data.Id = data.IdCard; + reqs.Index(x => x.Document(data).Index(index)); + } + + var res = await _elasticClient.BulkAsync(reqs); + + if (!res.IsValid) + { + _logger.LogError("SetBulkSampleEsService-Failed: {ServerError}", res.ServerError.CamelSerialize()); + + return false; + } + + return true; + } + catch (Exception ex) + { + _logger.LogError(ex, "SetBulkSampleEsService-Exception: {Datas}", datas.CamelSerialize()); + throw; + } + } + + public async ValueTask DeleteAll() + { + try + { + _ = _elasticClient.DeleteSampleIndex(); + + return await FromResult(true); + } + catch (Exception ex) + { + _logger.LogError(ex, "DeleteAllSampleEsService-Exception"); + throw; + } + } +} diff --git a/src/YANLib.Application/Mappers/CertificateMapper.cs b/src/YANLib.Application/Mappers/CertificateMapper.cs new file mode 100644 index 00000000..cecb6c21 --- /dev/null +++ b/src/YANLib.Application/Mappers/CertificateMapper.cs @@ -0,0 +1,24 @@ +using AutoMapper; +using Volo.Abp.AutoMapper; +using YANLib.Models; +using YANLib.Requests; +using YANLib.Responses; + +namespace YANLib.Mappers; + +public sealed class CertificateMapper : Profile +{ + public CertificateMapper() + { + _ = CreateMap() + .Ignore(d => d.CreatedDate) + .Ignore(d => d.ModifiedDate); + + _ = CreateMap() + .Ignore(d => d.Id) + .Ignore(d => d.CreatedDate) + .Ignore(d => d.ModifiedDate); + + _ = CreateMap().ReverseMap(); + } +} diff --git a/src/YANLib.Application/Mappers/DeveloperTypeMapper.cs b/src/YANLib.Application/Mappers/DeveloperTypeMapper.cs new file mode 100644 index 00000000..a45fc31f --- /dev/null +++ b/src/YANLib.Application/Mappers/DeveloperTypeMapper.cs @@ -0,0 +1,33 @@ +using AutoMapper; +using System.Collections.Generic; +using Volo.Abp.AutoMapper; +using YANLib.DTOs; +using YANLib.Models; +using YANLib.Requests; +using YANLib.Responses; + +namespace YANLib.Mappers; + +public sealed class DeveloperTypeMapper : Profile +{ + public DeveloperTypeMapper() + { + _ = CreateMap() + .Ignore(d => d.CreatedDate) + .Ignore(d => d.ModifiedDate); + + _ = CreateMap().ReverseMap(); + + _ = CreateMap, DeveloperTypeResponse>() + .ForMember(d => d.Code, o => o.MapFrom(s => s.Key.ToInt())) + .ForMember(d => d.Name, o => o.MapFrom(s => s.Value.Name)) + .ForMember(d => d.IsActive, o => o.MapFrom(s => s.Value.IsActive)) + .ForMember(d => d.CreatedDate, o => o.MapFrom(s => s.Value.CreatedDate)) + .ForMember(d => d.ModifiedDate, o => o.MapFrom(s => s.Value.ModifiedDate)); + + _ = CreateMap() + .Ignore(d => d.Code); + + _ = CreateMap(); + } +} diff --git a/src/YANLib.Application/Services/CertificateService.cs b/src/YANLib.Application/Services/CertificateService.cs new file mode 100644 index 00000000..a966e1ab --- /dev/null +++ b/src/YANLib.Application/Services/CertificateService.cs @@ -0,0 +1,81 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using YANLib.Models; +using YANLib.Repositories; +using YANLib.Requests; +using YANLib.Responses; + +namespace YANLib.Services; + +public class CertificateService : YANLibAppService, ICertificateService +{ + #region Fields + private readonly ILogger _logger; + private readonly ICertificateRepository _repository; + #endregion + + #region Constructors + public CertificateService(ILogger logger, ICertificateRepository repository) + { + _logger = logger; + _repository = repository; + } + #endregion + + #region Implements + public async ValueTask Get(Guid id) + { + try + { + return ObjectMapper.Map(await _repository.Get(id)); + } + catch (Exception ex) + { + _logger.LogError(ex, "GetCertificateService-Exception: {Id}", id); + throw; + } + } + + public async ValueTask Insert(CertificateRequest request) + { + try + { + return ObjectMapper.Map(await _repository.Insert(ObjectMapper.Map(request))); + } + catch (Exception ex) + { + _logger.LogError(ex, "InsertCertificateService-Exception: {Request}", request.CamelSerialize()); + throw; + } + } + + public async ValueTask Update(CertificateFullRequest request) + { + try + { + return ObjectMapper.Map(await _repository.Update(ObjectMapper.Map(request))); + } + catch (Exception ex) + { + _logger.LogError(ex, "UpdateCertificateService-Exception: {Request}", request.CamelSerialize()); + throw; + } + } + + public async ValueTask> GetByDeveloperId(Guid developerId) + { + try + { + return ObjectMapper.Map, IEnumerable>(await _repository.GetByDeveloperId(developerId)).ToList(); + } + catch (Exception ex) + { + _logger.LogError(ex, "GetByDeveloperIdCertificateService-Exception: {DeveloperId}", developerId); + throw; + } + } + #endregion +} diff --git a/src/YANLib.Application/Services/DeveloperTypeService.cs b/src/YANLib.Application/Services/DeveloperTypeService.cs new file mode 100644 index 00000000..18666003 --- /dev/null +++ b/src/YANLib.Application/Services/DeveloperTypeService.cs @@ -0,0 +1,124 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using YANLib.Application.Redis.Services; +using YANLib.DTOs; +using YANLib.Models; +using YANLib.Repositories; +using YANLib.Requests; +using YANLib.Responses; +using static YANLib.Common.RedisConstant; + +namespace YANLib.Services; + +public class DeveloperTypeService : YANLibAppService, IDeveloperTypeService +{ + #region Fields + private readonly ILogger _logger; + private readonly IDeveloperTypeRepository _repository; + private readonly IRedisService _redisService; + #endregion + + #region Constructors + public DeveloperTypeService(ILogger logger, IDeveloperTypeRepository repository, IRedisService redisService) + { + _logger = logger; + _repository = repository; + _redisService = redisService; + } + #endregion + + #region Implements + public async ValueTask> GetAll() + { + try + { + return (await _redisService.GetAll(DEV_TYPE_GRP)).Select(ObjectMapper.Map, DeveloperTypeResponse>).ToList(); + } + catch (Exception ex) + { + _logger.LogError(ex, "GetAllDeveloperTypeService-Exception"); + throw; + } + } + + public async ValueTask Get(int code) + { + try + { + var rslt = ObjectMapper.Map(await _redisService.Get(DEV_TYPE_GRP, code.ToString())); + + if (rslt is not null) + { + rslt.Code = code; + } + + return rslt; + } + catch (Exception ex) + { + _logger.LogError(ex, "GetDeveloperTypeService-Exception: {Code}", code); + throw; + } + } + + public async ValueTask Insert(DeveloperTypeRequest request) + { + try + { + var mdl = await _repository.Insert(ObjectMapper.Map(request)); + + if (mdl is not null) + { + await _redisService.Set(DEV_TYPE_GRP, mdl.Code.ToString(), ObjectMapper.Map(mdl)); + } + + return ObjectMapper.Map(mdl); + } + catch (Exception ex) + { + _logger.LogError(ex, "InsertDeveloperTypeService-Exception: {Request}", request.CamelSerialize()); + throw; + } + } + + public async ValueTask Update(DeveloperTypeRequest request) + { + try + { + var mdl = await _repository.Update(ObjectMapper.Map(request)); + + if (mdl is not null) + { + await _redisService.Set(DEV_TYPE_GRP, mdl.Code.ToString(), ObjectMapper.Map(mdl)); + } + + return ObjectMapper.Map(mdl); + } + catch (Exception ex) + { + _logger.LogError(ex, "UpdateDeveloperTypeService-Exception: {Request}", request.CamelSerialize()); + throw; + } + } + + public async ValueTask SyncDbToRedis() + { + try + { + var task = _redisService.DeleteAll(DEV_TYPE_GRP); + var mdls = await _repository.GetAll(); + var rslt = await task; + + return mdls.IsNotEmptyAndNull() ? rslt && await _redisService.SetBulk(DEV_TYPE_GRP, mdls.ToDictionary(x => x.Code.ToString(), ObjectMapper.Map)) : rslt; + } + catch (Exception ex) + { + _logger.LogError(ex, "SyncDbToRedisDeveloperTypeService-Exception"); + throw; + } + } + #endregion +} diff --git a/src/YANLib.Application/Services/YANJsonService.cs b/src/YANLib.Application/Services/YANJsonService.cs index 0d0359be..a9790c88 100644 --- a/src/YANLib.Application/Services/YANJsonService.cs +++ b/src/YANLib.Application/Services/YANJsonService.cs @@ -2,7 +2,7 @@ using System.Text.Json; using System.Threading.Tasks; using Volo.Abp.Json; -using YANLib.Dtos; +using YANLib.Requests; using static Newtonsoft.Json.JsonConvert; using static System.Guid; using static System.Text.Json.JsonSerializer; @@ -12,17 +12,22 @@ namespace YANLib.Services; public class YANJsonService : YANLibAppService, IYANJsonService { + #region Fields private readonly IJsonSerializer _jsonSerializer; + #endregion + #region Constructors public YANJsonService(IJsonSerializer jsonSerializer) => _jsonSerializer = jsonSerializer; + #endregion + #region Implements public async ValueTask YanVsStandards(uint quantity, bool hideSystem) { - var json = new JsonDto + var json = new SampleRequest { Id = NewGuid() }.Serialize(); - var jsonCamel = new JsonDto + var jsonCamel = new SampleRequest { Id = NewGuid() }.CamelSerialize(); @@ -34,7 +39,7 @@ public async ValueTask YanVsStandards(uint quantity, bool hideSystem) var last = string.Empty; for (var i = 0; i < quantity; i++) { - var dto = DeserializeObject(i is 0 ? json : jsonCamel); + var dto = DeserializeObject(i is 0 ? json : jsonCamel); first = i is 0 ? dto.Id.ToString().Replace("-", string.Empty) : first; last = i == quantity - 1 ? dto.Id.ToString().Replace("-", string.Empty) : last; } @@ -49,7 +54,7 @@ public async ValueTask YanVsStandards(uint quantity, bool hideSystem) var last = string.Empty; for (var i = 0; i < quantity; i++) { - var dto = (JsonDto)_jsonSerializer.Deserialize(typeof(JsonDto), i is 0 ? json : jsonCamel); + var dto = (SampleRequest)_jsonSerializer.Deserialize(typeof(SampleRequest), i is 0 ? json : jsonCamel); first = i is 0 ? dto.Id.ToString().Replace("-", string.Empty) : first; last = i == quantity - 1 ? dto.Id.ToString().Replace("-", string.Empty) : last; } @@ -64,7 +69,7 @@ public async ValueTask YanVsStandards(uint quantity, bool hideSystem) var last = string.Empty; for (var i = 0; i < quantity; i++) { - var dto = (i is 0 ? json : jsonCamel).Deserialize(); + var dto = (i is 0 ? json : jsonCamel).Deserialize(); first = i is 0 ? dto.Id.ToString().Replace("-", string.Empty) : first; last = i == quantity - 1 ? dto.Id.ToString().Replace("-", string.Empty) : last; } @@ -81,7 +86,7 @@ public async ValueTask YanVsStandards(uint quantity, bool hideSystem) var last = string.Empty; for (var i = 0; i < quantity; i++) { - var dto = Deserialize(i is 0 ? json : jsonCamel); + var dto = Deserialize(i is 0 ? json : jsonCamel); first = i is 0 ? dto.Id.ToString().Replace("-", string.Empty) : first; last = i == quantity - 1 ? dto.Id.ToString().Replace("-", string.Empty) : last; } @@ -96,7 +101,7 @@ public async ValueTask YanVsStandards(uint quantity, bool hideSystem) var last = string.Empty; for (var i = 0; i < quantity; i++) { - var dto = Deserialize(i is 0 ? json : jsonCamel, new JsonSerializerOptions + var dto = Deserialize(i is 0 ? json : jsonCamel, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); @@ -115,4 +120,5 @@ public async ValueTask YanVsStandards(uint quantity, bool hideSystem) return $"Newtonsoft 13.0.3:\t{newtonsoftTask.Result}\nVolo.Abp 6.0.3:\t\t{voloTask.Result}\nYANLib:\t\t\t{yanTask.Result}"; } } + #endregion } diff --git a/src/YANLib.Application/Utilities/ElasticsearchUtil.cs b/src/YANLib.Application/Utilities/ElasticsearchUtil.cs new file mode 100644 index 00000000..6d2d52f0 --- /dev/null +++ b/src/YANLib.Application/Utilities/ElasticsearchUtil.cs @@ -0,0 +1,58 @@ +using Elasticsearch.Net; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Nest; +using System; +using System.Linq; +using YANLib.EsIndexs; +using static Elasticsearch.Net.CertificateValidations; +using static System.TimeSpan; +using static YANLib.YANLibConsts; + +namespace YANLib.Utilities; + +public static class ElasticsearchUtil +{ + #region Fields + private static string _indexSample; + #endregion + + #region Extensions + public static void AddElasticsearch(this IServiceCollection services, IConfiguration configuration) + { + var urlTag = "Elasticsearch:Url"; + var usernameTag = "Elasticsearch:Username"; + var pwdTag = "Elasticsearch:Password"; + var settings = new ConnectionSettings(configuration.GetSection(urlTag).GetChildren().Any() + ? new StaticConnectionPool((configuration.GetSection(urlTag).GetChildren().Any() + ? configuration.GetSection(urlTag).GetChildren().ToArray() + : (new IConfigurationSection[] { configuration.GetSection(urlTag) })).Select(s => new Uri(s.Value)).ToArray()) + : new SingleNodeConnectionPool(new Uri(configuration.GetSection(urlTag).Value))).DefaultIndex(configuration.GetSection(IdxSample)?.Value).EnableDebugMode().PrettyJson().RequestTimeout(FromMinutes(2)); + + if (configuration.GetSection(usernameTag).Value.IsWhiteSpaceOrNull()) + { + settings.ServerCertificateValidationCallback((o, certificate, chain, errors) => true); + settings.ServerCertificateValidationCallback(AllowAll); + settings.BasicAuthentication(configuration.GetSection(usernameTag).Value, configuration.GetSection(pwdTag).Value); + } + + _indexSample = configuration.GetSection(IdxSample)?.Value; + _ = settings.DefaultMappingFor(m => m.IndexName(_indexSample)); + + var client = new ElasticClient(settings); + + if (!client.Indices.Exists(configuration.GetSection(IdxSample)?.Value).Exists) + { + _ = client.Indices.Create(configuration.GetSection(IdxSample).Value, c => c + .Map(t => t + .AutoMap().Properties(p => p + .Text(d => d + .Name(x => x.Id))))); + } + + _ = services.AddSingleton(client); + } + + public static DeleteIndexResponse DeleteSampleIndex(this IElasticClient client) => _indexSample.IsNotWhiteSpaceAndNull() ? client.Indices.Delete(_indexSample) : default; + #endregion +} diff --git a/src/YANLib.Application/Validations/CertificateValidation.cs b/src/YANLib.Application/Validations/CertificateValidation.cs new file mode 100644 index 00000000..4da5c51e --- /dev/null +++ b/src/YANLib.Application/Validations/CertificateValidation.cs @@ -0,0 +1,70 @@ +using FluentValidation; +using System.Collections.Generic; +using System.Linq; +using YANLib.Requests; +using static YANLib.YANLibDomainErrorCodes; + +namespace YANLib.Validations; + +public sealed class CertificateFullValidator : AbstractValidator +{ + public CertificateFullValidator() + { + _ = RuleFor(x => x.Id).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_ID); + _ = RuleFor(x => x.Name).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_NAME); + _ = RuleFor(x => x.GPA).GreaterThan(0).WithErrorCode(BAD_REQUEST_GPA); + _ = RuleFor(x => x.DeveloperId).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_DEV_ID); + } +} + +public sealed class CertificateFullValidators : AbstractValidator> +{ + #region Constructors + public CertificateFullValidators() + { + _ = RuleFor(x => x).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST); + + _ = RuleForEach(s => s).SetValidator(new CertificateFullValidator()); + + _ = RuleFor(x => x).Must(IsNotEmptyAndNull).WithErrorCode(BAD_REQUEST); + _ = RuleFor(x => x).Must(NameIsNotWhiteSpace).WithErrorCode(BAD_REQUEST_NAME); + } + #endregion + + #region Methods + private bool IsNotEmptyAndNull(List requests) => requests.IsNotEmptyAndNull(); + + private bool NameIsNotWhiteSpace(List requests) => requests.Select(x => x.Name).AllNotWhiteSpaceAndNull(); + #endregion +} + +public sealed class CertificateValidator : AbstractValidator +{ + public CertificateValidator() + { + _ = RuleFor(x => x.Name).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_NAME); + _ = RuleFor(x => x.GPA).GreaterThan(0).WithErrorCode(BAD_REQUEST_GPA); + _ = RuleFor(x => x.DeveloperId).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_DEV_ID); + } +} + +public sealed class CertificateValidators : AbstractValidator> +{ + #region Constructors + public CertificateValidators() + { + _ = RuleFor(x => x).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST); + + _ = RuleForEach(s => s).SetValidator(new CertificateValidator()); + + _ = RuleFor(x => x).Must(IsNotEmptyAndNull).WithErrorCode(BAD_REQUEST); + _ = RuleFor(x => x).Must(NameIsNotWhiteSpace).WithErrorCode(BAD_REQUEST_NAME); + } + #endregion + + #region Methods + private bool IsNotEmptyAndNull(List requests) => requests.IsNotEmptyAndNull(); + + private bool NameIsNotWhiteSpace(List requests) => requests.Select(x => x.Name).AllNotWhiteSpaceAndNull(); + #endregion +} diff --git a/src/YANLib.Application/Validations/DeveloperTypeValidation.cs b/src/YANLib.Application/Validations/DeveloperTypeValidation.cs new file mode 100644 index 00000000..6f126f2e --- /dev/null +++ b/src/YANLib.Application/Validations/DeveloperTypeValidation.cs @@ -0,0 +1,37 @@ +using FluentValidation; +using System.Collections.Generic; +using System.Linq; +using YANLib.Requests; +using static YANLib.YANLibDomainErrorCodes; + +namespace YANLib.Validations; + +public sealed class DeveloperTypeValidator : AbstractValidator +{ + public DeveloperTypeValidator() + { + _ = RuleFor(x => x.Code).NotNull().NotEmpty().GreaterThanOrEqualTo(0).WithErrorCode(BAD_REQUEST_CODE); + _ = RuleFor(x => x.Name).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_NAME); + } +} + +public sealed class DeveloperTypeValidators : AbstractValidator> +{ + #region Constructors + public DeveloperTypeValidators() + { + _ = RuleFor(x => x).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST); + + _ = RuleForEach(s => s).SetValidator(new DeveloperTypeValidator()); + + _ = RuleFor(x => x).Must(IsNotEmptyAndNull).WithErrorCode(BAD_REQUEST); + _ = RuleFor(x => x).Must(NameIsNotWhiteSpace).WithErrorCode(BAD_REQUEST_NAME); + } + #endregion + + #region Methods + private bool IsNotEmptyAndNull(List requests) => requests.IsNotEmptyAndNull(); + + private bool NameIsNotWhiteSpace(List requests) => requests.Select(x => x.Name).AllNotWhiteSpaceAndNull(); + #endregion +} diff --git a/src/YANLib.Application/Validations/DeveloperValidation.cs b/src/YANLib.Application/Validations/DeveloperValidation.cs new file mode 100644 index 00000000..af3c3c9d --- /dev/null +++ b/src/YANLib.Application/Validations/DeveloperValidation.cs @@ -0,0 +1,41 @@ +using FluentValidation; +using System.Collections.Generic; +using System.Linq; +using YANLib.Requests; +using static YANLib.YANLibDomainErrorCodes; + +namespace YANLib.Validations; + +public sealed class DeveloperValidator : AbstractValidator +{ + public DeveloperValidator() + { + _ = RuleFor(x => x.Name).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_NAME); + _ = RuleFor(x => x.IdCard).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_ID_CARD); + _ = RuleFor(x => x.DeveloperTypeCode).NotNull().NotEmpty().GreaterThanOrEqualTo(0).WithErrorCode(BAD_REQUEST_CODE); + } +} + +public sealed class DeveloperValidators : AbstractValidator> +{ + #region Constructors + public DeveloperValidators() + { + _ = RuleFor(x => x).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST); + + _ = RuleForEach(s => s).SetValidator(new DeveloperValidator()); + + _ = RuleFor(x => x).Must(IsNotEmptyAndNull).WithErrorCode(BAD_REQUEST); + _ = RuleFor(x => x).Must(NameIsNotWhiteSpace).WithErrorCode(BAD_REQUEST_NAME); + _ = RuleFor(x => x).Must(IdCardIsNotWhiteSpace).WithErrorCode(BAD_REQUEST_ID_CARD); + } + #endregion + + #region Methods + private bool IsNotEmptyAndNull(List requests) => requests.IsNotEmptyAndNull(); + + private bool NameIsNotWhiteSpace(List requests) => requests.Select(x => x.Name).AllNotWhiteSpaceAndNull(); + + private bool IdCardIsNotWhiteSpace(List requests) => requests.Select(x => x.IdCard).AllNotWhiteSpaceAndNull(); + #endregion +} \ No newline at end of file diff --git a/src/YANLib.Application/Validations/JsonValidation.cs b/src/YANLib.Application/Validations/JsonValidation.cs deleted file mode 100644 index e6d00295..00000000 --- a/src/YANLib.Application/Validations/JsonValidation.cs +++ /dev/null @@ -1,21 +0,0 @@ -using FluentValidation; -using System.Collections.Generic; -using YANLib.Dtos; -using YANLib.Exceptions; -using static YANLib.Exceptions.ExceptionMessage; - -namespace YANLib.Validations; - -public sealed class JsonValidator : AbstractValidator -{ - public JsonValidator() => RuleFor(d => d.Id).NotNull().NotEmpty().WithErrorCode(ExceptionCode.BAD_REQUEST_ID).WithMessage(BAD_REQUEST_ID); -} - -public sealed class JsonValidators : AbstractValidator> -{ - public JsonValidators() - { - _ = RuleFor(s => s).NotNull().NotEmpty().WithErrorCode(ExceptionCode.BAD_REQUEST_ID).WithMessage(BAD_REQUEST_ID); - _ = RuleForEach(s => s).SetValidator(new JsonValidator()); - } -} diff --git a/src/YANLib.Application/Validations/SampleValidation.cs b/src/YANLib.Application/Validations/SampleValidation.cs new file mode 100644 index 00000000..3c0bfb96 --- /dev/null +++ b/src/YANLib.Application/Validations/SampleValidation.cs @@ -0,0 +1,29 @@ +using FluentValidation; +using System.Collections.Generic; +using YANLib.Requests; +using static YANLib.YANLibDomainErrorCodes; + +namespace YANLib.Validations; + +public sealed class SampleValidator : AbstractValidator +{ + public SampleValidator() => RuleFor(x => x.Id).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_ID); +} + +public sealed class SampleValidators : AbstractValidator> +{ + #region Constructors + public SampleValidators() + { + _ = RuleFor(x => x).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST); + + _ = RuleForEach(s => s).SetValidator(new SampleValidator()); + + _ = RuleFor(x => x).Must(IsNotEmptyAndNull).WithErrorCode(BAD_REQUEST); + } + #endregion + + #region Methods + private bool IsNotEmptyAndNull(List requests) => requests.IsNotEmptyAndNull(); + #endregion +} diff --git a/src/YANLib.Application/YANLib.Application.csproj b/src/YANLib.Application/YANLib.Application.csproj index 13493b3e..20bd3871 100644 --- a/src/YANLib.Application/YANLib.Application.csproj +++ b/src/YANLib.Application/YANLib.Application.csproj @@ -1,25 +1,27 @@ - + - - net6.0 - YANLib - + + net6.0 + YANLib + - - - - - - + + + + + + - - - - - - - + + + + + + + + + diff --git a/src/YANLib.Application/YANLibApplicationModule.cs b/src/YANLib.Application/YANLibApplicationModule.cs index c95af2ca..07ee0d50 100644 --- a/src/YANLib.Application/YANLibApplicationModule.cs +++ b/src/YANLib.Application/YANLibApplicationModule.cs @@ -2,12 +2,14 @@ using Volo.Abp.AutoMapper; using Volo.Abp.FluentValidation; using Volo.Abp.Modularity; +using YANLib.Application.Redis; namespace YANLib; [DependsOn( typeof(YANLibDomainModule), typeof(YANLibApplicationContractsModule), + typeof(YANLibApplicationRedisModule), typeof(AbpDddApplicationModule), typeof(AbpAutoMapperModule), typeof(AbpFluentValidationModule) diff --git a/src/YANLib.Domain.Shared/YANLib.Domain.Shared.csproj b/src/YANLib.Domain.Shared/YANLib.Domain.Shared.csproj index a7b624f5..77b9117c 100644 --- a/src/YANLib.Domain.Shared/YANLib.Domain.Shared.csproj +++ b/src/YANLib.Domain.Shared/YANLib.Domain.Shared.csproj @@ -1,20 +1,20 @@ - + - - net6.0 - YANLib - true - + + net6.0 + YANLib + true + - - - - + + + + - - - + + + diff --git a/src/YANLib.Domain.Shared/YANLibDomainErrorCodes.cs b/src/YANLib.Domain.Shared/YANLibDomainErrorCodes.cs index b07e79d0..b0ef4e4d 100644 --- a/src/YANLib.Domain.Shared/YANLibDomainErrorCodes.cs +++ b/src/YANLib.Domain.Shared/YANLibDomainErrorCodes.cs @@ -2,5 +2,20 @@ public static class YANLibDomainErrorCodes { - /* You can add your business exception error codes here, as constants */ + public const string BAD_REQUEST = "YANLib:400"; + public const string BAD_REQUEST_NAME = "YANLib:410"; + public const string BAD_REQUEST_ID_CARD = "YANLib:420"; + public const string BAD_REQUEST_CODE = "YANLib:430"; + public const string BAD_REQUEST_GPA = "YANLib:440"; + public const string BAD_REQUEST_ID = "YANLib:450"; + public const string BAD_REQUEST_DEV_ID = "YANLib:460"; + + public const string BUSINESS_ERROR = "YANLib:413"; + public const string EXIST_CODE = "YANLib:413"; + + public const string NOT_FOUND = "YANLib:404"; + public const string NOT_FOUND_CERT = "YANLib:414"; + public const string NOT_FOUND_DEV_TYPE = "YANLib:424"; + + public const string INTERNAL_SERVER_ERROR = "YANLib:500"; } diff --git a/src/YANLib.Domain/Models/Certificate.cs b/src/YANLib.Domain/Models/Certificate.cs new file mode 100644 index 00000000..b86dfa99 --- /dev/null +++ b/src/YANLib.Domain/Models/Certificate.cs @@ -0,0 +1,17 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace YANLib.Models; + +[Table("Certificates")] +public sealed class Certificate +{ + [Key] + public Guid Id { get; set; } + public string Name { get; set; } + public float? GPA { get; set; } + public Guid DeveloperId { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime? ModifiedDate { get; set; } +} diff --git a/src/YANLib.Domain/Models/Developer.cs b/src/YANLib.Domain/Models/Developer.cs new file mode 100644 index 00000000..fedd2a6d --- /dev/null +++ b/src/YANLib.Domain/Models/Developer.cs @@ -0,0 +1,22 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace YANLib.Models; + +[Table("Developers")] +public sealed class Developer +{ + [Key] + public Guid Id { get; set; } + public string Name { get; set; } + public string IdCard { get; set; } + public int DeveloperTypeCode { get; set; } + public bool IsActive { get; set; } + public int Version { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime? ModifiedDate { get; set; } + + [ForeignKey("DeveloperTypeCode")] + public DeveloperType DeveloperType { get; set; } +} diff --git a/src/YANLib.Domain/Models/DeveloperType.cs b/src/YANLib.Domain/Models/DeveloperType.cs new file mode 100644 index 00000000..92f2d1eb --- /dev/null +++ b/src/YANLib.Domain/Models/DeveloperType.cs @@ -0,0 +1,16 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace YANLib.Models; + +[Table("DeveloperTypes")] +public sealed class DeveloperType +{ + [Key] + public int Code { get; set; } + public string Name { get; set; } + public bool IsActive { get; set; } + public DateTime CreatedDate { get; set; } + public DateTime? ModifiedDate { get; set; } +} diff --git a/src/YANLib.Domain/Repositories/ICertificateRepository.cs b/src/YANLib.Domain/Repositories/ICertificateRepository.cs new file mode 100644 index 00000000..4e6f7b86 --- /dev/null +++ b/src/YANLib.Domain/Repositories/ICertificateRepository.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using YANLib.Models; + +namespace YANLib.Repositories; + +public interface ICertificateRepository : ITransientDependency +{ + public ValueTask Get(Guid id); + public ValueTask Insert(Certificate entity); + public ValueTask Update(Certificate entity); + public ValueTask> GetByDeveloperId(Guid developerId); +} diff --git a/src/YANLib.Domain/Repositories/IDeveloperRepository.cs b/src/YANLib.Domain/Repositories/IDeveloperRepository.cs new file mode 100644 index 00000000..fa6762df --- /dev/null +++ b/src/YANLib.Domain/Repositories/IDeveloperRepository.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using YANLib.Models; + +namespace YANLib.Repositories; + +public interface IDeveloperRepository : ITransientDependency +{ + public ValueTask> GetAll(); + public ValueTask Insert(Developer entity); + public ValueTask Update(Developer entity); +} diff --git a/src/YANLib.Domain/Repositories/IDeveloperTypeRepository.cs b/src/YANLib.Domain/Repositories/IDeveloperTypeRepository.cs new file mode 100644 index 00000000..6e473f13 --- /dev/null +++ b/src/YANLib.Domain/Repositories/IDeveloperTypeRepository.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using YANLib.Models; + +namespace YANLib.Repositories; + +public interface IDeveloperTypeRepository : ITransientDependency +{ + public ValueTask> GetAll(); + public ValueTask Get(int code); + public ValueTask Insert(DeveloperType entity); + public ValueTask Update(DeveloperType entity); +} diff --git a/src/YANLib.Domain/YANLib.Domain.csproj b/src/YANLib.Domain/YANLib.Domain.csproj index 8871e478..9529bceb 100644 --- a/src/YANLib.Domain/YANLib.Domain.csproj +++ b/src/YANLib.Domain/YANLib.Domain.csproj @@ -1,18 +1,18 @@ - + - - net6.0 - YANLib - + + net6.0 + YANLib + - - - + + + - - - + + + diff --git a/src/YANLib.Domain/YANLibConsts.cs b/src/YANLib.Domain/YANLibConsts.cs index 45546db0..5fe6896e 100644 --- a/src/YANLib.Domain/YANLibConsts.cs +++ b/src/YANLib.Domain/YANLibConsts.cs @@ -3,6 +3,11 @@ public static class YANLibConsts { public const string DbTablePrefix = "App"; + public const string DbSchema = "sample"; - public const string DbSchema = null; + public const string ConnectionStringName = "Default"; + + public const string IdxSample = "Elasticsearch:Indices:Sample"; + + public const string RedisKeyCommand = "KEYS"; } diff --git a/src/YANLib.EntityFrameworkCore/EntityFrameworkCore/DbContext/IYANLibDbContext.cs b/src/YANLib.EntityFrameworkCore/EntityFrameworkCore/DbContext/IYANLibDbContext.cs index c33ed85d..0bbb1e5c 100644 --- a/src/YANLib.EntityFrameworkCore/EntityFrameworkCore/DbContext/IYANLibDbContext.cs +++ b/src/YANLib.EntityFrameworkCore/EntityFrameworkCore/DbContext/IYANLibDbContext.cs @@ -1,9 +1,15 @@ -using Volo.Abp.Data; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; +using YANLib.Models; +using static YANLib.YANLibConsts; namespace YANLib.EntityFrameworkCore.DbContext; -[ConnectionStringName("Default")] +[ConnectionStringName(ConnectionStringName)] public interface IYANLibDbContext : IEfCoreDbContext { + public DbSet Developers { get; } + public DbSet DeveloperTypes { get; } + public DbSet Certificates { get; } } diff --git a/src/YANLib.EntityFrameworkCore/EntityFrameworkCore/DbContext/Implements/YANLibDbContext.cs b/src/YANLib.EntityFrameworkCore/EntityFrameworkCore/DbContext/Implements/YANLibDbContext.cs index e0f43c53..516fce0b 100644 --- a/src/YANLib.EntityFrameworkCore/EntityFrameworkCore/DbContext/Implements/YANLibDbContext.cs +++ b/src/YANLib.EntityFrameworkCore/EntityFrameworkCore/DbContext/Implements/YANLibDbContext.cs @@ -1,23 +1,22 @@ using Microsoft.EntityFrameworkCore; -using Volo.Abp.Data; using Volo.Abp.EntityFrameworkCore; +using YANLib.Models; +using static YANLib.YANLibConsts; namespace YANLib.EntityFrameworkCore.DbContext.Implements; -[ConnectionStringName("Default")] public class YANLibDbContext : AbpDbContext, IYANLibDbContext { - /* Add DbSet for each Aggregate Root here. Example: - * public DbSet Questions { get; set; } - */ + public DbSet Developers { get; set; } + public DbSet DeveloperTypes { get; set; } + public DbSet Certificates { get; set; } - public YANLibDbContext(DbContextOptions options) : base(options) - { - } + public YANLibDbContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); + _ = builder.HasDefaultSchema(DbSchema); builder.ConfigureYANLib(); } } diff --git a/src/YANLib.EntityFrameworkCore/Repositories/CertificateRepository.cs b/src/YANLib.EntityFrameworkCore/Repositories/CertificateRepository.cs new file mode 100644 index 00000000..8c0eb307 --- /dev/null +++ b/src/YANLib.EntityFrameworkCore/Repositories/CertificateRepository.cs @@ -0,0 +1,94 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp; +using YANLib.EntityFrameworkCore.DbContext; +using YANLib.Models; +using static System.DateTime; +using static YANLib.YANLibDomainErrorCodes; + +namespace YANLib.Repositories; + +public sealed class CertificateRepository : ICertificateRepository +{ + #region Fields + private readonly ILogger _logger; + private readonly IYANLibDbContext _dbContext; + #endregion + + #region Constructors + public CertificateRepository(ILogger logger, IYANLibDbContext dbContext) + { + _logger = logger; + _dbContext = dbContext; + } + #endregion + + #region Implements + public async ValueTask Get(Guid id) + { + try + { + return await _dbContext.Certificates.AsNoTracking().FirstOrDefaultAsync(x => x.Id == id); + } + catch (Exception ex) + { + _logger.LogError(ex, "GetCertificateRepository-Exception: {Id}", id); + throw; + } + } + + public async ValueTask Insert(Certificate entity) + { + try + { + entity.CreatedDate = Now; + _ = await _dbContext.Certificates.AddAsync(entity); + + return await _dbContext.SaveChangesAsync() > 0 ? entity : throw new BusinessException(INTERNAL_SERVER_ERROR); + } + catch (Exception ex) + { + _logger.LogError(ex, "InsertCertificateRepository-Exception: {Entity}", entity.CamelSerialize()); + throw; + } + } + + public async ValueTask Update(Certificate entity) + { + try + { + var mdl = await Get(entity.Id) ?? throw new BusinessException(NOT_FOUND_CERT); + + mdl.Name = entity.Name; + mdl.GPA = entity.GPA; + mdl.DeveloperId = entity.DeveloperId; + mdl.ModifiedDate = Now; + _dbContext.Certificates.Update(mdl); + + return await _dbContext.SaveChangesAsync() > 0 ? mdl : throw new BusinessException(INTERNAL_SERVER_ERROR); + } + catch (Exception ex) + { + _logger.LogError(ex, "UpdateCertificateRepository-Exception: {Entity}", entity.CamelSerialize()); + throw; + } + } + + public async ValueTask> GetByDeveloperId(Guid developerId) + { + try + { + return await _dbContext.Certificates.AsNoTracking().Where(x => x.DeveloperId == developerId).ToArrayAsync(); + } + catch (Exception ex) + { + _logger.LogError(ex, "GetByDeveloperIdCertificateRepository-Exception: {DeveloperId}", developerId); + throw; + } + } + #endregion +} diff --git a/src/YANLib.EntityFrameworkCore/Repositories/DeveloperRepository.cs b/src/YANLib.EntityFrameworkCore/Repositories/DeveloperRepository.cs new file mode 100644 index 00000000..39ea052b --- /dev/null +++ b/src/YANLib.EntityFrameworkCore/Repositories/DeveloperRepository.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using YANLib.Models; + +namespace YANLib.Repositories; + +public sealed class DeveloperRepository : IDeveloperRepository +{ + public ValueTask> GetAll() => throw new NotImplementedException(); + public ValueTask Insert(Developer entity) => throw new NotImplementedException(); + public ValueTask Update(Developer entity) => throw new NotImplementedException(); +} diff --git a/src/YANLib.EntityFrameworkCore/Repositories/DeveloperTypeRepository.cs b/src/YANLib.EntityFrameworkCore/Repositories/DeveloperTypeRepository.cs new file mode 100644 index 00000000..56d42f0b --- /dev/null +++ b/src/YANLib.EntityFrameworkCore/Repositories/DeveloperTypeRepository.cs @@ -0,0 +1,99 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp; +using YANLib.EntityFrameworkCore.DbContext; +using YANLib.Models; +using static System.DateTime; +using static YANLib.YANLibDomainErrorCodes; + +namespace YANLib.Repositories; + +public sealed class DeveloperTypeRepository : IDeveloperTypeRepository +{ + #region Fields + private readonly ILogger _logger; + private readonly IYANLibDbContext _dbContext; + #endregion + + #region Constructors + public DeveloperTypeRepository(ILogger logger, IYANLibDbContext dbContext) + { + _logger = logger; + _dbContext = dbContext; + } + #endregion + + #region Implements + public async ValueTask> GetAll() + { + try + { + return await _dbContext.DeveloperTypes.AsNoTracking().ToArrayAsync(); + } + catch (Exception ex) + { + _logger.LogError(ex, "GetAllDeveloperTypeRepository-Exception"); + throw; + } + } + + public async ValueTask Get(int code) + { + try + { + return await _dbContext.DeveloperTypes.AsNoTracking().FirstOrDefaultAsync(x => x.Code == code); + } + catch (Exception ex) + { + _logger.LogError(ex, "GetDeveloperTypeRepository-Exception: {Code}", code); + throw; + } + } + + public async ValueTask Insert(DeveloperType entity) + { + try + { + var mdl = await _dbContext.DeveloperTypes.AsNoTracking().FirstOrDefaultAsync(x => x.Code == entity.Code); + + if (mdl is not null) + { + throw new BusinessException(EXIST_CODE); + } + + entity.CreatedDate = Now; + _ = await _dbContext.DeveloperTypes.AddAsync(entity); + + return await _dbContext.SaveChangesAsync() > 0 ? entity : throw new BusinessException(INTERNAL_SERVER_ERROR); + } + catch (Exception ex) + { + _logger.LogError(ex, "InsertDeveloperTypeRepository-Exception: {Entity}", entity.CamelSerialize()); + throw; + } + } + + public async ValueTask Update(DeveloperType entity) + { + try + { + var mdl = await Get(entity.Code) ?? throw new BusinessException(NOT_FOUND_CERT); + + mdl.Name = entity.Name; + mdl.IsActive = entity.IsActive; + mdl.ModifiedDate = Now; + _dbContext.DeveloperTypes.Update(mdl); + + return await _dbContext.SaveChangesAsync() > 0 ? mdl : throw new BusinessException(INTERNAL_SERVER_ERROR); + } + catch (Exception ex) + { + _logger.LogError(ex, "UpdateDeveloperTypeRepository-Exception: {Entity}", entity.CamelSerialize()); + throw; + } + } + #endregion +} diff --git a/src/YANLib.EntityFrameworkCore/YANLib.EntityFrameworkCore.csproj b/src/YANLib.EntityFrameworkCore/YANLib.EntityFrameworkCore.csproj index 6dde8824..2dec504e 100644 --- a/src/YANLib.EntityFrameworkCore/YANLib.EntityFrameworkCore.csproj +++ b/src/YANLib.EntityFrameworkCore/YANLib.EntityFrameworkCore.csproj @@ -1,15 +1,16 @@ - + - - net6.0 - YANLib - + + net6.0 + YANLib + - - - - + + + + + diff --git a/src/YANLib.HttpApi.Client/YANLib.HttpApi.Client.csproj b/src/YANLib.HttpApi.Client/YANLib.HttpApi.Client.csproj index 03997514..11a1dfc1 100644 --- a/src/YANLib.HttpApi.Client/YANLib.HttpApi.Client.csproj +++ b/src/YANLib.HttpApi.Client/YANLib.HttpApi.Client.csproj @@ -1,23 +1,23 @@ - + - - net6.0 - YANLib - + + net6.0 + YANLib + - - - + + + - - - + + + - - - - + + + + diff --git a/src/YANLib.HttpApi/Controllers/CertificateController.cs b/src/YANLib.HttpApi/Controllers/CertificateController.cs new file mode 100644 index 00000000..e8343e85 --- /dev/null +++ b/src/YANLib.HttpApi/Controllers/CertificateController.cs @@ -0,0 +1,68 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Swashbuckle.AspNetCore.Annotations; +using System; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Volo.Abp; +using YANLib.Requests; +using YANLib.Services; + +namespace YANLib.Controllers; + +[RemoteService] +[ApiExplorerSettings(GroupName = "main")] +[Route("api/yanlib/certificates")] +public sealed class CertificateController : YANLibController +{ + #region Fields + private readonly ILogger _logger; + private readonly ICertificateService _service; + #endregion + + #region Constructors + public CertificateController(ILogger logger, ICertificateService service) + { + _logger = logger; + _service = service; + } + #endregion + + #region Methods + [HttpGet("{id}")] + [SwaggerOperation(Summary = "Tìm Certificate theo Id")] + public async ValueTask Get([Required] Guid id) + { + _logger.LogInformation("GetCertificateController: {Id}", id); + + return Ok(await _service.Get(id)); + } + + [HttpPost] + [SwaggerOperation(Summary = "Thêm mới Certificate")] + public async ValueTask Insert([Required] CertificateRequest request) + { + _logger.LogInformation("InsertCertificateController: {Request}", request.CamelSerialize()); + + return Ok(await _service.Insert(request)); + } + + [HttpPut] + [SwaggerOperation(Summary = "Cập nhật Certificate")] + public async ValueTask Update([Required] CertificateFullRequest request) + { + _logger.LogInformation("UpdateCertificateController: {Request}", request.CamelSerialize()); + + return Ok(await _service.Update(request)); + } + + [HttpGet("get-by-developer-id")] + [SwaggerOperation(Summary = "Tìm tất cả Certificates theo Developer Id")] + public async ValueTask GetByDeveloperId([Required] Guid developerId) + { + _logger.LogInformation("GetByDeveloperIdCertificateController: {developerId}", developerId); + + return Ok(await _service.GetByDeveloperId(developerId)); + } + #endregion +} diff --git a/src/YANLib.HttpApi/Controllers/DeveloperTypeController.cs b/src/YANLib.HttpApi/Controllers/DeveloperTypeController.cs new file mode 100644 index 00000000..5745420c --- /dev/null +++ b/src/YANLib.HttpApi/Controllers/DeveloperTypeController.cs @@ -0,0 +1,66 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Swashbuckle.AspNetCore.Annotations; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Volo.Abp; +using YANLib.Requests; +using YANLib.Services; + +namespace YANLib.Controllers; + +[RemoteService] +[ApiExplorerSettings(GroupName = "main")] +[Route("api/yanlib/developer-types")] +public sealed class DeveloperTypeController : YANLibController +{ + #region Fields + private readonly ILogger _logger; + private readonly IDeveloperTypeService _service; + #endregion + + #region Constructors + public DeveloperTypeController(ILogger logger, IDeveloperTypeService service) + { + _logger = logger; + _service = service; + } + #endregion + + #region Methods + [HttpGet] + [SwaggerOperation(Summary = "Tìm tất cả Developer Types")] + public async ValueTask GetAll() => Ok(await _service.GetAll()); + + [HttpGet("{code}")] + [SwaggerOperation(Summary = "Tìm Developer Type theo Code")] + public async ValueTask Get([Required] int code) + { + _logger.LogInformation("GetDeveloperTypeController: {Code}", code); + + return Ok(await _service.Get(code)); + } + + [HttpPost] + [SwaggerOperation(Summary = "Thêm mới Developer Type")] + public async ValueTask Insert([Required] DeveloperTypeRequest request) + { + _logger.LogInformation("InsertDeveloperTypeController: {Request}", request.CamelSerialize()); + + return Ok(await _service.Insert(request)); + } + + [HttpPut] + [SwaggerOperation(Summary = "Cập nhật Developer Type")] + public async ValueTask Update([Required] DeveloperTypeRequest request) + { + _logger.LogInformation("UpdateDeveloperTypeController: {Request}", request.CamelSerialize()); + + return Ok(await _service.Update(request)); + } + + [SwaggerOperation(Summary = "Đồng bộ tất cả Developer Types từ Database sang Redis")] + [HttpPost("sync-db-to-redis")] + public async ValueTask SyncDbToRedis() => Ok(await _service.SyncDbToRedis()); + #endregion +} diff --git a/src/YANLib.HttpApi/Controllers/YANJsonController.cs b/src/YANLib.HttpApi/Controllers/YANJsonController.cs index b9c55ca8..2967a766 100644 --- a/src/YANLib.HttpApi/Controllers/YANJsonController.cs +++ b/src/YANLib.HttpApi/Controllers/YANJsonController.cs @@ -1,18 +1,16 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Swashbuckle.AspNetCore.Annotations; -using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Volo.Abp; -using YANLib.Dtos; using YANLib.Services; namespace YANLib.Controllers; [RemoteService] [ApiExplorerSettings(GroupName = "json")] -[Route("api/tynab/yanlib/yanjson")] +[Route("api/yanlib/yanjson")] public class YANJsonController : YANLibController { #region Fields @@ -30,43 +28,12 @@ public YANJsonController(ILogger logger, IYANJsonService serv #region Methods [HttpGet("yan-vs-standards")] - [SwaggerOperation(Summary = "Deserialize speed test (YAN vs Standards)")] + [SwaggerOperation(Summary = "Đo tốc độ của thư viện YANLib và các chuẩn khác")] public async ValueTask YanVsStandards([Required] uint quantity = 10000, [Required] bool hideSystem = true) { - _logger.LogInformation("YanVsStandardsYANJsonController: {Quantity}, {HideSystem}", quantity, hideSystem); + _logger.LogInformation("YanVsStandardsYANJsonController: {Quantity} - {HideSystem}", quantity, hideSystem); + return Ok(await _service.YanVsStandards(quantity, hideSystem)); } - - [HttpPost("serialize")] - [SwaggerOperation(Summary = "Serialize n-1 Pascal case")] - public IActionResult Serialize([Required] List request) => Ok(request.Serialize()); - - [HttpPost("camel-serialize")] - [SwaggerOperation(Summary = "Serialize n-1 Camel case")] - public IActionResult SerializeCamel([Required] List request) => Ok(request.CamelSerialize()); - - [HttpGet("standard-deserialize/{text}")] - [SwaggerOperation(Summary = "Deserialize 1-1 ignore case")] - public IActionResult DeserializeStandard([Required] string text = "{\"Id\":\"3fa85f64-5717-4562-b3fc-2c963f66afa6\"}") => Ok(text.StandardDeserialize()); - - [HttpGet("deserialize/{text}")] - [SwaggerOperation(Summary = "Deserialize 1-1 Pascal case")] - public IActionResult Deserializes([Required] string text = "{\"Id\":\"3fa85f64-5717-4562-b3fc-2c963f66afa6\"}") => Ok(text.Deserialize()); - - [HttpPost("serializes")] - [SwaggerOperation(Summary = "Serialize n-n Pascal case")] - public IActionResult Serializes([Required] List request) => Ok(request.Serializes()); - - [HttpPost("camel-serializes")] - [SwaggerOperation(Summary = "Serialize n-n Camel case")] - public IActionResult SerializeCamels([Required] List request) => Ok(request.CamelSerializes()); - - [HttpPost("deserializes")] - [SwaggerOperation(Summary = "Deserialize n-n Pascal case")] - public IActionResult Deserializes([Required] List text) => Ok(text.Deserializes()); - - [HttpPost("standard-deserializes")] - [SwaggerOperation(Summary = "Deserialize n-n ignore case")] - public IActionResult DeserializeStandards([Required] List text) => Ok(text.StandardDeserializes()); #endregion } diff --git a/src/YANLib.HttpApi/YANLib.HttpApi.csproj b/src/YANLib.HttpApi/YANLib.HttpApi.csproj index f2bf5472..715184d5 100644 --- a/src/YANLib.HttpApi/YANLib.HttpApi.csproj +++ b/src/YANLib.HttpApi/YANLib.HttpApi.csproj @@ -1,20 +1,20 @@ - + - - net6.0 - YANLib - + + net6.0 + YANLib + - - - - + + + + - - - - + + + + diff --git a/src/YANLib.MongoDB/YANLib.MongoDB.csproj b/src/YANLib.MongoDB/YANLib.MongoDB.csproj index ec1a4966..7c511b50 100644 --- a/src/YANLib.MongoDB/YANLib.MongoDB.csproj +++ b/src/YANLib.MongoDB/YANLib.MongoDB.csproj @@ -1,17 +1,17 @@ - - net6.0 - enable - enable - + + net6.0 + enable + enable + - - - + + + - - - + + +