Update sync contracts

This commit is contained in:
Sergey Nazarov 2024-03-26 15:18:12 +03:00
parent 6fd1ae7c80
commit 367b13e175
12 changed files with 170 additions and 54 deletions

View File

@ -6,12 +6,12 @@ public sealed class TextMatchData
public long UserId { get; set; }
public long? ChatId { get; set; }
public string ChatUsername { get; set; }
public string Template { get; set; }
public bool Active { get; set; }
public TextMatchRule Rule { get; set; }
public DateTimeOffset CreatedDateTime { get; set; }

View File

@ -10,6 +10,18 @@ public interface ITextMatchesController
[Post]
Task<long> Create([Body] CreateTextMatchRequest request, CancellationToken cancellationToken = default);
[Get(WebRoutes.TextMatches.ById)]
Task<TextMatchData> GetById([Path] long id, CancellationToken cancellationToken = default);
[Get(WebRoutes.TextMatches.ByUserId)]
Task<TextMatchData[]> GetByUserId([Path] long userId, CancellationToken cancellationToken = default);
[Delete(WebRoutes.TextMatches.ById)]
public Task Delete([Path] long id, CancellationToken cancellationToken = default);
[Patch(WebRoutes.TextMatches.Activate)]
Task Activate([Path] long id, CancellationToken cancellationToken = default);
[Patch(WebRoutes.TextMatches.Disable)]
Task Disable([Path] long id, CancellationToken cancellationToken = default);
}

View File

@ -4,8 +4,6 @@ public class CreateTextMatchRequest
{
public long UserId { get; set; }
public long? ChatId { get; set; }
public string ChatUsername { get; set; }
public string Template { get; set; }

View File

@ -9,5 +9,11 @@ public static class WebRoutes
public const string Path = BasePath + "/" + "text-matches";
public const string ByUserId = "by-user-id/{userId}";
public const string Activate = ById + "/" + "activate";
public const string Disable = ById + "/" + "disable";
public const string ById = "{id}";
}
}

View File

@ -1,6 +1,6 @@
using Microsoft.Extensions.Logging;
using Nocr.TelegramListener.Async.Api.Contracts.Events;
using Nocr.TextMatcher.AppServices.TextMatches.Services;
using Nocr.TextMatcher.AppServices.TextMatches.Repositories;
using Nocr.TextMatcher.Async.Api.Contracts;
using Nocr.TextMatcher.Core.Dates;
using Rebus.Bus;
@ -12,17 +12,17 @@ public sealed class MessageReceivedHandler : IHandleMessages<MessageReceived>
{
private readonly ILogger<MessageReceivedHandler> _logger;
private readonly IBus _bus;
private readonly ITextMatchService _textMatchService;
private readonly ITextMatchRepository _textMatchService;
private readonly ICurrentDateProvider _dateProvider;
public MessageReceivedHandler(ILogger<MessageReceivedHandler> logger,
IBus bus,
ITextMatchService textMatchService,
ITextMatchRepository textMatchRepository,
ICurrentDateProvider dateProvider)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
_textMatchService = textMatchService ?? throw new ArgumentNullException(nameof(textMatchService));
_textMatchService = textMatchRepository ?? throw new ArgumentNullException(nameof(textMatchRepository));
_dateProvider = dateProvider ?? throw new ArgumentNullException(nameof(dateProvider));
}
@ -32,17 +32,15 @@ public sealed class MessageReceivedHandler : IHandleMessages<MessageReceived>
var matches = await _textMatchService.Get();
foreach (var match in matches)
foreach (var match in matches.Where(x => x.Active))
{
if (match.IsMatches(message.ChatId, message.ChatUsername, message.Text))
if (match.IsMatches(message.ChatUsername, message.Text))
{
_logger.LogInformation("Message {@Message} matched {@Match}", message, match);
var @event = new TextMatchMatched
{
ChatId = message.ChatId,
ChatUsername = message.ChatUsername,
Text = message.Text,
UserId = message.From,
MatchId = match.Id,
MatchUserId = match.UserId,
OccuredDateTime = message.OccuredDateTime,
PublishedDateTime = _dateProvider.UtcNow
};

View File

@ -9,4 +9,8 @@ public interface ITextMatchRepository
Task<IReadOnlyCollection<TextMatch>> Get(CancellationToken cancellationToken = default);
Task<IReadOnlyCollection<TextMatch>> GetByUserId(long userId, CancellationToken cancellationToken = default);
Task<TextMatch?> GetById(long id, CancellationToken cancellationToken = default);
Task Update(TextMatch textMatch, CancellationToken cancellationToken = default);
}

View File

@ -1,5 +1,4 @@
using Nocr.TextMatcher.Api.Contracts.TextMatches;
using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
namespace Nocr.TextMatcher.AppServices.TextMatches.Repositories;
@ -49,4 +48,14 @@ public sealed class InMemoryTextMatchRepository : ITextMatchRepository
{
return Task.FromResult<IReadOnlyCollection<TextMatch>>(_textMatches.Where(x => x.UserId == userId).ToArray());
}
public Task<TextMatch?> GetById(long id, CancellationToken cancellationToken)
{
return Task.FromResult(_textMatches.FirstOrDefault(x => x.Id == id));
}
public Task Update(TextMatch textMatch, CancellationToken cancellationToken = default)
{
return Task.CompletedTask;
}
}

