Compare commits
6 Commits
f2ee509727
...
423b293197
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
423b293197 | ||
|
|
27618a343e | ||
|
|
fe106c5a8c | ||
|
|
941b98b1a4 | ||
|
|
168c33bfea | ||
|
|
40c25ee111 |
@@ -1,7 +1,7 @@
|
|||||||
using DigitalData.Core.Abstractions.Application;
|
using DigitalData.Core.Abstractions.Application;
|
||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Contracts
|
namespace EnvelopeGenerator.Application.Contracts
|
||||||
@@ -30,5 +30,7 @@ namespace EnvelopeGenerator.Application.Contracts
|
|||||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
||||||
|
|
||||||
Task<DataResult<string?>> ReadLastUsedReceiverNameByMail(string mail);
|
Task<DataResult<string?>> ReadLastUsedReceiverNameByMail(string mail);
|
||||||
|
|
||||||
|
Task<DataResult<SmsResponse>> SendSmsAsync(string envelopeReceiverId, string message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
namespace EnvelopeGenerator.Application.Contracts
|
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.Contracts
|
||||||
{
|
{
|
||||||
public interface IMessagingService
|
public interface IMessagingService
|
||||||
{
|
{
|
||||||
public Task<dynamic?> SendSmsAsync(string recipient, string message);
|
public Task<SmsResponse> SendSmsAsync(string recipient, string message);
|
||||||
|
|
||||||
public Task<TResponse?> SendSmsAsync<TResponse>(string recipient, string message);
|
string ServiceProvider { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17
EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs
Normal file
17
EnvelopeGenerator.Application/DTOs/Messaging/SmsResponse.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
namespace EnvelopeGenerator.Application.DTOs.Messaging
|
||||||
|
{
|
||||||
|
public record SmsResponse
|
||||||
|
{
|
||||||
|
public required bool Ok { get; init; }
|
||||||
|
|
||||||
|
public DateTime? AllowedAt { get; set; }
|
||||||
|
|
||||||
|
public TimeSpan AllowedAfter => Allowed ? TimeSpan.Zero : AllowedAt!.Value - DateTime.Now;
|
||||||
|
|
||||||
|
public bool Allowed => AllowedAt is null || DateTime.Now >= AllowedAt;
|
||||||
|
|
||||||
|
public bool Error => !Ok && Allowed;
|
||||||
|
|
||||||
|
public dynamic? Errors { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="2.2.1" />
|
<PackageReference Include="DigitalData.Core.Abstractions" Version="2.2.1" />
|
||||||
<PackageReference Include="DigitalData.Core.Application" Version="2.0.0" />
|
<PackageReference Include="DigitalData.Core.Application" Version="2.0.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Client" Version="2.0.2" />
|
<PackageReference Include="DigitalData.Core.Client" Version="2.0.3" />
|
||||||
<PackageReference Include="DigitalData.Core.DTO" Version="2.0.0" />
|
<PackageReference Include="DigitalData.Core.DTO" Version="2.0.0" />
|
||||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="2.0.0" />
|
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="2.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.18" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.18" />
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
public static readonly string PossibleSecurityBreach = nameof(PossibleSecurityBreach);
|
public static readonly string PossibleSecurityBreach = nameof(PossibleSecurityBreach);
|
||||||
public static readonly string WrongEnvelopeReceiverId = nameof(WrongEnvelopeReceiverId);
|
public static readonly string WrongEnvelopeReceiverId = nameof(WrongEnvelopeReceiverId);
|
||||||
public static readonly string EnvelopeOrReceiverNonexists = nameof(EnvelopeOrReceiverNonexists);
|
public static readonly string EnvelopeOrReceiverNonexists = nameof(EnvelopeOrReceiverNonexists);
|
||||||
|
public static readonly string PhoneNumberNonexists = nameof(PhoneNumberNonexists);
|
||||||
public static readonly string Default = nameof(Default);
|
public static readonly string Default = nameof(Default);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
11
EnvelopeGenerator.Application/MappingExtensions,.cs
Normal file
11
EnvelopeGenerator.Application/MappingExtensions,.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using EnvelopeGenerator.Domain.HttpResponse;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application
|
||||||
|
{
|
||||||
|
public static class MappingExtensions
|
||||||
|
{
|
||||||
|
public static bool Ok(this GtxMessagingResponse gtxMessagingResponse)
|
||||||
|
=> gtxMessagingResponse.TryGetValue("message-status", out var status)
|
||||||
|
&& status?.ToString()?.ToLower() == "ok";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,10 @@ using EnvelopeGenerator.Application.DTOs;
|
|||||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiverReadOnly;
|
||||||
|
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
using EnvelopeGenerator.Domain.HttpResponse;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.MappingProfiles
|
namespace EnvelopeGenerator.Application.MappingProfiles
|
||||||
{
|
{
|
||||||
@@ -50,6 +52,13 @@ namespace EnvelopeGenerator.Application.MappingProfiles
|
|||||||
CreateMap<EnvelopeReceiverBase, EnvelopeReceiverBasicDto>();
|
CreateMap<EnvelopeReceiverBase, EnvelopeReceiverBasicDto>();
|
||||||
CreateMap<EnvelopeReceiverReadOnlyCreateDto, EnvelopeReceiverReadOnly>();
|
CreateMap<EnvelopeReceiverReadOnlyCreateDto, EnvelopeReceiverReadOnly>();
|
||||||
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, EnvelopeReceiverReadOnly>();
|
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, EnvelopeReceiverReadOnly>();
|
||||||
|
|
||||||
|
// Messaging mappings
|
||||||
|
// for GTX messaging
|
||||||
|
CreateMap<GtxMessagingResponse, SmsResponse>()
|
||||||
|
.ConstructUsing(gtxRes => gtxRes.Ok()
|
||||||
|
? new SmsResponse() { Ok = true }
|
||||||
|
: new SmsResponse() { Ok = false, Errors = gtxRes });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@ using EnvelopeGenerator.Infrastructure.Contracts;
|
|||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using EnvelopeGenerator.Extensions;
|
using EnvelopeGenerator.Extensions;
|
||||||
|
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Services
|
namespace EnvelopeGenerator.Application.Services
|
||||||
{
|
{
|
||||||
@@ -16,10 +17,13 @@ namespace EnvelopeGenerator.Application.Services
|
|||||||
{
|
{
|
||||||
private readonly IStringLocalizer<Resource> _localizer;
|
private readonly IStringLocalizer<Resource> _localizer;
|
||||||
|
|
||||||
public EnvelopeReceiverService(IEnvelopeReceiverRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper)
|
private readonly IMessagingService _messagingService;
|
||||||
|
|
||||||
|
public EnvelopeReceiverService(IEnvelopeReceiverRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper, IMessagingService messagingService)
|
||||||
: base(repository, mapper)
|
: base(repository, mapper)
|
||||||
{
|
{
|
||||||
_localizer = localizer;
|
_localizer = localizer;
|
||||||
|
_messagingService = messagingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true)
|
public async Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true)
|
||||||
@@ -135,5 +139,31 @@ namespace EnvelopeGenerator.Application.Services
|
|||||||
var er = await _repository.ReadLastByReceiver(mail);
|
var er = await _repository.ReadLastByReceiver(mail);
|
||||||
return er is null ? Result.Fail<string?>().Notice(LogLevel.None, Flag.NotFound) : Result.Success(er.Name);
|
return er is null ? Result.Fail<string?>().Notice(LogLevel.None, Flag.NotFound) : Result.Success(er.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<DataResult<SmsResponse>> SendSmsAsync(string envelopeReceiverId, string message)
|
||||||
|
{
|
||||||
|
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||||
|
|
||||||
|
if (uuid is null || signature is null)
|
||||||
|
return Result.Fail<SmsResponse>()
|
||||||
|
.Message(_localizer[Key.WrongEnvelopeReceiverId])
|
||||||
|
.Notice(LogLevel.Warning, (uuid, signature).ToTitle())
|
||||||
|
.Notice(LogLevel.Warning, EnvelopeFlag.WrongEnvelopeReceiverId)
|
||||||
|
.Notice(LogLevel.Warning, Flag.PossibleSecurityBreach);
|
||||||
|
|
||||||
|
var env_rcv = await _repository.ReadByUuidSignatureAsync(uuid: uuid, signature: signature, withEnvelope: false, withReceiver: false);
|
||||||
|
if (env_rcv is null)
|
||||||
|
return Result.Fail<SmsResponse>()
|
||||||
|
.Message(Key.EnvelopeReceiverNotFound);
|
||||||
|
|
||||||
|
if (env_rcv.PhoneNumber is null)
|
||||||
|
return Result.Fail<SmsResponse>()
|
||||||
|
.Message(Key.PhoneNumberNonexists)
|
||||||
|
.Notice(LogLevel.Error, Flag.NotFound, $"An attempt was made to send sms to the user whose phone number is null. Envelope recipient ID is {envelopeReceiverId}, UUID is {uuid} and signature is {signature}.");
|
||||||
|
|
||||||
|
var res = await _messagingService.SendSmsAsync(recipient: env_rcv.PhoneNumber, message: message);
|
||||||
|
|
||||||
|
return Result.Success(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
using DigitalData.Core.Abstractions.Client;
|
using AutoMapper;
|
||||||
|
using DigitalData.Core.Abstractions.Client;
|
||||||
using DigitalData.Core.Client;
|
using DigitalData.Core.Client;
|
||||||
using EnvelopeGenerator.Application.Configurations.GtxMessaging;
|
using EnvelopeGenerator.Application.Configurations.GtxMessaging;
|
||||||
using EnvelopeGenerator.Application.Contracts;
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
|
using EnvelopeGenerator.Application.DTOs.Messaging;
|
||||||
|
using EnvelopeGenerator.Domain.HttpResponse;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Services
|
namespace EnvelopeGenerator.Application.Services
|
||||||
@@ -11,21 +14,28 @@ namespace EnvelopeGenerator.Application.Services
|
|||||||
private readonly IHttpClientService<SmsParams> _smsClient;
|
private readonly IHttpClientService<SmsParams> _smsClient;
|
||||||
|
|
||||||
private readonly SmsParams _smsParams;
|
private readonly SmsParams _smsParams;
|
||||||
|
|
||||||
public GtxMessagingService(IHttpClientService<SmsParams> smsClient, IOptions<SmsParams> smsParamsOptions)
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public GtxMessagingService(IHttpClientService<SmsParams> smsClient, IOptions<SmsParams> smsParamsOptions, IMapper mapper)
|
||||||
{
|
{
|
||||||
_smsClient = smsClient;
|
_smsClient = smsClient;
|
||||||
_smsParams = smsParamsOptions.Value;
|
_smsParams = smsParamsOptions.Value;
|
||||||
|
_mapper = mapper;
|
||||||
|
ServiceProvider = GetType().Name.Replace("Service", string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<dynamic?> SendSmsAsync(string recipient, string message) => SendSmsAsync<dynamic>(recipient: recipient, message: message);
|
public async Task<SmsResponse> SendSmsAsync(string recipient, string message)
|
||||||
|
|
||||||
public async Task<TResponse?> SendSmsAsync<TResponse>(string recipient, string message)
|
|
||||||
{
|
{
|
||||||
return await _smsClient.FetchAsync(queryParams: new Dictionary<string, object?>() {
|
return await _smsClient.FetchAsync(queryParams: new Dictionary<string, object?>()
|
||||||
|
{
|
||||||
{ _smsParams.RecipientQueryParamName, recipient },
|
{ _smsParams.RecipientQueryParamName, recipient },
|
||||||
{ _smsParams.MessageQueryParamName, message }
|
{ _smsParams.MessageQueryParamName, message }
|
||||||
}).ThenAsync(res => res.Json<TResponse>());
|
})
|
||||||
|
.ThenAsync(res => res.Json<GtxMessagingResponse>())
|
||||||
|
.ThenAsync(_mapper.Map<SmsResponse>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ServiceProvider { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,6 +41,11 @@ namespace EnvelopeGenerator.Domain.Entities
|
|||||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||||
public DateTime? ChangedWhen { get; set; }
|
public DateTime? ChangedWhen { get; set; }
|
||||||
|
|
||||||
|
[Column("PHONE_NUMBER")]
|
||||||
|
[StringLength(20)]
|
||||||
|
[RegularExpression(@"^\+[0-9]+$", ErrorMessage = "Phone number must start with '+' followed by digits.")]
|
||||||
|
public string? PhoneNumber { get; set; }
|
||||||
|
|
||||||
public (int Envelope, int Receiver) Id => (Envelope: EnvelopeId, Receiver: ReceiverId);
|
public (int Envelope, int Receiver) Id => (Envelope: EnvelopeId, Receiver: ReceiverId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace EnvelopeGenerator.Domain.HttpResponse
|
||||||
|
{
|
||||||
|
public class GtxMessagingResponse : Dictionary<string, object?> { }
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ namespace EnvelopeGenerator.Web.Controllers.Test
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> SendAsync(string recipient, string message)
|
public async Task<IActionResult> SendAsync(string recipient, string message, bool staticResponse = true)
|
||||||
{
|
{
|
||||||
var res = await _service.SendSmsAsync(recipient: recipient, message: message);
|
var res = await _service.SendSmsAsync(recipient: recipient, message: message);
|
||||||
return res is null? StatusCode(StatusCodes.Status500InternalServerError) : Ok(res);
|
return res is null? StatusCode(StatusCodes.Status500InternalServerError) : Ok(res);
|
||||||
|
|||||||
@@ -134,7 +134,7 @@
|
|||||||
"Path": "smsc/sendsms/f566f7e5-bdf2-4a9a-bf52-ed88215a432e/json",
|
"Path": "smsc/sendsms/f566f7e5-bdf2-4a9a-bf52-ed88215a432e/json",
|
||||||
"Headers": {},
|
"Headers": {},
|
||||||
"QueryParams": {
|
"QueryParams": {
|
||||||
"from": "signFLOW Portal"
|
"from": "signFlow"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user