diff --git a/NetinaShop.Api/Controller/AuthController.cs b/NetinaShop.Api/Controller/AuthController.cs index 4cf758f..a89a0f6 100644 --- a/NetinaShop.Api/Controller/AuthController.cs +++ b/NetinaShop.Api/Controller/AuthController.cs @@ -1,5 +1,6 @@ namespace NetinaShop.Api.Controller; + public class AuthController : ICarterModule { diff --git a/NetinaShop.Api/Controller/BlogController.cs b/NetinaShop.Api/Controller/BlogController.cs index 6ab01b8..f3a804f 100644 --- a/NetinaShop.Api/Controller/BlogController.cs +++ b/NetinaShop.Api/Controller/BlogController.cs @@ -53,7 +53,7 @@ public class BlogController : ICarterModule } repositoryWrapper.SetRepository().Add(ent); await repositoryWrapper.SaveChangesAsync(cancellationToken); - return TypedResults.Ok(); + return TypedResults.Ok(ent.AdaptToSDto()); } // PUT:Update Entity diff --git a/NetinaShop.Api/Docs/NetinaShopApi.Blog.http b/NetinaShop.Api/Docs/NetinaShopApi.Blog.http new file mode 100644 index 0000000..7a6068f --- /dev/null +++ b/NetinaShop.Api/Docs/NetinaShopApi.Blog.http @@ -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 diff --git a/NetinaShop.Api/Docs/NetinaShopApi.BlogCategory.http b/NetinaShop.Api/Docs/NetinaShopApi.BlogCategory.http new file mode 100644 index 0000000..7c18107 --- /dev/null +++ b/NetinaShop.Api/Docs/NetinaShopApi.BlogCategory.http @@ -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": "دسته بندی عمومی" +} \ No newline at end of file diff --git a/NetinaShop.Api/Docs/NetinaShopApi.http b/NetinaShop.Api/Docs/NetinaShopApi.http new file mode 100644 index 0000000..f47c066 --- /dev/null +++ b/NetinaShop.Api/Docs/NetinaShopApi.http @@ -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" +} + + diff --git a/NetinaShop.Api/NetinaShop.Api.http b/NetinaShop.Api/NetinaShop.Api.http deleted file mode 100644 index b5286a6..0000000 --- a/NetinaShop.Api/NetinaShop.Api.http +++ /dev/null @@ -1,2 +0,0 @@ -@NetinaShop.Api_HostAddress = http://localhost:5173 - diff --git a/NetinaShop.Api/Services/CurrentUserService.cs b/NetinaShop.Api/Services/CurrentUserService.cs new file mode 100644 index 0000000..ebaa789 --- /dev/null +++ b/NetinaShop.Api/Services/CurrentUserService.cs @@ -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? Permissions => _httpContextAccessor.HttpContext?.User?.FindAll("Permission")?.Select(c => c.Value)?.ToList(); +} \ No newline at end of file diff --git a/NetinaShop.Api/WebFramework/Swagger/SwaggerConfiguration.cs b/NetinaShop.Api/WebFramework/Swagger/SwaggerConfiguration.cs index a5b14ba..0da7920 100644 --- a/NetinaShop.Api/WebFramework/Swagger/SwaggerConfiguration.cs +++ b/NetinaShop.Api/WebFramework/Swagger/SwaggerConfiguration.cs @@ -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(); diff --git a/NetinaShop.Domain/Dtos/LargDtos/BlogLDto.cs b/NetinaShop.Domain/Dtos/LargDtos/BlogLDto.cs index e0f9218..e6bf2db 100644 --- a/NetinaShop.Domain/Dtos/LargDtos/BlogLDto.cs +++ b/NetinaShop.Domain/Dtos/LargDtos/BlogLDto.cs @@ -2,13 +2,13 @@ public class BlogLDto : BaseDto { - 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 Files { get; internal set; } = new(); } \ No newline at end of file diff --git a/NetinaShop.Domain/Dtos/SmallDtos/BlogCategorySDto.cs b/NetinaShop.Domain/Dtos/SmallDtos/BlogCategorySDto.cs index dbfb5f4..ddc948b 100644 --- a/NetinaShop.Domain/Dtos/SmallDtos/BlogCategorySDto.cs +++ b/NetinaShop.Domain/Dtos/SmallDtos/BlogCategorySDto.cs @@ -2,6 +2,6 @@ public class BlogCategorySDto : BaseDto { - 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; } \ No newline at end of file diff --git a/NetinaShop.Infrastructure/Models/RestAddress.cs b/NetinaShop.Infrastructure/Models/RestAddress.cs new file mode 100644 index 0000000..a742622 --- /dev/null +++ b/NetinaShop.Infrastructure/Models/RestAddress.cs @@ -0,0 +1,6 @@ +namespace NetinaShop.Infrastructure.Models; + +public static class RestAddress +{ + public static string BaseKaveNegar { get => "https://api.kavenegar.com/v1/"; } +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponse.cs b/NetinaShop.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponse.cs new file mode 100644 index 0000000..494bf99 --- /dev/null +++ b/NetinaShop.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponse.cs @@ -0,0 +1,7 @@ +namespace NetinaShop.Infrastructure.Models.RestApi.KaveNegar; + +public class KaveNegarResponse +{ + public KaveNegarReturn Return { get; set; } + public KaveNegarResponseEntry[] entries { get; set; } +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponseEntry.cs b/NetinaShop.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponseEntry.cs new file mode 100644 index 0000000..0ff2fb0 --- /dev/null +++ b/NetinaShop.Infrastructure/Models/RestApi/KaveNegar/KaveNegarResponseEntry.cs @@ -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; } +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/Models/RestApi/KaveNegar/KaveNegarReturn.cs b/NetinaShop.Infrastructure/Models/RestApi/KaveNegar/KaveNegarReturn.cs new file mode 100644 index 0000000..7bea23a --- /dev/null +++ b/NetinaShop.Infrastructure/Models/RestApi/KaveNegar/KaveNegarReturn.cs @@ -0,0 +1,7 @@ +namespace NetinaShop.Infrastructure.Models.RestApi.KaveNegar; + +public class KaveNegarReturn +{ + public int status { get; set; } + public string message { get; set; } +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/NetinaShop.Infrastructure.csproj b/NetinaShop.Infrastructure/NetinaShop.Infrastructure.csproj index 01fe40e..8993144 100644 --- a/NetinaShop.Infrastructure/NetinaShop.Infrastructure.csproj +++ b/NetinaShop.Infrastructure/NetinaShop.Infrastructure.csproj @@ -19,6 +19,22 @@ + + + + + + + + + + + + + + + + diff --git a/NetinaShop.Infrastructure/RestServices/IKaveNegarRestApi.cs b/NetinaShop.Infrastructure/RestServices/IKaveNegarRestApi.cs new file mode 100644 index 0000000..200f3b4 --- /dev/null +++ b/NetinaShop.Infrastructure/RestServices/IKaveNegarRestApi.cs @@ -0,0 +1,10 @@ +namespace NetinaShop.Infrastructure.RestServices; + +public interface IKaveNegarRestApi +{ + + [Post("/{apiKey}/verify/lookup.json")] + Task 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 SendSms(string apiKey, [Query] string receptor, [Query] string message, [Query] string sender); +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/RestServices/IRestApiWrapper.cs b/NetinaShop.Infrastructure/RestServices/IRestApiWrapper.cs new file mode 100644 index 0000000..b913979 --- /dev/null +++ b/NetinaShop.Infrastructure/RestServices/IRestApiWrapper.cs @@ -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(RestAddress.BaseKaveNegar); +} \ No newline at end of file diff --git a/NetinaShop.Infrastructure/Services/SmsService.cs b/NetinaShop.Infrastructure/Services/SmsService.cs new file mode 100644 index 0000000..71bb437 --- /dev/null +++ b/NetinaShop.Infrastructure/Services/SmsService.cs @@ -0,0 +1,55 @@ +namespace NetinaShop.Infrastructure.Services; + +public class SmsService : ISmsService +{ + private readonly IRestApiWrapper _restApiWrapper; + private readonly ILogger _logger; + private readonly IHostEnvironment _environment; + private readonly SiteSettings _siteSettings; + public SmsService( + IRestApiWrapper restApiWrapper, + IOptionsSnapshot optionsSnapshot, + ILogger 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); + } + } + +} \ No newline at end of file diff --git a/NetinaShop.Repository/Abstracts/ICurrentUserService.cs b/NetinaShop.Repository/Abstracts/ICurrentUserService.cs index 0b32269..296c738 100644 --- a/NetinaShop.Repository/Abstracts/ICurrentUserService.cs +++ b/NetinaShop.Repository/Abstracts/ICurrentUserService.cs @@ -5,4 +5,5 @@ public interface ICurrentUserService : IScopedDependency string? UserId { get; } string? RoleName { get; } string? UserName { get; } + public List? Permissions { get; } } \ No newline at end of file diff --git a/NetinaShop.Repository/Services/DbInitializerService.cs b/NetinaShop.Repository/Services/DbInitializerService.cs index a4ef57e..4ef7b92 100644 --- a/NetinaShop.Repository/Services/DbInitializerService.cs +++ b/NetinaShop.Repository/Services/DbInitializerService.cs @@ -93,7 +93,8 @@ public class DbInitializerService : IDbInitializerService { customerRole = new ApplicationRole { - Name = "مشتری", + Name = "Customer", + PersianName = "مشتری", EnglishName = "Customer", };