feat : add sms service , run test one

complete test base , authorize tested , add sms service
release
Amir Hossein Khademi 2024-01-02 19:08:39 +03:30
parent 5c5cbc99e6
commit f4fa5e5e1b
20 changed files with 222 additions and 16 deletions

View File

@ -1,5 +1,6 @@
namespace NetinaShop.Api.Controller;
public class AuthController : ICarterModule
{

View File

@ -53,7 +53,7 @@ public class BlogController : ICarterModule
}
repositoryWrapper.SetRepository<Blog>().Add(ent);
await repositoryWrapper.SaveChangesAsync(cancellationToken);
return TypedResults.Ok();
return TypedResults.Ok(ent.AdaptToSDto());
}
// PUT:Update Entity

View File

@ -0,0 +1,28 @@
@NetinaShopApi_HostAddress = http://localhost:32770
@BaseApiAddress = {{NetinaShopApi_HostAddress}}/api
@page = 0
@deleteId = 7fe89459-6405-48c3-b1dc-eab67b3d0a90
GET {{BaseApiAddress}}/blog?page={{page}}
Authorization:Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJKd3RJRCI6IjgwNmM0NmYyIiwidW5pcXVlX25hbWUiOiJuZXRpbmFzaG9wIiwiU2lnblVwU3RhdHVzIjoiMCIsIm5hbWVpZCI6ImJjNTIxNzVlLTY0MzYtNGRjMC05OGY0LTE2ZDM5ZGZhZTIyZiIsImVtYWlsIjoiaW5mb0BuZXRpbmFzaG9wLmlvIiwiZ2VuZGVyIjoiRmVtYWxlIiwibmJmIjoxNzA0MTk5NjE1LCJleHAiOjE3MDU0OTU2MTUsImlhdCI6MTcwNDE5OTYxNSwiaXNzIjoiQnJpemNvIiwiYXVkIjoiQnJpemNvIn0.e1RdLu9x6aGYdgmLYthgSFq0CVlw7T09d1flanOO6FlFcfQu7FGpq9jgSjwje9VIf14nVQ3imCepGF4NvJoEsw
###
POST {{BaseApiAddress}}/blog
Content-Type:application/json
Authorization:Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJKd3RJRCI6IjgwNmM0NmYyIiwidW5pcXVlX25hbWUiOiJuZXRpbmFzaG9wIiwiU2lnblVwU3RhdHVzIjoiMCIsIm5hbWVpZCI6ImJjNTIxNzVlLTY0MzYtNGRjMC05OGY0LTE2ZDM5ZGZhZTIyZiIsImVtYWlsIjoiaW5mb0BuZXRpbmFzaG9wLmlvIiwiZ2VuZGVyIjoiRmVtYWxlIiwibmJmIjoxNzA0MTk5NjE1LCJleHAiOjE3MDU0OTU2MTUsImlhdCI6MTcwNDE5OTYxNSwiaXNzIjoiQnJpemNvIiwiYXVkIjoiQnJpemNvIn0.e1RdLu9x6aGYdgmLYthgSFq0CVlw7T09d1flanOO6FlFcfQu7FGpq9jgSjwje9VIf14nVQ3imCepGF4NvJoEsw
{
"title": "string",
"content": "string",
"tags": "string",
"readingTime": 0,
"summery": "string",
"isSuggested": true,
"categoryId": "9dcc16a9-914c-4f97-aa56-fe7257418e41",
"categoryName": "string"
}
###
DELETE {{BaseApiAddress}}/blog/{{deleteId}}
Authorization:Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJKd3RJRCI6IjgwNmM0NmYyIiwidW5pcXVlX25hbWUiOiJuZXRpbmFzaG9wIiwiU2lnblVwU3RhdHVzIjoiMCIsIm5hbWVpZCI6ImJjNTIxNzVlLTY0MzYtNGRjMC05OGY0LTE2ZDM5ZGZhZTIyZiIsImVtYWlsIjoiaW5mb0BuZXRpbmFzaG9wLmlvIiwiZ2VuZGVyIjoiRmVtYWxlIiwibmJmIjoxNzA0MTk5NjE1LCJleHAiOjE3MDU0OTU2MTUsImlhdCI6MTcwNDE5OTYxNSwiaXNzIjoiQnJpemNvIiwiYXVkIjoiQnJpemNvIn0.e1RdLu9x6aGYdgmLYthgSFq0CVlw7T09d1flanOO6FlFcfQu7FGpq9jgSjwje9VIf14nVQ3imCepGF4NvJoEsw

View File