View File

@ -5,12 +5,18 @@ namespace Nocr.TextMatcher.AppServices.TextMatches.Services;
public interface ITextMatchService
{
Task<long> Create(long userId, string chatUsername, string template, TextMatchRule rule, long? chatId = null,
Task<long> Create(long userId, string chatUsername, string template, TextMatchRule rule,
CancellationToken cancellationToken = default);
Task<TextMatchData?> GetById(long id, CancellationToken cancellationToken = default);
Task Delete(long id, CancellationToken cancellationToken = default);
Task<IReadOnlyCollection<TextMatch>> Get(CancellationToken cancellationToken = default);
Task<IReadOnlyCollection<TextMatchData>> GetByUserId(long userId, CancellationToken cancellationToken);
Task Activate(long id, CancellationToken cancellationToken = default);
Task Disable(long id, CancellationToken cancellationToken = default);
Task<IReadOnlyCollection<TextMatchData>> Get(CancellationToken cancellationToken = default);
Task<IReadOnlyCollection<TextMatchData>> GetByUserId(long userId, CancellationToken cancellationToken = default);
}

View File

@ -21,10 +21,10 @@ public sealed class TextMatchService : ITextMatchService
_dateProvider = dateProvider ?? throw new ArgumentNullException(nameof(dateProvider));
}
public async Task<long> Create(long userId, string chatUsername, string template, TextMatchRule rule, long? chatId = null,
public async Task<long> Create(long userId, string chatUsername, string template, TextMatchRule rule,
CancellationToken cancellationToken = default)
{
var textMatch = TextMatch.Initialize(userId, chatUsername, template, rule, _dateProvider.UtcNow, chatId);
var textMatch = TextMatch.Initialize(userId, chatUsername, template, rule, _dateProvider.UtcNow);
await _repository.Create(textMatch, cancellationToken);
var @event = new TextMatchCreated
@ -38,28 +38,71 @@ public sealed class TextMatchService : ITextMatchService
return textMatch.Id;
}
public async Task<TextMatchData?> GetById(long id, CancellationToken cancellationToken)
{
var textMatch = await _repository.GetById(id, cancellationToken);
if (textMatch == null)
return null;
return MapToTextMatchData(textMatch);
}
public Task Delete(long id, CancellationToken cancellationToken = default)
{
return _repository.Delete(id, cancellationToken);
}
public Task<IReadOnlyCollection<TextMatch>> Get(CancellationToken cancellationToken = default)
public async Task Activate(long id, CancellationToken cancellationToken = default)
{
return _repository.Get(cancellationToken);
var textMatch = await _repository.GetById(id, cancellationToken);
if (textMatch == null)
{
throw new InvalidOperationException($"Match with id {id} not found");
}
textMatch.Activate();
await _repository.Update(textMatch, cancellationToken);
}
public async Task<IReadOnlyCollection<TextMatchData>> GetByUserId(long userId, CancellationToken cancellationToken = default)
public async Task Disable(long id, CancellationToken cancellationToken = default)
{
var textMatch = await _repository.GetById(id, cancellationToken);
if (textMatch == null)
{
throw new InvalidOperationException($"Match with id {id} not found");
}
textMatch.Disable();
await _repository.Update(textMatch, cancellationToken);
}
public async Task<IReadOnlyCollection<TextMatchData>> Get(CancellationToken cancellationToken = default)
{
var matches = await _repository.Get(cancellationToken);
return matches.Select(MapToTextMatchData).ToArray();
}
public async Task<IReadOnlyCollection<TextMatchData>> GetByUserId(long userId,
CancellationToken cancellationToken = default)
{
var matches = await _repository.GetByUserId(userId, cancellationToken);
return matches.Select(x => new TextMatchData
return matches.Select(MapToTextMatchData).ToArray();
}
private TextMatchData MapToTextMatchData(TextMatch textMatch)
{
return new TextMatchData
{
Id = x.Id,
ChatId = x.ChatId,
ChatUsername = x.ChatUsername,
Template = x.Template,
UserId = x.UserId,
Rule = x.Rule,
CreatedDateTime = x.CreatedDateTime
}).ToArray();
Id = textMatch.Id,
ChatUsername = textMatch.ChatUsername,
Active = textMatch.Active,
Template = textMatch.Template,
UserId = textMatch.UserId,
Rule = textMatch.Rule,
CreatedDateTime = textMatch.CreatedDateTime
};
}
}

