Skip to content

Commit

Permalink
Merge pull request #85 from Tynab/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Tynab committed Feb 3, 2024
2 parents b8ec758 + 10aec6a commit ece22ca
Show file tree
Hide file tree
Showing 24 changed files with 299 additions and 14 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ var dto = json.Deserialize<JsonDto>();

### NOTE

- Elastic.Apm.NetCoreAll (v.1.24.x and above) is spam logs.
- DotNetCap.CAP (v.7.x.x and above) is MongoDB error.
- Elastic.Apm... (v.1.24.x and above) is spam logs.
- DotNetCap.CAP... (v.7.x.x and above) is MongoDB error.
- Do not [Remove Unused References...] in layers:
- Host:
- Microsoft.EntityFrameworkCore.Tools
Expand Down
4 changes: 3 additions & 1 deletion host/YANLib.HttpApi.Host/YANLibHttpApiHostModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
using Volo.Abp.Swashbuckle;
using YANLib.Core;
using YANLib.EntityFrameworkCore;
using YANLib.Middlewares;
using YANLib.Utilities;
using static Elastic.Apm.Agent;
using static HealthChecks.UI.Client.UIResponseWriter;
Expand Down Expand Up @@ -230,7 +229,10 @@ public override void OnApplicationInitialization(ApplicationInitializationContex
_ = app.UseAuthentication();
_ = app.UseAuthorization();
_ = app.UseSwagger();

#if RELEASE
_ = app.UseMiddleware<SwaggerBasicAuthMiddleware>();

Check failure on line 234 in host/YANLib.HttpApi.Host/YANLibHttpApiHostModule.cs

View workflow job for this annotation

GitHub Actions / publish

The type or namespace name 'SwaggerBasicAuthMiddleware' could not be found (are you missing a using directive or an assembly reference?)

Check failure on line 234 in host/YANLib.HttpApi.Host/YANLibHttpApiHostModule.cs

View workflow job for this annotation

GitHub Actions / publish

The type or namespace name 'SwaggerBasicAuthMiddleware' could not be found (are you missing a using directive or an assembly reference?)
#endif

_ = app.UseAbpSwaggerUI(c =>
{
Expand Down
4 changes: 2 additions & 2 deletions host/YANLib.HttpApi.Host/appsettings.Development.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@
"Password": "admin123"
},
"RemoteServices": {
"TestApi": {
"BaseUrl": "http://sample-api.local/"
"EcommerceApi": {
"BaseUrl": "https://ecommerce.yamiannephilim.com/api/"
}
},
"Serilog": {
Expand Down
4 changes: 2 additions & 2 deletions host/YANLib.HttpApi.Host/appsettings.Production.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@
"Password": "admin123"
},
"RemoteServices": {
"TestApi": {
"BaseUrl": "http://sample-api.local/"
"EcommerceApi": {
"BaseUrl": "https://ecommerce.yamiannephilim.com/api/"
}
},
"Serilog": {
Expand Down
11 changes: 11 additions & 0 deletions src/YANLib.Application.Contracts/RemoteService/IRemoteService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using RestSharp;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;

namespace YANLib.RemoteService;

public interface IRemoteService : IApplicationService
{
public ValueTask<T> InvokeApi<T>(string remoteRoot, string path, Method method, Dictionary<string, string> headers = null, string jsonInput = null, Dictionary<string, object> queryParams = null);
}
12 changes: 12 additions & 0 deletions src/YANLib.Application.Contracts/Requests/EcommerceLoginRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.ComponentModel;

namespace YANLib.Requests;

public sealed class EcommerceLoginRequest
{
[DefaultValue("nguyenvana@gmail.com")]
public required string Username { get; set; }

[DefaultValue("nguyenvana")]
public required string Password { get; set; }
}
12 changes: 12 additions & 0 deletions src/YANLib.Application.Contracts/Services/IEcommerceService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using YANLib.Requests;

namespace YANLib.Services;

public interface IEcommerceService : IApplicationService
{
public ValueTask<string> GetAccessToken(EcommerceLoginRequest request);

public ValueTask<string> GetRefreshToken(string accessToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<ItemGroup>
<PackageReference Include="NEST" Version="7.17.5" />
<PackageReference Include="RestSharp" Version="110.2.0" />
<PackageReference Include="Volo.Abp.Authorization" Version="7.4.5" />
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="7.4.5" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using Elastic.Apm.StackExchange.Redis;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
using Volo.Abp;
using YANLib.Application.Redis.ConnectionFactory;
Expand All @@ -23,6 +24,7 @@ public DeveloperTypeRedisService(ILogger<DeveloperTypeRedisService> logger, IRed
_logger = logger;
_connectionFactory = connectionFactory;
_connectionMultiplexer = _connectionFactory.Connection();
_connectionMultiplexer.UseElasticApm();
_database = _connectionMultiplexer.GetDatabase();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Elastic.Apm.StackExchange.Redis" Version="1.23.0" />
<PackageReference Include="StackExchange.Redis" Version="2.7.17" />
</ItemGroup>

Expand Down
94 changes: 94 additions & 0 deletions src/YANLib.Application/RemoteService/RemoteService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NUglify.Helpers;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Http;
using Volo.Abp.Http.Client;
using YANLib.Core;
using static Newtonsoft.Json.Linq.JObject;
using static RestSharp.ParameterType;
using static System.Net.HttpStatusCode;
using static YANLib.YANLibDomainErrorCodes;

namespace YANLib.RemoteService;

public class RemoteService(
ILogger<RemoteService> logger,
IOptionsSnapshot<AbpRemoteServiceOptions> remoteServiceOptions
) : YANLibAppService, IRemoteService
{
private readonly ILogger<RemoteService> _logger = logger;
private readonly AbpRemoteServiceOptions _remoteServiceOptions = remoteServiceOptions.Value;

public async ValueTask<T> InvokeApi<T>(string remoteRoot, string path, Method method, Dictionary<string, string> headers = null, string jsonInput = null, Dictionary<string, object> queryParams = null)
{
try
{
var req = new RestRequest(path, method);

if (headers.IsNotEmptyAndNull())
{
headers.ForEach(x => req.AddHeader(x.Key, x.Value));
}
else
{
_ = req.AddHeader("Accept", "*/*");
_ = req.AddHeader("Content-Type", "application/json");
}

if (jsonInput.IsNotWhiteSpaceAndNull())
{
_ = req.AddParameter("application/json", jsonInput, RequestBody);
}

if (queryParams.IsNotEmptyAndNull())
{
queryParams.ForEach(x => req.AddParameter(x.Key, x.Value, QueryString));
}

var res = await new RestClient(_remoteServiceOptions.RemoteServices.GetConfigurationOrDefaultOrNull(remoteRoot)?.BaseUrl)?.ExecuteAsync(req);

if (res.StatusCode is OK)
{
return res.Content.Deserialize<T>();
}
else
{
_logger.LogError("Invoke API: {PathRoot} - {Code} - {Error} - {Content}", $"{remoteRoot}{path}", res.StatusCode, res.ErrorMessage, res.Content);

if (res.Content.IsWhiteSpaceOrNull())
{
throw new AbpRemoteCallException(new RemoteServiceErrorInfo
{
Code = NOT_FOUND,
Message = res.ErrorException.Message
})
{
HttpStatusCode = res.StatusCode.ToInt()
};
}
else
{
var jtoken = Parse(res.Content)["error"]?.ToString();

throw new AbpRemoteCallException(jtoken?.Deserialize<RemoteServiceErrorInfo>() ?? new RemoteServiceErrorInfo
{
Message = jtoken
})
{
HttpStatusCode = res.StatusCode.ToInt()
};
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "InvokeApiRemoteService-Exception: {PathRoot} - {Method} - {JsonInput} - {QueryParams}", $"{remoteRoot}{path}", method.ToString(), jsonInput, queryParams.Serialize());

throw;
}
}
}
59 changes: 59 additions & 0 deletions src/YANLib.Application/Services/EcommerceService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using YANLib.Core;
using YANLib.RemoteService;
using YANLib.Requests;
using static RestSharp.Method;
using static YANLib.YANLibConsts.RemoteService;
using static YANLib.YANLibConsts.RemoteService.Path;

namespace YANLib.Services;

public class EcommerceService(
ILogger<EcommerceService> logger,
IRemoteService remoteService
) : YANLibAppService, IEcommerceService
{
private readonly ILogger<EcommerceService> _logger = logger;
private readonly IRemoteService _remoteService = remoteService;

public async ValueTask<string> GetAccessToken(EcommerceLoginRequest request)
{
var json = request.Serialize();

try
{
var hdrs = new Dictionary<string, string>
{
{ "Accept", "*/*" },
{ "Content-Type", "application/x-www-form-urlencoded" }
};
return await _remoteService.InvokeApi<string>(EcommerceApi, Login, Post, jsonInput: json);
}
catch (Exception ex)
{
_logger.LogError(ex, "GetAccessTokenEcommerceService-Exception: {Request}", json);

throw;
}
}

public async ValueTask<string> GetRefreshToken(string accessToken)
{
try
{
return await _remoteService.InvokeApi<string>(EcommerceApi, Refresh, Get, new Dictionary<string, string>
{
{ "Authorization", $"Bearer {accessToken}" }
});
}
catch (Exception ex)
{
_logger.LogError(ex, "GetRefreshTokenEcommerceService-Exception: {AccessToken}", accessToken);

throw;
}
}
}
35 changes: 35 additions & 0 deletions src/YANLib.Application/Validations/EcommerceValidation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using FluentValidation;
using System.Collections.Generic;
using System.Linq;
using YANLib.Core;
using YANLib.Requests;
using static YANLib.YANLibDomainErrorCodes;

namespace YANLib.Validations;

public sealed class EcommerceValidator : AbstractValidator<EcommerceLoginRequest>
{
public EcommerceValidator()
{
_ = RuleFor(x => x.Username).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_USER_NAME).WithMessage(YANLibDomainErrorMessages.BAD_REQUEST_USER_NAME);
_ = RuleFor(x => x.Password).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST_PWD).WithMessage(YANLibDomainErrorMessages.BAD_REQUEST_PWD);
}
}

public sealed class EcommerceValidators : AbstractValidator<List<EcommerceLoginRequest>>
{
public EcommerceValidators()
{
_ = RuleFor(x => x).NotNull().NotEmpty().WithErrorCode(BAD_REQUEST).WithMessage(YANLibDomainErrorMessages.BAD_REQUEST);
_ = RuleForEach(s => s).SetValidator(new EcommerceValidator());
_ = RuleFor(x => x).Must(IsNotEmptyAndNull).WithErrorCode(BAD_REQUEST).WithMessage(YANLibDomainErrorMessages.BAD_REQUEST);
_ = RuleFor(x => x).Must(UsernameIsNotWhiteSpace).WithErrorCode(BAD_REQUEST_USER_NAME).WithMessage(YANLibDomainErrorMessages.BAD_REQUEST_USER_NAME);
_ = RuleFor(x => x).Must(PasswordIsNotWhiteSpace).WithErrorCode(BAD_REQUEST_PWD).WithMessage(YANLibDomainErrorMessages.BAD_REQUEST_PWD);
}

private bool IsNotEmptyAndNull(List<EcommerceLoginRequest> requests) => requests.IsNotEmptyAndNull();

private bool UsernameIsNotWhiteSpace(List<EcommerceLoginRequest> requests) => requests.Select(x => x.Username).AllNotWhiteSpaceAndNull();

private bool PasswordIsNotWhiteSpace(List<EcommerceLoginRequest> requests) => requests.Select(x => x.Password).AllNotWhiteSpaceAndNull();
}
1 change: 1 addition & 0 deletions src/YANLib.Application/YANLib.Application.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<PackageReference Include="Volo.Abp.AutoMapper" Version="7.4.5" />
<PackageReference Include="Volo.Abp.Ddd.Application" Version="7.4.5" />
<PackageReference Include="Volo.Abp.FluentValidation" Version="7.4.5" />
<PackageReference Include="Volo.Abp.Http.Client" Version="7.4.5" />
</ItemGroup>

</Project>
2 changes: 2 additions & 0 deletions src/YANLib.Domain.Shared/Localization/YANLib/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"YANLib:430": "Mã truyền vào không hợp lệ!",
"YANLib:440": "Điểm truyền vào không hợp lệ!",
"YANLib:450": "Mã hồ sơ lập trình viên truyền vào không hợp lệ!",
"YANLib:460": "Tên người dùng truyền vào không hợp lệ!",
"YANLib:470": "Mật khẩu truyền vào không hợp lệ!",
"YANLib:403": "Lỗi quy tắc!",
"YANLib:413": "Mã {Id} đã tồn tại!",
"YANLib:423": "Mã định danh {IdCard} đã tồn tại!",
Expand Down
2 changes: 2 additions & 0 deletions src/YANLib.Domain.Shared/YANLibDomainErrorCodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public static class YANLibDomainErrorCodes
public const string BAD_REQUEST_ID = "YANLib:430";
public const string BAD_REQUEST_GPA = "YANLib:440";
public const string BAD_REQUEST_DEV_ID = "YANLib:450";
public const string BAD_REQUEST_USER_NAME = "YANLib:460";
public const string BAD_REQUEST_PWD = "YANLib:470";

public const string BUSINESS_ERROR = "YANLib:403";
public const string EXIST_ID = "YANLib:413";
Expand Down
2 changes: 2 additions & 0 deletions src/YANLib.Domain.Shared/YANLibDomainErrorMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ public static class YANLibDomainErrorMessages
public const string BAD_REQUEST_ID = "Mã truyền vào không hợp lệ!";
public const string BAD_REQUEST_GPA = "Điểm truyền vào không hợp lệ!";
public const string BAD_REQUEST_DEV_ID = "Mã hồ sơ lập trình viên truyền vào không hợp lệ!";
public const string BAD_REQUEST_USER_NAME = "Tên người dùng truyền vào không hợp lệ!";
public const string BAD_REQUEST_PWD = "Mật khẩu truyền vào không hợp lệ!";

public const string BUSINESS_ERROR = "Lỗi quy tắc!";
public const string EXIST_ID = "Mã đã tồn tại!";
Expand Down
11 changes: 11 additions & 0 deletions src/YANLib.Domain/YANLibConsts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,15 @@ public readonly struct RedisConstant

public static readonly string DeveloperTypeGroup = $"{YanlibPrefix}:{SamplePrefix}:{DeveloperTypePrefix}";
}

public readonly struct RemoteService
{
public const string EcommerceApi = "EcommerceApi";

public readonly struct Path
{
public const string Login = "login";
public const string Refresh = "refresh";
}
}
}
2 changes: 1 addition & 1 deletion src/YANLib.HttpApi/Controllers/DeveloperController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace YANLib.Controllers;

[RemoteService]
[ApiExplorerSettings(GroupName = "sample")]
[Route("api/yanlib/developers")]
[Route("api/developers")]
public sealed class DeveloperController(ILogger<DeveloperController> logger, IDeveloperService service) : YANLibController
{
private readonly ILogger<DeveloperController> _logger = logger;
Expand Down
4 changes: 2 additions & 2 deletions src/YANLib.HttpApi/Controllers/DeveloperTypeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace YANLib.Controllers;

[RemoteService]
[ApiExplorerSettings(GroupName = "sample")]
[Route("api/yanlib/developer-types")]
[Route("api/developer-types")]
public sealed class DeveloperTypeController(ILogger<DeveloperTypeController> logger, IDeveloperTypeService service) : YANLibController
{
private readonly ILogger<DeveloperTypeController> _logger = logger;
Expand Down Expand Up @@ -49,7 +49,7 @@ public async ValueTask<IActionResult> Update(int code, [Required] DeveloperTypeU
return Ok(await _service.Update(code, request));
}

[SwaggerOperation(Summary = "Đồng bộ tất cả định nghĩa Developer Types từ Database sang Redis")]
[HttpPost("sync-db-to-redis")]
[SwaggerOperation(Summary = "Đồng bộ tất cả định nghĩa Developer Types từ Database sang Redis")]
public async ValueTask<IActionResult> SyncDbToRedis() => Ok(await _service.SyncDbToRedis());
}
Loading

0 comments on commit ece22ca

Please sign in to comment.