@ -0,0 +1,16 @@
@NetinaShopApi_HostAddress = http://localhost:32770
@BaseApiAddress = {{NetinaShopApi_HostAddress}}/api
@page = 0
GET {{BaseApiAddress}}/blog/category?page={{page}}
Authorization:Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJKd3RJRCI6IjgwNmM0NmYyIiwidW5pcXVlX25hbWUiOiJuZXRpbmFzaG9wIiwiU2lnblVwU3RhdHVzIjoiMCIsIm5hbWVpZCI6ImJjNTIxNzVlLTY0MzYtNGRjMC05OGY0LTE2ZDM5ZGZhZTIyZiIsImVtYWlsIjoiaW5mb0BuZXRpbmFzaG9wLmlvIiwiZ2VuZGVyIjoiRmVtYWxlIiwibmJmIjoxNzA0MTk5NjE1LCJleHAiOjE3MDU0OTU2MTUsImlhdCI6MTcwNDE5OTYxNSwiaXNzIjoiQnJpemNvIiwiYXVkIjoiQnJpemNvIn0.e1RdLu9x6aGYdgmLYthgSFq0CVlw7T09d1flanOO6FlFcfQu7FGpq9jgSjwje9VIf14nVQ3imCepGF4NvJoEsw
###
POST {{BaseApiAddress}}/blog/category
Authorization:Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJKd3RJRCI6IjgwNmM0NmYyIiwidW5pcXVlX25hbWUiOiJuZXRpbmFzaG9wIiwiU2lnblVwU3RhdHVzIjoiMCIsIm5hbWVpZCI6ImJjNTIxNzVlLTY0MzYtNGRjMC05OGY0LTE2ZDM5ZGZhZTIyZiIsImVtYWlsIjoiaW5mb0BuZXRpbmFzaG9wLmlvIiwiZ2VuZGVyIjoiRmVtYWxlIiwibmJmIjoxNzA0MTk5NjE1LCJleHAiOjE3MDU0OTU2MTUsImlhdCI6MTcwNDE5OTYxNSwiaXNzIjoiQnJpemNvIiwiYXVkIjoiQnJpemNvIn0.e1RdLu9x6aGYdgmLYthgSFq0CVlw7T09d1flanOO6FlFcfQu7FGpq9jgSjwje9VIf14nVQ3imCepGF4NvJoEsw
Content-Type:application/json
{
"name": "بی نام",
"description": "دسته بندی عمومی"
}

View File

@ -0,0 +1,12 @@
@NetinaShopApi_HostAddress = http://localhost:32770
@BaseApiAddress = {{NetinaShopApi_HostAddress}}/api
POST {{BaseApiAddress}}/auth/login/password
Content-Type:application/json
{
"UserName":"netinashop",
"Password":"eF79o4P4BopCUbUK"
}

View File

@ -1,2 +0,0 @@
@NetinaShop.Api_HostAddress = http://localhost:5173

View File

@ -0,0 +1,18 @@
using NetinaShop.Repository.Abstracts;
namespace NetinaShop.Api.Services;
public class CurrentUserService : ICurrentUserService
{
private readonly IHttpContextAccessor _httpContextAccessor;
public CurrentUserService(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string? UserId => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier);
public string? RoleName => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Role);
public string? UserName => _httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name);
public List<string>? Permissions => _httpContextAccessor.HttpContext?.User?.FindAll("Permission")?.Select(c => c.Value)?.ToList();
}

View File

@ -193,13 +193,17 @@ public class ApplySummariesOperationFilter : IOperationFilter
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var controllerActionDescriptor = context.ApiDescription.ActionDescriptor as ControllerActionDescriptor;
if (controllerActionDescriptor == null) return;
if (controllerActionDescriptor == null)
{
operation.Summary = context.ApiDescription.ActionDescriptor.DisplayName;
return;
}
var pluralizer = new Pluralizer();
var actionName = controllerActionDescriptor.ActionName;
var singularizeName = pluralizer.Singularize(controllerActionDescriptor.ControllerName);
var pluralizeName = pluralizer.Pluralize(singularizeName);
var pluralizeName = pluralizer.Pluralize(controllerActionDescriptor.DisplayName);
var parameterCount = operation.Parameters.Where(p => p.Name != "version" && p.Name != "api-version").Count();

View File

@ -2,13 +2,13 @@
public class BlogLDto : BaseDto<BlogLDto , Blog>
{
public string Title { get; internal set; } = string.Empty;
public string Content { get; internal set; } = string.Empty;
public string Tags { get; internal set; } = string.Empty;
public int ReadingTime { get; internal set; }
public string Summery { get; internal set; } = string.Empty;
public bool IsSuggested { get; internal set; }
public Guid CategoryId { get; internal set; }
public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public string Tags { get; set; } = string.Empty;
public int ReadingTime { get; set; }
public string Summery { get; set; } = string.Empty;
public bool IsSuggested { get; set; }
public Guid CategoryId { get; set; }
public string CategoryName { get; set; } = string.Empty;
public List<StorageFileSDto> Files { get; internal set; } = new();
}

View File

