diff --git a/Directory.Packages.props b/Directory.Packages.props
index 6b05077..7efbb5e 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -24,8 +24,15 @@
+
+
+
+
+
+
+
diff --git a/Nocr.TextMatcher.sln b/Nocr.TextMatcher.sln
index ae093f3..1e5c82a 100644
--- a/Nocr.TextMatcher.sln
+++ b/Nocr.TextMatcher.sln
@@ -22,6 +22,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Tests", "_Tests", "{6E4D9F
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nocr.TextMatcher.AppServices.UnitTests", "tests\Nocr.TextMatcher.AppServices.UnitTests\Nocr.TextMatcher.AppServices.UnitTests.csproj", "{B721E055-84AF-44C6-973D-33241FD2EA7C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nocr.TextMatcher.Contracts", "src\Nocr.TextMatcher.Contracts\Nocr.TextMatcher.Contracts.csproj", "{D6EC25FA-B8B9-4B21-BC4B-16E604B16E02}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nocr.TextMatcher.Persistence", "src\Nocr.TextMatcher.Persistence\Nocr.TextMatcher.Persistence.csproj", "{D578EE54-B55A-4B45-859D-7F343C73EEF5}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Contracts", "Contracts", "{0B8E28B3-EECC-4981-A87F-6D74C4F23371}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nocr.TextMatcher.Domain", "src\Nocr.TextMatcher.Domain\Nocr.TextMatcher.Domain.csproj", "{301BBDEA-ACF8-404D-83FA-AA26A8153D35}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -52,8 +60,23 @@ Global
{B721E055-84AF-44C6-973D-33241FD2EA7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B721E055-84AF-44C6-973D-33241FD2EA7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B721E055-84AF-44C6-973D-33241FD2EA7C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D6EC25FA-B8B9-4B21-BC4B-16E604B16E02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D6EC25FA-B8B9-4B21-BC4B-16E604B16E02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D6EC25FA-B8B9-4B21-BC4B-16E604B16E02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D6EC25FA-B8B9-4B21-BC4B-16E604B16E02}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D578EE54-B55A-4B45-859D-7F343C73EEF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D578EE54-B55A-4B45-859D-7F343C73EEF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D578EE54-B55A-4B45-859D-7F343C73EEF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D578EE54-B55A-4B45-859D-7F343C73EEF5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {301BBDEA-ACF8-404D-83FA-AA26A8153D35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {301BBDEA-ACF8-404D-83FA-AA26A8153D35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {301BBDEA-ACF8-404D-83FA-AA26A8153D35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {301BBDEA-ACF8-404D-83FA-AA26A8153D35}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{B721E055-84AF-44C6-973D-33241FD2EA7C} = {6E4D9F75-861F-4C00-A5C8-00D1BEE5A659}
+ {4028666B-FAE8-4DB9-8D10-B00F5F31BDCC} = {0B8E28B3-EECC-4981-A87F-6D74C4F23371}
+ {A6332064-40EE-498A-826D-638BC295A185} = {0B8E28B3-EECC-4981-A87F-6D74C4F23371}
+ {D6EC25FA-B8B9-4B21-BC4B-16E604B16E02} = {0B8E28B3-EECC-4981-A87F-6D74C4F23371}
EndGlobalSection
EndGlobal
diff --git a/src/Nocr.TextMatcher.Api.Contracts/Nocr.TextMatcher.Api.Contracts.csproj b/src/Nocr.TextMatcher.Api.Contracts/Nocr.TextMatcher.Api.Contracts.csproj
index 27549fd..b576723 100644
--- a/src/Nocr.TextMatcher.Api.Contracts/Nocr.TextMatcher.Api.Contracts.csproj
+++ b/src/Nocr.TextMatcher.Api.Contracts/Nocr.TextMatcher.Api.Contracts.csproj
@@ -8,4 +8,8 @@
+
+
+
+
diff --git a/src/Nocr.TextMatcher.Api.Contracts/TextMatches/Dto/TextMatchData.cs b/src/Nocr.TextMatcher.Api.Contracts/TextMatches/Dto/TextSubscriptionData.cs
similarity index 85%
rename from src/Nocr.TextMatcher.Api.Contracts/TextMatches/Dto/TextMatchData.cs
rename to src/Nocr.TextMatcher.Api.Contracts/TextMatches/Dto/TextSubscriptionData.cs
index 2d3aa8d..e5a0663 100644
--- a/src/Nocr.TextMatcher.Api.Contracts/TextMatches/Dto/TextMatchData.cs
+++ b/src/Nocr.TextMatcher.Api.Contracts/TextMatches/Dto/TextSubscriptionData.cs
@@ -1,6 +1,8 @@
+using Nocr.TextMatcher.Contracts;
+
namespace Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
-public sealed class TextMatchData
+public sealed class TextSubscriptionData
{
public long Id { get; set; }
@@ -27,7 +29,7 @@ public sealed class TextMatchData
///
/// Тип матча
///
- public TextMatchRule Rule { get; set; }
+ public TextSubscriptionRule Rule { get; set; }
///
/// Дата создания
diff --git a/src/Nocr.TextMatcher.Api.Contracts/TextMatches/ITextMatchesController.cs b/src/Nocr.TextMatcher.Api.Contracts/TextMatches/ITextMatchesController.cs
deleted file mode 100644
index 7038899..0000000
--- a/src/Nocr.TextMatcher.Api.Contracts/TextMatches/ITextMatchesController.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
-using Nocr.TextMatcher.Api.Contracts.TextMatches.Requests;
-using RestEase;
-
-namespace Nocr.TextMatcher.Api.Contracts.TextMatches;
-
-[BasePath(WebRoutes.TextMatches.Path)]
-public interface ITextMatchesController
-{
- [Post]
- Task Create([Body] CreateTextMatchRequest request, CancellationToken cancellationToken = default);
-
- [Get(WebRoutes.TextMatches.ById)]
- Task GetById([Path] long id, CancellationToken cancellationToken = default);
-
- [Get(WebRoutes.TextMatches.ByUserId)]
- Task 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);
-}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.Api.Contracts/TextMatches/ITextSubscriptionsController.cs b/src/Nocr.TextMatcher.Api.Contracts/TextMatches/ITextSubscriptionsController.cs
new file mode 100644
index 0000000..3fa2563
--- /dev/null
+++ b/src/Nocr.TextMatcher.Api.Contracts/TextMatches/ITextSubscriptionsController.cs
@@ -0,0 +1,27 @@
+using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
+using Nocr.TextMatcher.Api.Contracts.TextMatches.Requests;
+using RestEase;
+
+namespace Nocr.TextMatcher.Api.Contracts.TextMatches;
+
+[BasePath(WebRoutes.TextSubscriptions.Path)]
+public interface ITextSubscriptionsController
+{
+ [Post]
+ Task Create([Body] CreateTextSubscriptionRequest request, CancellationToken cancellationToken = default);
+
+ [Get(WebRoutes.TextSubscriptions.ById)]
+ Task GetById([Path] long id, CancellationToken cancellationToken = default);
+
+ [Get(WebRoutes.TextSubscriptions.ByUserId)]
+ Task GetByUserId([Path] long userId, CancellationToken cancellationToken = default);
+
+ [Delete(WebRoutes.TextSubscriptions.ById)]
+ public Task Delete([Path] long id, CancellationToken cancellationToken = default);
+
+ [Patch(WebRoutes.TextSubscriptions.Activate)]
+ Task Activate([Path] long id, CancellationToken cancellationToken = default);
+
+ [Patch(WebRoutes.TextSubscriptions.Disable)]
+ Task Disable([Path] long id, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.Api.Contracts/TextMatches/Requests/CreateTextMatchRequest.cs b/src/Nocr.TextMatcher.Api.Contracts/TextMatches/Requests/CreateTextSubscriptionRequest.cs
similarity index 81%
rename from src/Nocr.TextMatcher.Api.Contracts/TextMatches/Requests/CreateTextMatchRequest.cs
rename to src/Nocr.TextMatcher.Api.Contracts/TextMatches/Requests/CreateTextSubscriptionRequest.cs
index bd54c88..560dc6f 100644
--- a/src/Nocr.TextMatcher.Api.Contracts/TextMatches/Requests/CreateTextMatchRequest.cs
+++ b/src/Nocr.TextMatcher.Api.Contracts/TextMatches/Requests/CreateTextSubscriptionRequest.cs
@@ -1,6 +1,8 @@
+using Nocr.TextMatcher.Contracts;
+
namespace Nocr.TextMatcher.Api.Contracts.TextMatches.Requests;
-public class CreateTextMatchRequest
+public class CreateTextSubscriptionRequest
{
///
/// Идентификатор пользователя в системе
@@ -20,5 +22,5 @@ public class CreateTextMatchRequest
///
/// Тип совпадения
///
- public TextMatchRule Rule { get; set; }
+ public TextSubscriptionRule Rule { get; set; }
}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.Api.Contracts/WebRoutes.cs b/src/Nocr.TextMatcher.Api.Contracts/WebRoutes.cs
index 1294b0b..e49518d 100644
--- a/src/Nocr.TextMatcher.Api.Contracts/WebRoutes.cs
+++ b/src/Nocr.TextMatcher.Api.Contracts/WebRoutes.cs
@@ -4,7 +4,7 @@ public static class WebRoutes
{
public const string BasePath = "/api";
- public static class TextMatches
+ public static class TextSubscriptions
{
public const string Path = BasePath + "/" + "text-matches";
diff --git a/src/Nocr.TextMatcher.AppServices/Constants.cs b/src/Nocr.TextMatcher.AppServices/Constants.cs
new file mode 100644
index 0000000..f347657
--- /dev/null
+++ b/src/Nocr.TextMatcher.AppServices/Constants.cs
@@ -0,0 +1,11 @@
+namespace Nocr.TextMatcher.AppServices;
+
+public static class Constants
+{
+ public static class RoutingKeys
+ {
+ public const string MatchedSubscriptions = "nocr.text.matcher.matched";
+
+ public const string Subscriptions = "nocr.text.matcher.subscriptions";
+ }
+}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.AppServices/Nocr.TextMatcher.AppServices.csproj b/src/Nocr.TextMatcher.AppServices/Nocr.TextMatcher.AppServices.csproj
index 90cdda5..0145c78 100644
--- a/src/Nocr.TextMatcher.AppServices/Nocr.TextMatcher.AppServices.csproj
+++ b/src/Nocr.TextMatcher.AppServices/Nocr.TextMatcher.AppServices.csproj
@@ -15,6 +15,8 @@
+
+
diff --git a/src/Nocr.TextMatcher.AppServices/ServiceCollectionExtensions.cs b/src/Nocr.TextMatcher.AppServices/ServiceCollectionExtensions.cs
index 66c5ca5..a555b2a 100644
--- a/src/Nocr.TextMatcher.AppServices/ServiceCollectionExtensions.cs
+++ b/src/Nocr.TextMatcher.AppServices/ServiceCollectionExtensions.cs
@@ -1,7 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
-using Nocr.TextMatcher.AppServices.TextMatchers;
using Nocr.TextMatcher.AppServices.TextMatches.Repositories;
using Nocr.TextMatcher.AppServices.TextMatches.Services;
+using Nocr.TextMatcher.AppServices.TextSubscriptions;
using Rebus.Config;
namespace Nocr.TextMatcher.AppServices;
@@ -15,8 +15,8 @@ public static class ServiceCollectionExtensions
// Add registrations here
services.AddRebusHandler();
- services.AddScoped();
- services.AddSingleton();
+ services.AddScoped();
+ services.AddScoped();
return services;
}
diff --git a/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/ITextMatchRepository.cs b/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/ITextMatchRepository.cs
deleted file mode 100644
index d0f661b..0000000
--- a/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/ITextMatchRepository.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-namespace Nocr.TextMatcher.AppServices.TextMatches.Repositories;
-
-public interface ITextMatchRepository
-{
- Task Create(TextMatch textMatch, CancellationToken cancellationToken = default);
-
- Task Delete(long id, CancellationToken cancellationToken = default);
-
- Task> Get(CancellationToken cancellationToken = default);
-
- Task> GetByUserId(long userId, CancellationToken cancellationToken = default);
-
- Task GetById(long id, CancellationToken cancellationToken = default);
-
- Task Update(TextMatch textMatch, CancellationToken cancellationToken = default);
-}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/ITextSubscriptionRepository.cs b/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/ITextSubscriptionRepository.cs
new file mode 100644
index 0000000..876238a
--- /dev/null
+++ b/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/ITextSubscriptionRepository.cs
@@ -0,0 +1,16 @@
+namespace Nocr.TextMatcher.AppServices.TextMatches.Repositories;
+
+public interface ITextSubscriptionRepository
+{
+ Task Create(TextSubscription textSubscription, CancellationToken cancellationToken = default);
+
+ Task Delete(long id, CancellationToken cancellationToken = default);
+
+ Task> Get(CancellationToken cancellationToken = default);
+
+ Task> GetByUserId(long userId, CancellationToken cancellationToken = default);
+
+ Task GetById(long id, CancellationToken cancellationToken = default);
+
+ Task Update(TextSubscription subscription, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/InMemoryTextMatchRepository.cs b/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/InMemoryTextMatchRepository.cs
deleted file mode 100644
index d022b61..0000000
--- a/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/InMemoryTextMatchRepository.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using Nocr.TextMatcher.Api.Contracts.TextMatches;
-
-namespace Nocr.TextMatcher.AppServices.TextMatches.Repositories;
-
-public sealed class InMemoryTextMatchRepository : ITextMatchRepository
-{
- private long _id = 0;
-
- private List _textMatches = new List();
-
- public InMemoryTextMatchRepository()
- {
- var seed = new[]
- {
- TextMatch.Initialize(1, "baraholka_tbi", "телевизор", TextMatchRule.Full, DateTimeOffset.UtcNow),
- TextMatch.Initialize(1, "baraholka_tbi", "macbook mac", TextMatchRule.AnyWord, DateTimeOffset.UtcNow),
- TextMatch.Initialize(1, "baraholka_tbi", "гитар", TextMatchRule.Full, DateTimeOffset.UtcNow),
- TextMatch.Initialize(1, "baraholka_tbi", "обувь ботинки туфли", TextMatchRule.AnyWord, DateTimeOffset.UtcNow),
- TextMatch.Initialize(1, "baraholka_tbi", "одежда платья брюки рубашка рубашки", TextMatchRule.AnyWord, DateTimeOffset.UtcNow),
- };
-
- _textMatches.AddRange(seed);
- }
-
- public Task Create(TextMatch textMatch, CancellationToken cancellationToken = default)
- {
- var id = Interlocked.Increment(ref _id);
- textMatch.Id = id;
- _textMatches.Add(textMatch);
-
- return Task.FromResult(id);
- }
-
- public Task Delete(long id, CancellationToken cancellationToken = default)
- {
- var index = _textMatches.FindIndex(x => x.Id == id);
- _textMatches.RemoveAt(index);
-
- return Task.CompletedTask;
- }
-
- public Task> Get(CancellationToken cancellationToken = default)
- {
- return Task.FromResult>(_textMatches);
- }
-
- public Task> GetByUserId(long userId, CancellationToken cancellationToken = default)
- {
- return Task.FromResult>(_textMatches.Where(x => x.UserId == userId).ToArray());
- }
-
- public Task 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;
- }
-}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/TextSubscriptionRepository.cs b/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/TextSubscriptionRepository.cs
new file mode 100644
index 0000000..a70f85b
--- /dev/null
+++ b/src/Nocr.TextMatcher.AppServices/TextMatches/Repositories/TextSubscriptionRepository.cs
@@ -0,0 +1,48 @@
+using Microsoft.EntityFrameworkCore;
+using Nocr.TextMatcher.Persistence;
+
+namespace Nocr.TextMatcher.AppServices.TextMatches.Repositories;
+
+public sealed class TextSubscriptionRepository : ITextSubscriptionRepository
+{
+ private readonly TextMatcherContext _db;
+
+ public TextSubscriptionRepository(TextMatcherContext db)
+ {
+ _db = db ?? throw new ArgumentNullException(nameof(db));
+ }
+
+ public async Task Create(TextSubscription textSubscription, CancellationToken cancellationToken = default)
+ {
+ await _db.TextSubscriptions.AddAsync(textSubscription, cancellationToken);
+ await _db.SaveChangesAsync(cancellationToken);
+
+ return textSubscription.Id;
+ }
+
+ public async Task Delete(long id, CancellationToken cancellationToken = default)
+ {
+ await _db.TextSubscriptions.Where(x => x.Id == id).ExecuteDeleteAsync(cancellationToken);
+ }
+
+ public async Task> Get(CancellationToken cancellationToken = default)
+ {
+ return await _db.TextSubscriptions.AsNoTracking().ToListAsync(cancellationToken);
+ }
+
+ public async Task> GetByUserId(long userId, CancellationToken cancellationToken = default)
+ {
+ return await _db.TextSubscriptions.Where(x => x.UserId == userId).AsNoTracking().ToListAsync(cancellationToken);
+ }
+
+ public async Task GetById(long id, CancellationToken cancellationToken = default)
+ {
+ return await _db.TextSubscriptions.FirstOrDefaultAsync(x => x.Id == id, cancellationToken: cancellationToken);
+ }
+
+ public async Task Update(TextSubscription subscription, CancellationToken cancellationToken = default)
+ {
+ _db.TextSubscriptions.Update(subscription);
+ await _db.SaveChangesAsync(cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.AppServices/TextMatches/Services/ITextMatchService.cs b/src/Nocr.TextMatcher.AppServices/TextMatches/Services/ITextSubscriptionsService.cs
similarity index 55%
rename from src/Nocr.TextMatcher.AppServices/TextMatches/Services/ITextMatchService.cs
rename to src/Nocr.TextMatcher.AppServices/TextMatches/Services/ITextSubscriptionsService.cs
index d286a4d..4eb256e 100644
--- a/src/Nocr.TextMatcher.AppServices/TextMatches/Services/ITextMatchService.cs
+++ b/src/Nocr.TextMatcher.AppServices/TextMatches/Services/ITextSubscriptionsService.cs
@@ -1,14 +1,14 @@
-using Nocr.TextMatcher.Api.Contracts.TextMatches;
using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
+using Nocr.TextMatcher.Contracts;
namespace Nocr.TextMatcher.AppServices.TextMatches.Services;
-public interface ITextMatchService
+public interface ITextSubscriptionsService
{
- Task Create(long userId, string chatUsername, string template, TextMatchRule rule,
+ Task Create(long userId, string chatUsername, string template, TextSubscriptionRule rule,
CancellationToken cancellationToken = default);
- Task GetById(long id, CancellationToken cancellationToken = default);
+ Task GetById(long id, CancellationToken cancellationToken = default);
Task Delete(long id, CancellationToken cancellationToken = default);
@@ -16,7 +16,7 @@ public interface ITextMatchService
Task Disable(long id, CancellationToken cancellationToken = default);
- Task> Get(CancellationToken cancellationToken = default);
+ Task> Get(CancellationToken cancellationToken = default);
- Task> GetByUserId(long userId, CancellationToken cancellationToken = default);
+ Task> GetByUserId(long userId, CancellationToken cancellationToken = default);
}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.AppServices/TextMatches/Services/TextMatchService.cs b/src/Nocr.TextMatcher.AppServices/TextMatches/Services/TextSubscriptionsService.cs
similarity index 65%
rename from src/Nocr.TextMatcher.AppServices/TextMatches/Services/TextMatchService.cs
rename to src/Nocr.TextMatcher.AppServices/TextMatches/Services/TextSubscriptionsService.cs
index cb2b137..8fba6a9 100644
--- a/src/Nocr.TextMatcher.AppServices/TextMatches/Services/TextMatchService.cs
+++ b/src/Nocr.TextMatcher.AppServices/TextMatches/Services/TextSubscriptionsService.cs
@@ -1,19 +1,19 @@
-using Nocr.TextMatcher.Api.Contracts.TextMatches;
using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
using Nocr.TextMatcher.AppServices.TextMatches.Repositories;
using Nocr.TextMatcher.Async.Api.Contracts;
+using Nocr.TextMatcher.Contracts;
using Nocr.TextMatcher.Core.Dates;
using Rebus.Bus;
namespace Nocr.TextMatcher.AppServices.TextMatches.Services;
-public sealed class TextMatchService : ITextMatchService
+public sealed class TextSubscriptionsService : ITextSubscriptionsService
{
private readonly IBus _bus;
- private readonly ITextMatchRepository _repository;
+ private readonly ITextSubscriptionRepository _repository;
private readonly ICurrentDateProvider _dateProvider;
- public TextMatchService(IBus bus, ITextMatchRepository repository,
+ public TextSubscriptionsService(IBus bus, ITextSubscriptionRepository repository,
ICurrentDateProvider dateProvider)
{
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
@@ -21,24 +21,23 @@ public sealed class TextMatchService : ITextMatchService
_dateProvider = dateProvider ?? throw new ArgumentNullException(nameof(dateProvider));
}
- public async Task Create(long userId, string chatUsername, string template, TextMatchRule rule,
+ public async Task Create(long userId, string chatUsername, string template, TextSubscriptionRule rule,
CancellationToken cancellationToken = default)
{
- var textMatch = TextMatch.Initialize(userId, chatUsername, template, rule, _dateProvider.UtcNow);
+ var textMatch = TextSubscription.Initialize(userId, chatUsername, template, rule, _dateProvider.UtcNow);
await _repository.Create(textMatch, cancellationToken);
- var @event = new TextMatchCreated
+ var @event = new TextSubscriptionCreated
{
ChatUsername = textMatch.ChatUsername
};
- // TODO:
- await _bus.Advanced.Topics.Publish("nocr.text.matcher.matches", @event);
+ await _bus.Advanced.Topics.Publish(Constants.RoutingKeys.Subscriptions, @event);
return textMatch.Id;
}
- public async Task GetById(long id, CancellationToken cancellationToken)
+ public async Task GetById(long id, CancellationToken cancellationToken)
{
var textMatch = await _repository.GetById(id, cancellationToken);
if (textMatch == null)
@@ -78,31 +77,31 @@ public sealed class TextMatchService : ITextMatchService
await _repository.Update(textMatch, cancellationToken);
}
- public async Task> Get(CancellationToken cancellationToken = default)
+ public async Task> Get(CancellationToken cancellationToken = default)
{
var matches = await _repository.Get(cancellationToken);
return matches.Select(MapToTextMatchData).ToArray();
}
- public async Task> GetByUserId(long userId,
+ public async Task> GetByUserId(long userId,
CancellationToken cancellationToken = default)
{
var matches = await _repository.GetByUserId(userId, cancellationToken);
return matches.Select(MapToTextMatchData).ToArray();
}
- private TextMatchData MapToTextMatchData(TextMatch textMatch)
+ private TextSubscriptionData MapToTextMatchData(TextSubscription textSubscription)
{
- return new TextMatchData
+ return new TextSubscriptionData
{
- Id = textMatch.Id,
- ChatUsername = textMatch.ChatUsername,
- Active = textMatch.Active,
- Template = textMatch.Template,
- UserId = textMatch.UserId,
- Rule = textMatch.Rule,
- CreatedDateTime = textMatch.CreatedDateTime
+ Id = textSubscription.Id,
+ ChatUsername = textSubscription.ChatUsername,
+ Active = textSubscription.Active,
+ Template = textSubscription.Template,
+ UserId = textSubscription.UserId,
+ Rule = textSubscription.Rule,
+ CreatedDateTime = textSubscription.CreatedDateTime
};
}
}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.AppServices/TextMatchers/MessageReceivedHandler.cs b/src/Nocr.TextMatcher.AppServices/TextSubscriptions/MessageReceivedHandler.cs
similarity index 71%
rename from src/Nocr.TextMatcher.AppServices/TextMatchers/MessageReceivedHandler.cs
rename to src/Nocr.TextMatcher.AppServices/TextSubscriptions/MessageReceivedHandler.cs
index 6f7046d..31cd827 100644
--- a/src/Nocr.TextMatcher.AppServices/TextMatchers/MessageReceivedHandler.cs
+++ b/src/Nocr.TextMatcher.AppServices/TextSubscriptions/MessageReceivedHandler.cs
@@ -6,23 +6,23 @@ using Nocr.TextMatcher.Core.Dates;
using Rebus.Bus;
using Rebus.Handlers;
-namespace Nocr.TextMatcher.AppServices.TextMatchers;
+namespace Nocr.TextMatcher.AppServices.TextSubscriptions;
public sealed class MessageReceivedHandler : IHandleMessages
{
private readonly ILogger _logger;
private readonly IBus _bus;
- private readonly ITextMatchRepository _textMatchService;
+ private readonly ITextSubscriptionRepository _textSubscriptionService;
private readonly ICurrentDateProvider _dateProvider;
public MessageReceivedHandler(ILogger logger,
IBus bus,
- ITextMatchRepository textMatchRepository,
+ ITextSubscriptionRepository textSubscriptionRepository,
ICurrentDateProvider dateProvider)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
- _textMatchService = textMatchRepository ?? throw new ArgumentNullException(nameof(textMatchRepository));
+ _textSubscriptionService = textSubscriptionRepository ?? throw new ArgumentNullException(nameof(textSubscriptionRepository));
_dateProvider = dateProvider ?? throw new ArgumentNullException(nameof(dateProvider));
}
@@ -30,17 +30,17 @@ public sealed class MessageReceivedHandler : IHandleMessages
{
_logger.LogInformation("Received message: {@Message}", message);
- var matches = await _textMatchService.Get();
+ var matches = await _textSubscriptionService.Get();
foreach (var match in matches.Where(x => x.Active))
{
if (match.IsMatches(message.ChatUsername, message.Text))
{
_logger.LogInformation("Message {@Message} matched {@Match}", message, match);
- var @event = new TextMatchMatched
+ var @event = new TextSubscriptionMatched
{
- MatchId = match.Id,
- MatchUserId = match.UserId,
+ SubscriptionId = match.Id,
+ SubscriptionUserId = match.UserId,
ChatUsername = match.ChatUsername,
Rule = (int)match.Rule,
Template = match.Template,
@@ -49,9 +49,8 @@ public sealed class MessageReceivedHandler : IHandleMessages
OccuredDateTime = message.OccuredDateTime,
PublishedDateTime = _dateProvider.UtcNow
};
-
- // TODO:
- await _bus.Advanced.Topics.Publish("nocr.text.matcher.matched", @event);
+
+ await _bus.Advanced.Topics.Publish(Constants.RoutingKeys.MatchedSubscriptions, @event);
}
}
}
diff --git a/src/Nocr.TextMatcher.Async.Api.Contracts/TextMatchCreated.cs b/src/Nocr.TextMatcher.Async.Api.Contracts/TextSubscriptionCreated.cs
similarity index 85%
rename from src/Nocr.TextMatcher.Async.Api.Contracts/TextMatchCreated.cs
rename to src/Nocr.TextMatcher.Async.Api.Contracts/TextSubscriptionCreated.cs
index e1870db..077f0ec 100644
--- a/src/Nocr.TextMatcher.Async.Api.Contracts/TextMatchCreated.cs
+++ b/src/Nocr.TextMatcher.Async.Api.Contracts/TextSubscriptionCreated.cs
@@ -1,6 +1,6 @@
namespace Nocr.TextMatcher.Async.Api.Contracts;
-public class TextMatchCreated : IEvent
+public class TextSubscriptionCreated : IEvent
{
public Guid Id => Guid.NewGuid();
diff --git a/src/Nocr.TextMatcher.Async.Api.Contracts/TextMatchMatched.cs b/src/Nocr.TextMatcher.Async.Api.Contracts/TextSubscriptionMatched.cs
similarity index 89%
rename from src/Nocr.TextMatcher.Async.Api.Contracts/TextMatchMatched.cs
rename to src/Nocr.TextMatcher.Async.Api.Contracts/TextSubscriptionMatched.cs
index 37cd9b0..e921fc3 100644
--- a/src/Nocr.TextMatcher.Async.Api.Contracts/TextMatchMatched.cs
+++ b/src/Nocr.TextMatcher.Async.Api.Contracts/TextSubscriptionMatched.cs
@@ -1,18 +1,18 @@
namespace Nocr.TextMatcher.Async.Api.Contracts;
-public class TextMatchMatched : IEvent
+public class TextSubscriptionMatched : IEvent
{
public Guid Id => Guid.NewGuid();
///
/// Идентификатор матча
///
- public long MatchId { get; set; }
+ public long SubscriptionId { get; set; }
///
/// Идентификатор владельца матча
///
- public long MatchUserId { get; set; }
+ public long SubscriptionUserId { get; set; }
///
/// Username чата
diff --git a/src/Nocr.TextMatcher.Contracts/Nocr.TextMatcher.Contracts.csproj b/src/Nocr.TextMatcher.Contracts/Nocr.TextMatcher.Contracts.csproj
new file mode 100644
index 0000000..ae01cf7
--- /dev/null
+++ b/src/Nocr.TextMatcher.Contracts/Nocr.TextMatcher.Contracts.csproj
@@ -0,0 +1,7 @@
+
+
+
+ true
+
+
+
diff --git a/src/Nocr.TextMatcher.Api.Contracts/TextMatches/TextMatchRule.cs b/src/Nocr.TextMatcher.Contracts/TextSubscriptionRule.cs
similarity index 65%
rename from src/Nocr.TextMatcher.Api.Contracts/TextMatches/TextMatchRule.cs
rename to src/Nocr.TextMatcher.Contracts/TextSubscriptionRule.cs
index 28666c7..70273ba 100644
--- a/src/Nocr.TextMatcher.Api.Contracts/TextMatches/TextMatchRule.cs
+++ b/src/Nocr.TextMatcher.Contracts/TextSubscriptionRule.cs
@@ -1,6 +1,6 @@
-namespace Nocr.TextMatcher.Api.Contracts.TextMatches;
+namespace Nocr.TextMatcher.Contracts;
-public enum TextMatchRule
+public enum TextSubscriptionRule
{
// Substring
Full = 1,
diff --git a/src/Nocr.TextMatcher.Core/Options/RebusRabbitMqOptions.cs b/src/Nocr.TextMatcher.Core/Options/RebusRabbitMqOptions.cs
index 2894977..e99f9d2 100644
--- a/src/Nocr.TextMatcher.Core/Options/RebusRabbitMqOptions.cs
+++ b/src/Nocr.TextMatcher.Core/Options/RebusRabbitMqOptions.cs
@@ -2,11 +2,28 @@ namespace Nocr.TextMatcher.Core.Options;
public sealed class RebusRabbitMqOptions
{
+ ///
+ /// Строка подключение
+ ///
public string ConnectionString { get; set; }
+ ///
+ /// Имя входящей очереди
+ ///
public string InputQueueName { get; set; }
+ ///
+ /// Имя direct exchange
+ ///
public string DirectExchangeName { get; set; }
+ ///
+ /// Имя topics exchange
+ ///
public string TopicsExchangeName { get; set; }
+
+ ///
+ /// Список подписок
+ ///
+ public string[] Subscriptions { get; set; } = Array.Empty();
}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.Domain/Nocr.TextMatcher.Domain.csproj b/src/Nocr.TextMatcher.Domain/Nocr.TextMatcher.Domain.csproj
new file mode 100644
index 0000000..2c71e7c
--- /dev/null
+++ b/src/Nocr.TextMatcher.Domain/Nocr.TextMatcher.Domain.csproj
@@ -0,0 +1,12 @@
+
+
+
+
+ false
+
+
+
+
+
+
+
diff --git a/src/Nocr.TextMatcher.AppServices/TextMatches/TextMatch.cs b/src/Nocr.TextMatcher.Domain/TextSubscriptions/TextSubscription.cs
similarity index 80%
rename from src/Nocr.TextMatcher.AppServices/TextMatches/TextMatch.cs
rename to src/Nocr.TextMatcher.Domain/TextSubscriptions/TextSubscription.cs
index 3d3b87c..c0a0ae6 100644
--- a/src/Nocr.TextMatcher.AppServices/TextMatches/TextMatch.cs
+++ b/src/Nocr.TextMatcher.Domain/TextSubscriptions/TextSubscription.cs
@@ -1,9 +1,9 @@
using System.Text.RegularExpressions;
-using Nocr.TextMatcher.Api.Contracts.TextMatches;
+using Nocr.TextMatcher.Contracts;
namespace Nocr.TextMatcher.AppServices.TextMatches;
-public sealed class TextMatch
+public sealed class TextSubscription
{
public long Id { get; set; }
@@ -13,16 +13,16 @@ public sealed class TextMatch
public string Template { get; private set; }
- public TextMatchRule Rule { get; private set; }
+ public TextSubscriptionRule Rule { get; private set; }
public bool Active { get; private set; }
public DateTimeOffset CreatedDateTime { get; private set; }
- private TextMatch(long userId,
+ private TextSubscription(long userId,
string chatUsername,
string template,
- TextMatchRule rule,
+ TextSubscriptionRule rule,
DateTimeOffset createdDateTime,
bool active)
{
@@ -34,10 +34,10 @@ public sealed class TextMatch
Active = active;
}
- public static TextMatch Initialize(long userId,
+ public static TextSubscription Initialize(long userId,
string chatUsername,
string template,
- TextMatchRule rule,
+ TextSubscriptionRule rule,
DateTimeOffset createdDateTime)
{
if (userId <= 0)
@@ -52,14 +52,14 @@ public sealed class TextMatch
if (chatUsername.StartsWith("@"))
throw new ArgumentException("Chat username should be without @", nameof(chatUsername));
- return new TextMatch(userId, chatUsername, template, rule, createdDateTime, true);
+ return new TextSubscription(userId, chatUsername, template, rule, createdDateTime, true);
}
public void Disable()
{
if (!Active)
{
- throw new InvalidOperationException("Failed to disable inactive match");
+ throw new InvalidOperationException("Failed to disable inactive subscription");
}
Active = false;
@@ -69,7 +69,7 @@ public sealed class TextMatch
{
if (Active)
{
- throw new InvalidOperationException("Failed to activate inactive match");
+ throw new InvalidOperationException("Failed to activate inactive subscription");
}
Active = true;
@@ -82,12 +82,12 @@ public sealed class TextMatch
switch (Rule)
{
- case TextMatchRule.Full:
+ case TextSubscriptionRule.Full:
return text.Contains(Template, StringComparison.OrdinalIgnoreCase);
- case TextMatchRule.AnyWord:
+ case TextSubscriptionRule.AnyWord:
var anyWords = Regex.Split(Template, @"\s+");
return anyWords.Any(word => text.Contains(word, StringComparison.OrdinalIgnoreCase));
- case TextMatchRule.AllWords:
+ case TextSubscriptionRule.AllWords:
var allWords = Regex.Split(Template, @"\s+");
return allWords.All(word => text.Contains(word, StringComparison.OrdinalIgnoreCase));
default:
diff --git a/src/Nocr.TextMatcher.Host/Controllers/TextMatchController.cs b/src/Nocr.TextMatcher.Host/Controllers/TextMatchController.cs
deleted file mode 100644
index bb05431..0000000
--- a/src/Nocr.TextMatcher.Host/Controllers/TextMatchController.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using Microsoft.AspNetCore.Mvc;
-using Nocr.TextMatcher.Api.Contracts;
-using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
-using Nocr.TextMatcher.Api.Contracts.TextMatches.Requests;
-using Nocr.TextMatcher.AppServices.TextMatches.Services;
-
-namespace Nocr.TextMatcher.Host.Controllers;
-
-[ApiController]
-[Route(WebRoutes.TextMatches.Path)]
-public class TextMatchController : ControllerBase
-{
- private readonly ITextMatchService _textMatchService;
-
- public TextMatchController(ITextMatchService textMatchService)
- {
- _textMatchService = textMatchService ?? throw new ArgumentNullException(nameof(textMatchService));
- }
-
- [HttpPost]
- public Task Create([FromBody] CreateTextMatchRequest request, CancellationToken cancellationToken = default)
- {
- return _textMatchService.Create(request.UserId, request.ChatUsername, request.Template, request.Rule, cancellationToken);
- }
-
- [HttpGet(WebRoutes.TextMatches.ById)]
- public Task 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> 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);
- }
-}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.Host/Controllers/TextSubscriptionsController.cs b/src/Nocr.TextMatcher.Host/Controllers/TextSubscriptionsController.cs
new file mode 100644
index 0000000..4257dab
--- /dev/null
+++ b/src/Nocr.TextMatcher.Host/Controllers/TextSubscriptionsController.cs
@@ -0,0 +1,57 @@
+using Microsoft.AspNetCore.Mvc;
+using Nocr.TextMatcher.Api.Contracts;
+using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
+using Nocr.TextMatcher.Api.Contracts.TextMatches.Requests;
+using Nocr.TextMatcher.AppServices.TextMatches.Services;
+
+namespace Nocr.TextMatcher.Host.Controllers;
+
+[ApiController]
+[Route(WebRoutes.TextSubscriptions.Path)]
+public class TextSubscriptionsController : ControllerBase
+{
+ private readonly ITextSubscriptionsService _textSubscriptionsService;
+
+ public TextSubscriptionsController(ITextSubscriptionsService textSubscriptionsService)
+ {
+ _textSubscriptionsService = textSubscriptionsService ?? throw new ArgumentNullException(nameof(textSubscriptionsService));
+ }
+
+ [HttpPost]
+ public Task Create([FromBody] CreateTextSubscriptionRequest request, CancellationToken cancellationToken = default)
+ {
+ return _textSubscriptionsService.Create(request.UserId, request.ChatUsername, request.Template, request.Rule, cancellationToken);
+ }
+
+ [HttpGet(WebRoutes.TextSubscriptions.ById)]
+ public Task GetById([FromRoute] long id, CancellationToken cancellationToken = default)
+ {
+ return _textSubscriptionsService.GetById(id, cancellationToken);
+ }
+
+
+ [HttpDelete(WebRoutes.TextSubscriptions.ById)]
+ public Task Delete([FromRoute] long id, CancellationToken cancellationToken = default)
+ {
+ return _textSubscriptionsService.Delete(id, cancellationToken);
+ }
+
+ [HttpGet(WebRoutes.TextSubscriptions.ByUserId)]
+ public Task> GetByUserId([FromRoute] long userId,
+ CancellationToken cancellationToken = default)
+ {
+ return _textSubscriptionsService.GetByUserId(userId, cancellationToken);
+ }
+
+ [HttpPatch(WebRoutes.TextSubscriptions.Activate)]
+ public Task Activate([FromRoute] long id, CancellationToken cancellationToken = default)
+ {
+ return _textSubscriptionsService.Activate(id, cancellationToken);
+ }
+
+ [HttpPatch(WebRoutes.TextSubscriptions.Disable)]
+ public Task Disable([FromRoute] long id, CancellationToken cancellationToken = default)
+ {
+ return _textSubscriptionsService.Disable(id, cancellationToken);
+ }
+}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.Host/Infrastructure/Startup.cs b/src/Nocr.TextMatcher.Host/Infrastructure/Startup.cs
index 9ce51d3..38cc9cb 100644
--- a/src/Nocr.TextMatcher.Host/Infrastructure/Startup.cs
+++ b/src/Nocr.TextMatcher.Host/Infrastructure/Startup.cs
@@ -1,7 +1,9 @@
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Nocr.TextMatcher.AppServices;
using Nocr.TextMatcher.Core.Dates;
using Nocr.TextMatcher.Core.Options;
+using Nocr.TextMatcher.Persistence;
using Rebus.Bus;
using Rebus.Config;
using Rebus.Routing.TypeBased;
@@ -28,6 +30,15 @@ public class Startup
services.AddSwaggerGen();
services.AddAppServices();
+ services.AddDbContext(
+ (ctx, context) =>
+ {
+ context.UseMySql(Configuration.GetConnectionString(nameof(TextMatcherContext)),
+ new MariaDbServerVersion(MariaDbServerVersion.LatestSupportedServerVersion),
+ builder => builder.MigrationsAssembly(typeof(TextMatcherContext).Assembly.FullName))
+ .UseLoggerFactory(ctx.GetRequiredService());
+ }
+ );
services.Configure(Configuration.GetSection(nameof(RebusRabbitMqOptions)));
services.AddRebus((builder, ctx) =>
@@ -54,7 +65,11 @@ public class Startup
app.UseRouting();
app.UseEndpoints(builder => builder.MapControllers());
+ var rabbitMqOptions = app.ApplicationServices.GetRequiredService>();
var bus = app.ApplicationServices.GetRequiredService();
- bus.Advanced.Topics.Subscribe("nocr.telegram.listener").GetAwaiter().GetResult();
+ foreach (var subscription in rabbitMqOptions.Value.Subscriptions)
+ {
+ bus.Advanced.Topics.Subscribe(subscription).GetAwaiter().GetResult();
+ }
}
}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.Host/Nocr.TextMatcher.Host.csproj b/src/Nocr.TextMatcher.Host/Nocr.TextMatcher.Host.csproj
index ba69f55..fe87c10 100644
--- a/src/Nocr.TextMatcher.Host/Nocr.TextMatcher.Host.csproj
+++ b/src/Nocr.TextMatcher.Host/Nocr.TextMatcher.Host.csproj
@@ -19,6 +19,7 @@
+
diff --git a/src/Nocr.TextMatcher.Host/appsettings.Development.json b/src/Nocr.TextMatcher.Host/appsettings.Development.json
index 2d26fac..5615168 100644
--- a/src/Nocr.TextMatcher.Host/appsettings.Development.json
+++ b/src/Nocr.TextMatcher.Host/appsettings.Development.json
@@ -11,5 +11,8 @@
},
"RebusRabbitMqOptions": {
"ConnectionString": "amqp://admin:admin@localhost:5672/"
+ },
+ "ConnectionStrings": {
+ "TextMatcherContext": "server=localhost;port=3306;database=nocr_text_matcher;uid=root;pwd=toor"
}
}
diff --git a/src/Nocr.TextMatcher.Host/appsettings.json b/src/Nocr.TextMatcher.Host/appsettings.json
index fd2a17d..1b55ccf 100644
--- a/src/Nocr.TextMatcher.Host/appsettings.json
+++ b/src/Nocr.TextMatcher.Host/appsettings.json
@@ -13,6 +13,9 @@
"RebusRabbitMqOptions": {
"InputQueueName": "nocr.text.matcher.queue",
"DirectExchangeName": "nocr.direct",
- "TopicsExchangeName": "nocr.topics"
+ "TopicsExchangeName": "nocr.topics",
+ "Subscriptions": [
+ "nocr.telegram.listener"
+ ]
}
}
diff --git a/src/Nocr.TextMatcher.Persistence/DesignTimeTextMatcherContextFactory.cs b/src/Nocr.TextMatcher.Persistence/DesignTimeTextMatcherContextFactory.cs
new file mode 100644
index 0000000..a419121
--- /dev/null
+++ b/src/Nocr.TextMatcher.Persistence/DesignTimeTextMatcherContextFactory.cs
@@ -0,0 +1,22 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Design;
+using Microsoft.Extensions.Configuration;
+
+namespace Nocr.TextMatcher.Persistence;
+
+public class DesignTimeTextMatcherContextFactory : IDesignTimeDbContextFactory
+{
+ public TextMatcherContext CreateDbContext(string[] args)
+ {
+ var optionsBuilder = new DbContextOptionsBuilder();
+ var configuration = new ConfigurationBuilder()
+ .AddJsonFile("appsettings.json")
+ .Build();
+
+ var connectionString = configuration.GetConnectionString("MariaLocal");
+ optionsBuilder.UseMySql(connectionString,
+ new MariaDbServerVersion(MariaDbServerVersion.LatestSupportedServerVersion));
+
+ return new TextMatcherContext(optionsBuilder.Options);
+ }
+}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.Persistence/Migrations/20240328201810_InitialMigration.Designer.cs b/src/Nocr.TextMatcher.Persistence/Migrations/20240328201810_InitialMigration.Designer.cs
new file mode 100644
index 0000000..e443aa6
--- /dev/null
+++ b/src/Nocr.TextMatcher.Persistence/Migrations/20240328201810_InitialMigration.Designer.cs
@@ -0,0 +1,65 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Nocr.TextMatcher.Persistence;
+
+#nullable disable
+
+namespace Nocr.TextMatcher.Persistence.Migrations
+{
+ [DbContext(typeof(TextMatcherContext))]
+ [Migration("20240328201810_InitialMigration")]
+ partial class InitialMigration
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
+
+ modelBuilder.Entity("Nocr.TextMatcher.AppServices.TextMatches.TextSubscription", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ChatUsername")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("varchar(1024)");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Rule")
+ .HasColumnType("int");
+
+ b.Property("Template")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("varchar(1024)");
+
+ b.Property("UserId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.ToTable("TextSubscriptions");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Nocr.TextMatcher.Persistence/Migrations/20240328201810_InitialMigration.cs b/src/Nocr.TextMatcher.Persistence/Migrations/20240328201810_InitialMigration.cs
new file mode 100644
index 0000000..7d7822b
--- /dev/null
+++ b/src/Nocr.TextMatcher.Persistence/Migrations/20240328201810_InitialMigration.cs
@@ -0,0 +1,47 @@
+using System;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Nocr.TextMatcher.Persistence.Migrations
+{
+ ///
+ public partial class InitialMigration : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterDatabase()
+ .Annotation("MySql:CharSet", "utf8mb4");
+
+ migrationBuilder.CreateTable(
+ name: "TextSubscriptions",
+ columns: table => new
+ {
+ Id = table.Column(type: "bigint", nullable: false)
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+ UserId = table.Column(type: "bigint", nullable: false),
+ ChatUsername = table.Column(type: "varchar(1024)", maxLength: 1024, nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ Template = table.Column(type: "varchar(1024)", maxLength: 1024, nullable: false)
+ .Annotation("MySql:CharSet", "utf8mb4"),
+ Rule = table.Column(type: "int", nullable: false),
+ Active = table.Column(type: "tinyint(1)", nullable: false),
+ CreatedDateTime = table.Column(type: "datetime(6)", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_TextSubscriptions", x => x.Id);
+ })
+ .Annotation("MySql:CharSet", "utf8mb4");
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "TextSubscriptions");
+ }
+ }
+}
diff --git a/src/Nocr.TextMatcher.Persistence/Migrations/TextMatcherContextModelSnapshot.cs b/src/Nocr.TextMatcher.Persistence/Migrations/TextMatcherContextModelSnapshot.cs
new file mode 100644
index 0000000..5dced80
--- /dev/null
+++ b/src/Nocr.TextMatcher.Persistence/Migrations/TextMatcherContextModelSnapshot.cs
@@ -0,0 +1,62 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Nocr.TextMatcher.Persistence;
+
+#nullable disable
+
+namespace Nocr.TextMatcher.Persistence.Migrations
+{
+ [DbContext(typeof(TextMatcherContext))]
+ partial class TextMatcherContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "8.0.3")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
+
+ modelBuilder.Entity("Nocr.TextMatcher.AppServices.TextMatches.TextSubscription", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ChatUsername")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("varchar(1024)");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Rule")
+ .HasColumnType("int");
+
+ b.Property("Template")
+ .IsRequired()
+ .HasMaxLength(1024)
+ .HasColumnType("varchar(1024)");
+
+ b.Property("UserId")
+ .HasColumnType("bigint");
+
+ b.HasKey("Id");
+
+ b.ToTable("TextSubscriptions");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/src/Nocr.TextMatcher.Persistence/Nocr.TextMatcher.Persistence.csproj b/src/Nocr.TextMatcher.Persistence/Nocr.TextMatcher.Persistence.csproj
new file mode 100644
index 0000000..4ccab86
--- /dev/null
+++ b/src/Nocr.TextMatcher.Persistence/Nocr.TextMatcher.Persistence.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Always
+
+
+
+
diff --git a/src/Nocr.TextMatcher.Persistence/TextMatcherContext.cs b/src/Nocr.TextMatcher.Persistence/TextMatcherContext.cs
new file mode 100644
index 0000000..150e604
--- /dev/null
+++ b/src/Nocr.TextMatcher.Persistence/TextMatcherContext.cs
@@ -0,0 +1,25 @@
+using Microsoft.EntityFrameworkCore;
+using Nocr.TextMatcher.AppServices.TextMatches;
+
+namespace Nocr.TextMatcher.Persistence;
+
+public class TextMatcherContext : DbContext
+{
+ public DbSet TextSubscriptions { get; set; }
+
+ public TextMatcherContext(DbContextOptions options)
+ : base(options)
+ {
+ }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.ApplyConfiguration(new TextSubscriptionConfiguration());
+
+ base.OnModelCreating(modelBuilder);
+ }
+}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.Persistence/TextSubscriptionConfiguration.cs b/src/Nocr.TextMatcher.Persistence/TextSubscriptionConfiguration.cs
new file mode 100644
index 0000000..6de47ec
--- /dev/null
+++ b/src/Nocr.TextMatcher.Persistence/TextSubscriptionConfiguration.cs
@@ -0,0 +1,15 @@
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+using Nocr.TextMatcher.AppServices.TextMatches;
+
+namespace Nocr.TextMatcher.Persistence;
+
+public class TextSubscriptionConfiguration : IEntityTypeConfiguration
+{
+ public void Configure(EntityTypeBuilder builder)
+ {
+ builder.HasKey(x => x.Id);
+ builder.Property(x=> x.ChatUsername).IsRequired().HasMaxLength(1024);
+ builder.Property(x => x.Template).IsRequired().HasMaxLength(1024);
+ }
+}
\ No newline at end of file
diff --git a/src/Nocr.TextMatcher.Persistence/appsettings.json b/src/Nocr.TextMatcher.Persistence/appsettings.json
new file mode 100644
index 0000000..78c0e88
--- /dev/null
+++ b/src/Nocr.TextMatcher.Persistence/appsettings.json
@@ -0,0 +1,5 @@
+{
+ "ConnectionStrings": {
+ "MariaLocal": "server=localhost;port=3306;database=nocr_text_matcher;uid=root;pwd=toor"
+ }
+}
\ No newline at end of file
diff --git a/tests/Nocr.TextMatcher.AppServices.UnitTests/TextMatchTests.cs b/tests/Nocr.TextMatcher.AppServices.UnitTests/TextSubscriptionTests.cs
similarity index 72%
rename from tests/Nocr.TextMatcher.AppServices.UnitTests/TextMatchTests.cs
rename to tests/Nocr.TextMatcher.AppServices.UnitTests/TextSubscriptionTests.cs
index 19928b4..11b0d74 100644
--- a/tests/Nocr.TextMatcher.AppServices.UnitTests/TextMatchTests.cs
+++ b/tests/Nocr.TextMatcher.AppServices.UnitTests/TextSubscriptionTests.cs
@@ -1,10 +1,10 @@
-using Nocr.TextMatcher.Api.Contracts.TextMatches;
using Nocr.TextMatcher.AppServices.TextMatches;
+using Nocr.TextMatcher.Contracts;
using Xunit;
namespace Nocr.TextMatcher.AppServices.UnitTests;
-public class TextMatchTests
+public class TextSubscriptionTests
{
private const long UserId = 1;
@@ -14,7 +14,7 @@ public class TextMatchTests
public void IsMatches_SameChatId_FullRule_MatchesText()
{
// Arrange
- var match = TextMatch.Initialize(UserId, "Барахолка", "велосипед", TextMatchRule.Full, CreatedDateTime);
+ var match = TextSubscription.Initialize(UserId, "Барахолка", "велосипед", TextSubscriptionRule.Full, CreatedDateTime);
var text = "Продам снежный велосипед 100 лари. Гудаури.";
// Act
@@ -28,7 +28,7 @@ public class TextMatchTests
public void IsMatches_SameChatId_AnyWord_MatchesText()
{
// Arrange
- var match = TextMatch.Initialize(UserId, "Барахолка", "iphone айфон", TextMatchRule.AnyWord,
+ var match = TextSubscription.Initialize(UserId, "Барахолка", "iphone айфон", TextSubscriptionRule.AnyWord,
CreatedDateTime);
var text = "Продам айфон велосипед 100 лари. Гудаури.";
@@ -43,7 +43,7 @@ public class TextMatchTests
public void IsMatches_SameChatId_AllWords_MatchesText()
{
// Arrange
- var match = TextMatch.Initialize(UserId, "Барахолка", "iphone айфон", TextMatchRule.AnyWord,
+ var match = TextSubscription.Initialize(UserId, "Барахолка", "iphone айфон", TextSubscriptionRule.AnyWord,
CreatedDateTime);
var text = "Гомарджоба. Продам iphone (айфон) 1000 лари. Гудаури.";
@@ -58,7 +58,7 @@ public class TextMatchTests
public void IsMatches_DifferentChatIdAndUserName_NotMatchesText()
{
// Arrange
- var match = TextMatch.Initialize(UserId, "Барахолка", "iphone", TextMatchRule.Full, CreatedDateTime);
+ var match = TextSubscription.Initialize(UserId, "Барахолка", "iphone", TextSubscriptionRule.Full, CreatedDateTime);
// Act
var result = match.IsMatches(string.Empty, "iphone");