View File

@ -9,14 +9,14 @@ public sealed class TextMatch
public long UserId { get; private set; }
public long? ChatId { get; private set; }
public string ChatUsername { get; private set; }
public string Template { get; private set; }
public TextMatchRule Rule { get; private set; }
public bool Active { get; private set; }
public DateTimeOffset CreatedDateTime { get; private set; }
private TextMatch(long userId,
@ -24,41 +24,60 @@ public sealed class TextMatch
string template,
TextMatchRule rule,
DateTimeOffset createdDateTime,
long? chatId)
bool active)
{
UserId = userId;
ChatUsername = chatUsername;
Template = template;
Rule = rule;
CreatedDateTime = createdDateTime;
ChatId = chatId;
Active = active;
}
public static TextMatch Initialize(long userId,
string chatUsername,
string template,
TextMatchRule rule,
DateTimeOffset createdDateTime,
long? chatId = null)
DateTimeOffset createdDateTime)
{
if (userId <= 0)
throw new ArgumentException("User id should be greater tha 0", nameof(userId));
if (chatId is <= 0)
throw new ArgumentException("Chat id should be greater tha 0", nameof(chatId));
if (string.IsNullOrWhiteSpace(template))
throw new ArgumentException("Template should not be empty", nameof(template));
if (string.IsNullOrWhiteSpace(chatUsername))
throw new ArgumentException("Chat username should not be empty", nameof(chatUsername));
return new TextMatch(userId, chatUsername, template, rule, createdDateTime,chatId);
if (chatUsername.StartsWith("@"))
throw new ArgumentException("Chat username should be without @", nameof(chatUsername));
return new TextMatch(userId, chatUsername, template, rule, createdDateTime, true);
}
public bool IsMatches(long chatId, string chatUsername, string text)
public void Disable()
{
if (ChatId.HasValue && ChatId != chatId && !string.Equals(ChatUsername, chatUsername, StringComparison.OrdinalIgnoreCase))
if (Active == false)
{
throw new InvalidOperationException("Failed to disable inactive match");
}
Active = false;
}
public void Activate()
{
if (Active == true)
{
throw new InvalidOperationException("Failed to activate inactive match");
}
Active = true;
}
public bool IsMatches(string chatUsername, string text)
{
if (!string.Equals(ChatUsername, chatUsername, StringComparison.OrdinalIgnoreCase))
return false;
switch (Rule)

View File

@ -4,13 +4,9 @@ public class TextMatchMatched : IEvent
{
public Guid Id => Guid.NewGuid();
public long UserId { get; set; }
public long MatchId { get; set; }
public long? ChatId { get; set; }
public string ChatUsername { get; set; } = null!;
public string Text { get; set; }
public long MatchUserId { get; set; }
public DateTimeOffset OccuredDateTime { get; set; }

View File

@ -20,13 +20,38 @@ public class TextMatchController : ControllerBase
[HttpPost]
public Task<long> Create([FromBody] CreateTextMatchRequest request, CancellationToken cancellationToken = default)
{
return _textMatchService.Create(request.UserId, request.ChatUsername, request.Template, request.Rule,
request.ChatId, cancellationToken);
return _textMatchService.Create(request.UserId, request.ChatUsername, request.Template, request.Rule, cancellationToken);
}
[HttpGet(WebRoutes.TextMatches.ById)]
public Task<TextMatchData?> GetById([FromRoute] long id, CancellationToken cancellationToken = default)
{
return _textMatchService.GetById(id, cancellationToken);
}
[HttpDelete(WebRoutes.TextMatches.ById)]
public Task Delete([FromRoute] long id, CancellationToken cancellationToken = default)
{
return _textMatchService.Delete(id, cancellationToken);
}
[HttpGet(WebRoutes.TextMatches.ByUserId)]
public Task<IReadOnlyCollection<TextMatchData>> GetByUserId([FromRoute] long userId, CancellationToken cancellationToken = default)
public Task<IReadOnlyCollection<TextMatchData>> GetByUserId([FromRoute] long userId,
CancellationToken cancellationToken = default)
{
return _textMatchService.GetByUserId(userId, cancellationToken);
}
[HttpPatch(WebRoutes.TextMatches.Activate)]
public Task Activate([FromRoute] long id, CancellationToken cancellationToken = default)
{
return _textMatchService.Activate(id, cancellationToken);
}
[HttpPatch(WebRoutes.TextMatches.Disable)]
public Task Disable([FromRoute] long id, CancellationToken cancellationToken = default)
{
return _textMatchService.Disable(id, cancellationToken);
}
}