@ -2,6 +2,6 @@
public class BlogCategorySDto : BaseDto<BlogCategorySDto , BlogCategory>
{
public string Name { get; internal set; } = string.Empty;
public string Description { get; internal set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}

View File

@ -0,0 +1,6 @@
namespace NetinaShop.Infrastructure.Models;
public static class RestAddress
{
public static string BaseKaveNegar { get => "https://api.kavenegar.com/v1/"; }
}

View File

@ -0,0 +1,7 @@
namespace NetinaShop.Infrastructure.Models.RestApi.KaveNegar;
public class KaveNegarResponse
{
public KaveNegarReturn Return { get; set; }
public KaveNegarResponseEntry[] entries { get; set; }
}

View File

@ -0,0 +1,13 @@
namespace NetinaShop.Infrastructure.Models.RestApi.KaveNegar;
public class KaveNegarResponseEntry
{
public int messageid { get; set; }
public string message { get; set; }
public int status { get; set; }
public string statustext { get; set; }
public string sender { get; set; }
public string receptor { get; set; }
public int date { get; set; }
public int cost { get; set; }
}

View File

@ -0,0 +1,7 @@
namespace NetinaShop.Infrastructure.Models.RestApi.KaveNegar;
public class KaveNegarReturn
{
public int status { get; set; }
public string message { get; set; }
}

View File

@ -19,6 +19,22 @@
<ItemGroup>
<Folder Include="Models\" />
<Folder Include="Services\" />
</ItemGroup>
<ItemGroup>
<Using Include="Microsoft.Extensions.Hosting" />
<Using Include="Microsoft.Extensions.Logging" />
<Using Include="Microsoft.Extensions.Options" />
<Using Include="NetinaShop.Common.Models" />
<Using Include="NetinaShop.Common.Models.Api" />
<Using Include="NetinaShop.Common.Models.Exception" />
<Using Include="NetinaShop.Core.Abstracts" />
<Using Include="NetinaShop.Domain.Models.Settings" />
<Using Include="NetinaShop.Infrastructure.Models.RestApi.KaveNegar" />
<Using Include="NetinaShop.Infrastructure.RestServices" />
<Using Include="Refit" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,10 @@
namespace NetinaShop.Infrastructure.RestServices;
public interface IKaveNegarRestApi
{
[Post("/{apiKey}/verify/lookup.json")]
Task<KaveNegarResponse> SendLookUp(string apiKey, [Query] string receptor, [Query] string token, [Query] string token2, [Query] string token10, [Query] string token20, [Query] string template);
[Post("/{apiKey}/sms/send.json")]
Task<KaveNegarResponse> SendSms(string apiKey, [Query] string receptor, [Query] string message, [Query] string sender);
}

View File

@ -0,0 +1,13 @@
using NetinaShop.Infrastructure.Models;
namespace NetinaShop.Infrastructure.RestServices;
public interface IRestApiWrapper : IScopedDependency
{
IKaveNegarRestApi KaveNegarRestApi { get; }
}
public class RestApiWrapper : IRestApiWrapper
{
public IKaveNegarRestApi KaveNegarRestApi => RestService.For<IKaveNegarRestApi>(RestAddress.BaseKaveNegar);
}

View File

@ -0,0 +1,55 @@
namespace NetinaShop.Infrastructure.Services;
public class SmsService : ISmsService
{
private readonly IRestApiWrapper _restApiWrapper;
private readonly ILogger<SmsService> _logger;
private readonly IHostEnvironment _environment;
private readonly SiteSettings _siteSettings;
public SmsService(
IRestApiWrapper restApiWrapper,
IOptionsSnapshot<SiteSettings> optionsSnapshot,
ILogger<SmsService> logger,
IHostEnvironment environment)
{
_restApiWrapper = restApiWrapper;
_logger = logger;
_environment = environment;
_siteSettings = optionsSnapshot.Value;
}
public async Task SendForgerPasswordAsync(string phoneNumber, string newPassword)
{
var rest = await _restApiWrapper.KaveNegarRestApi.SendLookUp(_siteSettings.KaveNegarApiKey, phoneNumber, newPassword, null, null, null, "forgetPassword");
if (rest.Return.status != 200)
throw new BaseApiException(ApiResultStatusCode.SendSmsError, rest.Return.message);
}
public async Task SendVerifyCodeAsync(string phoneNumber, string verifyCode)
{
try
{
var rest = await _restApiWrapper.KaveNegarRestApi.SendLookUp(_siteSettings.KaveNegarApiKey, phoneNumber,
verifyCode, null, null, null, "login-brizco");
if (rest.Return.status != 200 && _environment.IsProduction())
throw new BaseApiException(ApiResultStatusCode.SendSmsError, rest.Return.message);
}
catch (ApiException apiException)
{
if (_environment.IsProduction())
throw ;
else
_logger.LogError(apiException.Message);
}
catch (Exception apiException)
{
if (_environment.IsProduction())
throw;
else
_logger.LogError(apiException.Message);
}
}
}

View File

@ -5,4 +5,5 @@ public interface ICurrentUserService : IScopedDependency
string? UserId { get; }
string? RoleName { get; }
string? UserName { get; }
public List<string>? Permissions { get; }
}

View File

@ -93,7 +93,8 @@ public class DbInitializerService : IDbInitializerService
{
customerRole = new ApplicationRole
{
Name = "مشتری",
Name = "Customer",
PersianName = "مشتری",
EnglishName = "Customer",
};