DRAFT: nazarovsa/persistence (#2)
Reviewed-on: #2 Co-authored-by: Sergey Nazarov <insight.appdev@gmail.com> Co-committed-by: Sergey Nazarov <insight.appdev@gmail.com>
This commit is contained in:
parent
1f5cc40e54
commit
ced8c15efb
@ -24,8 +24,15 @@
|
|||||||
<PackageVersion Include="Rebus.Serilog" Version="8.0.0" />
|
<PackageVersion Include="Rebus.Serilog" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Microsoft">
|
<ItemGroup Label="Microsoft">
|
||||||
|
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="$(MicrosoftVersion)" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftVersion)" />
|
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftVersion)" />
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="$(MicrosoftVersion)" />
|
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="$(MicrosoftVersion)" />
|
||||||
|
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="$(MicrosoftVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup Label="EntityFramework">
|
||||||
|
<PackageVersion Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
|
||||||
|
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.3" />
|
||||||
|
<PackageVersion Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Tests">
|
<ItemGroup Label="Tests">
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
|
||||||
|
|||||||
@ -22,6 +22,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Tests", "_Tests", "{6E4D9F
|
|||||||
EndProject
|
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}"
|
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
|
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
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
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}.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.ActiveCfg = Release|Any CPU
|
||||||
{B721E055-84AF-44C6-973D-33241FD2EA7C}.Release|Any CPU.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{B721E055-84AF-44C6-973D-33241FD2EA7C} = {6E4D9F75-861F-4C00-A5C8-00D1BEE5A659}
|
{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
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@ -8,4 +8,8 @@
|
|||||||
<PackageReference Include="RestEase" />
|
<PackageReference Include="RestEase" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Nocr.TextMatcher.Contracts\Nocr.TextMatcher.Contracts.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
using Nocr.TextMatcher.Contracts;
|
||||||
|
|
||||||
namespace Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
|
namespace Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
|
||||||
|
|
||||||
public sealed class TextMatchData
|
public sealed class TextSubscriptionData
|
||||||
{
|
{
|
||||||
public long Id { get; set; }
|
public long Id { get; set; }
|
||||||
|
|
||||||
@ -27,7 +29,7 @@ public sealed class TextMatchData
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Тип матча
|
/// Тип матча
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TextMatchRule Rule { get; set; }
|
public TextSubscriptionRule Rule { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Дата создания
|
/// Дата создания
|
||||||
@ -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<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);
|
|
||||||
}
|
|
||||||
@ -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<long> Create([Body] CreateTextSubscriptionRequest request, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
[Get(WebRoutes.TextSubscriptions.ById)]
|
||||||
|
Task<TextSubscriptionData?> GetById([Path] long id, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
[Get(WebRoutes.TextSubscriptions.ByUserId)]
|
||||||
|
Task<TextSubscriptionData[]> 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);
|
||||||
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
|
using Nocr.TextMatcher.Contracts;
|
||||||
|
|
||||||
namespace Nocr.TextMatcher.Api.Contracts.TextMatches.Requests;
|
namespace Nocr.TextMatcher.Api.Contracts.TextMatches.Requests;
|
||||||
|
|
||||||
public class CreateTextMatchRequest
|
public class CreateTextSubscriptionRequest
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Идентификатор пользователя в системе
|
/// Идентификатор пользователя в системе
|
||||||
@ -20,5 +22,5 @@ public class CreateTextMatchRequest
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Тип совпадения
|
/// Тип совпадения
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TextMatchRule Rule { get; set; }
|
public TextSubscriptionRule Rule { get; set; }
|
||||||
}
|
}
|
||||||
@ -4,7 +4,7 @@ public static class WebRoutes
|
|||||||
{
|
{
|
||||||
public const string BasePath = "/api";
|
public const string BasePath = "/api";
|
||||||
|
|
||||||
public static class TextMatches
|
public static class TextSubscriptions
|
||||||
{
|
{
|
||||||
public const string Path = BasePath + "/" + "text-matches";
|
public const string Path = BasePath + "/" + "text-matches";
|
||||||
|
|
||||||
|
|||||||
11
src/Nocr.TextMatcher.AppServices/Constants.cs
Normal file
11
src/Nocr.TextMatcher.AppServices/Constants.cs
Normal file
@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,6 +15,8 @@
|
|||||||
<ProjectReference Include="..\Nocr.TextMatcher.Api.Contracts\Nocr.TextMatcher.Api.Contracts.csproj" />
|
<ProjectReference Include="..\Nocr.TextMatcher.Api.Contracts\Nocr.TextMatcher.Api.Contracts.csproj" />
|
||||||
<ProjectReference Include="..\Nocr.TextMatcher.Async.Api.Contracts\Nocr.TextMatcher.Async.Api.Contracts.csproj" />
|
<ProjectReference Include="..\Nocr.TextMatcher.Async.Api.Contracts\Nocr.TextMatcher.Async.Api.Contracts.csproj" />
|
||||||
<ProjectReference Include="..\Nocr.TextMatcher.Core\Nocr.TextMatcher.Core.csproj" />
|
<ProjectReference Include="..\Nocr.TextMatcher.Core\Nocr.TextMatcher.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\Nocr.TextMatcher.Persistence\Nocr.TextMatcher.Persistence.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Nocr.TextMatcher.AppServices.TextMatchers;
|
|
||||||
using Nocr.TextMatcher.AppServices.TextMatches.Repositories;
|
using Nocr.TextMatcher.AppServices.TextMatches.Repositories;
|
||||||
using Nocr.TextMatcher.AppServices.TextMatches.Services;
|
using Nocr.TextMatcher.AppServices.TextMatches.Services;
|
||||||
|
using Nocr.TextMatcher.AppServices.TextSubscriptions;
|
||||||
using Rebus.Config;
|
using Rebus.Config;
|
||||||
|
|
||||||
namespace Nocr.TextMatcher.AppServices;
|
namespace Nocr.TextMatcher.AppServices;
|
||||||
@ -15,8 +15,8 @@ public static class ServiceCollectionExtensions
|
|||||||
|
|
||||||
// Add registrations here
|
// Add registrations here
|
||||||
services.AddRebusHandler<MessageReceivedHandler>();
|
services.AddRebusHandler<MessageReceivedHandler>();
|
||||||
services.AddScoped<ITextMatchService, TextMatchService>();
|
services.AddScoped<ITextSubscriptionsService, TextSubscriptionsService>();
|
||||||
services.AddSingleton<ITextMatchRepository, InMemoryTextMatchRepository>();
|
services.AddScoped<ITextSubscriptionRepository, TextSubscriptionRepository>();
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
namespace Nocr.TextMatcher.AppServices.TextMatches.Repositories;
|
|
||||||
|
|
||||||
public interface ITextMatchRepository
|
|
||||||
{
|
|
||||||
Task<long> Create(TextMatch textMatch, CancellationToken cancellationToken = default);
|
|
||||||
|
|
||||||
Task Delete(long id, CancellationToken cancellationToken = default);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
namespace Nocr.TextMatcher.AppServices.TextMatches.Repositories;
|
||||||
|
|
||||||
|
public interface ITextSubscriptionRepository
|
||||||
|
{
|
||||||
|
Task<long> Create(TextSubscription textSubscription, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task Delete(long id, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<IReadOnlyCollection<TextSubscription>> Get(CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<IReadOnlyCollection<TextSubscription>> GetByUserId(long userId, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task<TextSubscription?> GetById(long id, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
|
Task Update(TextSubscription subscription, CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
@ -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<TextMatch> _textMatches = new List<TextMatch>();
|
|
||||||
|
|
||||||
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<long> 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<IReadOnlyCollection<TextMatch>> Get(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return Task.FromResult<IReadOnlyCollection<TextMatch>>(_textMatches);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<IReadOnlyCollection<TextMatch>> GetByUserId(long userId, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<long> 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<IReadOnlyCollection<TextSubscription>> Get(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await _db.TextSubscriptions.AsNoTracking().ToListAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyCollection<TextSubscription>> GetByUserId(long userId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await _db.TextSubscriptions.Where(x => x.UserId == userId).AsNoTracking().ToListAsync(cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TextSubscription?> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,14 +1,14 @@
|
|||||||
using Nocr.TextMatcher.Api.Contracts.TextMatches;
|
|
||||||
using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
|
using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
|
||||||
|
using Nocr.TextMatcher.Contracts;
|
||||||
|
|
||||||
namespace Nocr.TextMatcher.AppServices.TextMatches.Services;
|
namespace Nocr.TextMatcher.AppServices.TextMatches.Services;
|
||||||
|
|
||||||
public interface ITextMatchService
|
public interface ITextSubscriptionsService
|
||||||
{
|
{
|
||||||
Task<long> Create(long userId, string chatUsername, string template, TextMatchRule rule,
|
Task<long> Create(long userId, string chatUsername, string template, TextSubscriptionRule rule,
|
||||||
CancellationToken cancellationToken = default);
|
CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<TextMatchData?> GetById(long id, CancellationToken cancellationToken = default);
|
Task<TextSubscriptionData?> GetById(long id, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task Delete(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 Disable(long id, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<IReadOnlyCollection<TextMatchData>> Get(CancellationToken cancellationToken = default);
|
Task<IReadOnlyCollection<TextSubscriptionData>> Get(CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
Task<IReadOnlyCollection<TextMatchData>> GetByUserId(long userId, CancellationToken cancellationToken = default);
|
Task<IReadOnlyCollection<TextSubscriptionData>> GetByUserId(long userId, CancellationToken cancellationToken = default);
|
||||||
}
|
}
|
||||||
@ -1,19 +1,19 @@
|
|||||||
using Nocr.TextMatcher.Api.Contracts.TextMatches;
|
|
||||||
using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
|
using Nocr.TextMatcher.Api.Contracts.TextMatches.Dto;
|
||||||
using Nocr.TextMatcher.AppServices.TextMatches.Repositories;
|
using Nocr.TextMatcher.AppServices.TextMatches.Repositories;
|
||||||
using Nocr.TextMatcher.Async.Api.Contracts;
|
using Nocr.TextMatcher.Async.Api.Contracts;
|
||||||
|
using Nocr.TextMatcher.Contracts;
|
||||||
using Nocr.TextMatcher.Core.Dates;
|
using Nocr.TextMatcher.Core.Dates;
|
||||||
using Rebus.Bus;
|
using Rebus.Bus;
|
||||||
|
|
||||||
namespace Nocr.TextMatcher.AppServices.TextMatches.Services;
|
namespace Nocr.TextMatcher.AppServices.TextMatches.Services;
|
||||||
|
|
||||||
public sealed class TextMatchService : ITextMatchService
|
public sealed class TextSubscriptionsService : ITextSubscriptionsService
|
||||||
{
|
{
|
||||||
private readonly IBus _bus;
|
private readonly IBus _bus;
|
||||||
private readonly ITextMatchRepository _repository;
|
private readonly ITextSubscriptionRepository _repository;
|
||||||
private readonly ICurrentDateProvider _dateProvider;
|
private readonly ICurrentDateProvider _dateProvider;
|
||||||
|
|
||||||
public TextMatchService(IBus bus, ITextMatchRepository repository,
|
public TextSubscriptionsService(IBus bus, ITextSubscriptionRepository repository,
|
||||||
ICurrentDateProvider dateProvider)
|
ICurrentDateProvider dateProvider)
|
||||||
{
|
{
|
||||||
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
|
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
|
||||||
@ -21,24 +21,23 @@ public sealed class TextMatchService : ITextMatchService
|
|||||||
_dateProvider = dateProvider ?? throw new ArgumentNullException(nameof(dateProvider));
|
_dateProvider = dateProvider ?? throw new ArgumentNullException(nameof(dateProvider));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<long> Create(long userId, string chatUsername, string template, TextMatchRule rule,
|
public async Task<long> Create(long userId, string chatUsername, string template, TextSubscriptionRule rule,
|
||||||
CancellationToken cancellationToken = default)
|
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);
|
await _repository.Create(textMatch, cancellationToken);
|
||||||
|
|
||||||
var @event = new TextMatchCreated
|
var @event = new TextSubscriptionCreated
|
||||||
{
|
{
|
||||||
ChatUsername = textMatch.ChatUsername
|
ChatUsername = textMatch.ChatUsername
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO:
|
await _bus.Advanced.Topics.Publish(Constants.RoutingKeys.Subscriptions, @event);
|
||||||
await _bus.Advanced.Topics.Publish("nocr.text.matcher.matches", @event);
|
|
||||||
|
|
||||||
return textMatch.Id;
|
return textMatch.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TextMatchData?> GetById(long id, CancellationToken cancellationToken)
|
public async Task<TextSubscriptionData?> GetById(long id, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var textMatch = await _repository.GetById(id, cancellationToken);
|
var textMatch = await _repository.GetById(id, cancellationToken);
|
||||||
if (textMatch == null)
|
if (textMatch == null)
|
||||||
@ -78,31 +77,31 @@ public sealed class TextMatchService : ITextMatchService
|
|||||||
await _repository.Update(textMatch, cancellationToken);
|
await _repository.Update(textMatch, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyCollection<TextMatchData>> Get(CancellationToken cancellationToken = default)
|
public async Task<IReadOnlyCollection<TextSubscriptionData>> Get(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var matches = await _repository.Get(cancellationToken);
|
var matches = await _repository.Get(cancellationToken);
|
||||||
|
|
||||||
return matches.Select(MapToTextMatchData).ToArray();
|
return matches.Select(MapToTextMatchData).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyCollection<TextMatchData>> GetByUserId(long userId,
|
public async Task<IReadOnlyCollection<TextSubscriptionData>> GetByUserId(long userId,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var matches = await _repository.GetByUserId(userId, cancellationToken);
|
var matches = await _repository.GetByUserId(userId, cancellationToken);
|
||||||
return matches.Select(MapToTextMatchData).ToArray();
|
return matches.Select(MapToTextMatchData).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextMatchData MapToTextMatchData(TextMatch textMatch)
|
private TextSubscriptionData MapToTextMatchData(TextSubscription textSubscription)
|
||||||
{
|
{
|
||||||
return new TextMatchData
|
return new TextSubscriptionData
|
||||||
{
|
{
|
||||||
Id = textMatch.Id,
|
Id = textSubscription.Id,
|
||||||
ChatUsername = textMatch.ChatUsername,
|
ChatUsername = textSubscription.ChatUsername,
|
||||||
Active = textMatch.Active,
|
Active = textSubscription.Active,
|
||||||
Template = textMatch.Template,
|
Template = textSubscription.Template,
|
||||||
UserId = textMatch.UserId,
|
UserId = textSubscription.UserId,
|
||||||
Rule = textMatch.Rule,
|
Rule = textSubscription.Rule,
|
||||||
CreatedDateTime = textMatch.CreatedDateTime
|
CreatedDateTime = textSubscription.CreatedDateTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,23 +6,23 @@ using Nocr.TextMatcher.Core.Dates;
|
|||||||
using Rebus.Bus;
|
using Rebus.Bus;
|
||||||
using Rebus.Handlers;
|
using Rebus.Handlers;
|
||||||
|
|
||||||
namespace Nocr.TextMatcher.AppServices.TextMatchers;
|
namespace Nocr.TextMatcher.AppServices.TextSubscriptions;
|
||||||
|
|
||||||
public sealed class MessageReceivedHandler : IHandleMessages<MessageReceived>
|
public sealed class MessageReceivedHandler : IHandleMessages<MessageReceived>
|
||||||
{
|
{
|
||||||
private readonly ILogger<MessageReceivedHandler> _logger;
|
private readonly ILogger<MessageReceivedHandler> _logger;
|
||||||
private readonly IBus _bus;
|
private readonly IBus _bus;
|
||||||
private readonly ITextMatchRepository _textMatchService;
|
private readonly ITextSubscriptionRepository _textSubscriptionService;
|
||||||
private readonly ICurrentDateProvider _dateProvider;
|
private readonly ICurrentDateProvider _dateProvider;
|
||||||
|
|
||||||
public MessageReceivedHandler(ILogger<MessageReceivedHandler> logger,
|
public MessageReceivedHandler(ILogger<MessageReceivedHandler> logger,
|
||||||
IBus bus,
|
IBus bus,
|
||||||
ITextMatchRepository textMatchRepository,
|
ITextSubscriptionRepository textSubscriptionRepository,
|
||||||
ICurrentDateProvider dateProvider)
|
ICurrentDateProvider dateProvider)
|
||||||
{
|
{
|
||||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||||
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
|
_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));
|
_dateProvider = dateProvider ?? throw new ArgumentNullException(nameof(dateProvider));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,17 +30,17 @@ public sealed class MessageReceivedHandler : IHandleMessages<MessageReceived>
|
|||||||
{
|
{
|
||||||
_logger.LogInformation("Received message: {@Message}", message);
|
_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))
|
foreach (var match in matches.Where(x => x.Active))
|
||||||
{
|
{
|
||||||
if (match.IsMatches(message.ChatUsername, message.Text))
|
if (match.IsMatches(message.ChatUsername, message.Text))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Message {@Message} matched {@Match}", message, match);
|
_logger.LogInformation("Message {@Message} matched {@Match}", message, match);
|
||||||
var @event = new TextMatchMatched
|
var @event = new TextSubscriptionMatched
|
||||||
{
|
{
|
||||||
MatchId = match.Id,
|
SubscriptionId = match.Id,
|
||||||
MatchUserId = match.UserId,
|
SubscriptionUserId = match.UserId,
|
||||||
ChatUsername = match.ChatUsername,
|
ChatUsername = match.ChatUsername,
|
||||||
Rule = (int)match.Rule,
|
Rule = (int)match.Rule,
|
||||||
Template = match.Template,
|
Template = match.Template,
|
||||||
@ -49,9 +49,8 @@ public sealed class MessageReceivedHandler : IHandleMessages<MessageReceived>
|
|||||||
OccuredDateTime = message.OccuredDateTime,
|
OccuredDateTime = message.OccuredDateTime,
|
||||||
PublishedDateTime = _dateProvider.UtcNow
|
PublishedDateTime = _dateProvider.UtcNow
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO:
|
await _bus.Advanced.Topics.Publish(Constants.RoutingKeys.MatchedSubscriptions, @event);
|
||||||
await _bus.Advanced.Topics.Publish("nocr.text.matcher.matched", @event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Nocr.TextMatcher.Async.Api.Contracts;
|
namespace Nocr.TextMatcher.Async.Api.Contracts;
|
||||||
|
|
||||||
public class TextMatchCreated : IEvent
|
public class TextSubscriptionCreated : IEvent
|
||||||
{
|
{
|
||||||
public Guid Id => Guid.NewGuid();
|
public Guid Id => Guid.NewGuid();
|
||||||
|
|
||||||
@ -1,18 +1,18 @@
|
|||||||
namespace Nocr.TextMatcher.Async.Api.Contracts;
|
namespace Nocr.TextMatcher.Async.Api.Contracts;
|
||||||
|
|
||||||
public class TextMatchMatched : IEvent
|
public class TextSubscriptionMatched : IEvent
|
||||||
{
|
{
|
||||||
public Guid Id => Guid.NewGuid();
|
public Guid Id => Guid.NewGuid();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Идентификатор матча
|
/// Идентификатор матча
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public long MatchId { get; set; }
|
public long SubscriptionId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Идентификатор владельца матча
|
/// Идентификатор владельца матча
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public long MatchUserId { get; set; }
|
public long SubscriptionUserId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Username чата
|
/// Username чата
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<IsPackable>true</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Nocr.TextMatcher.Api.Contracts.TextMatches;
|
namespace Nocr.TextMatcher.Contracts;
|
||||||
|
|
||||||
public enum TextMatchRule
|
public enum TextSubscriptionRule
|
||||||
{
|
{
|
||||||
// Substring
|
// Substring
|
||||||
Full = 1,
|
Full = 1,
|
||||||
@ -2,11 +2,28 @@ namespace Nocr.TextMatcher.Core.Options;
|
|||||||
|
|
||||||
public sealed class RebusRabbitMqOptions
|
public sealed class RebusRabbitMqOptions
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Строка подключение
|
||||||
|
/// </summary>
|
||||||
public string ConnectionString { get; set; }
|
public string ConnectionString { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Имя входящей очереди
|
||||||
|
/// </summary>
|
||||||
public string InputQueueName { get; set; }
|
public string InputQueueName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Имя direct exchange
|
||||||
|
/// </summary>
|
||||||
public string DirectExchangeName { get; set; }
|
public string DirectExchangeName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Имя topics exchange
|
||||||
|
/// </summary>
|
||||||
public string TopicsExchangeName { get; set; }
|
public string TopicsExchangeName { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Список подписок
|
||||||
|
/// </summary>
|
||||||
|
public string[] Subscriptions { get; set; } = Array.Empty<string>();
|
||||||
}
|
}
|
||||||
12
src/Nocr.TextMatcher.Domain/Nocr.TextMatcher.Domain.csproj
Normal file
12
src/Nocr.TextMatcher.Domain/Nocr.TextMatcher.Domain.csproj
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Nocr.TextMatcher.Contracts\Nocr.TextMatcher.Contracts.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
@ -1,9 +1,9 @@
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Nocr.TextMatcher.Api.Contracts.TextMatches;
|
using Nocr.TextMatcher.Contracts;
|
||||||
|
|
||||||
namespace Nocr.TextMatcher.AppServices.TextMatches;
|
namespace Nocr.TextMatcher.AppServices.TextMatches;
|
||||||
|
|
||||||
public sealed class TextMatch
|
public sealed class TextSubscription
|
||||||
{
|
{
|
||||||
public long Id { get; set; }
|
public long Id { get; set; }
|
||||||
|
|
||||||
@ -13,16 +13,16 @@ public sealed class TextMatch
|
|||||||
|
|
||||||
public string Template { get; private set; }
|
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 bool Active { get; private set; }
|
||||||
|
|
||||||
public DateTimeOffset CreatedDateTime { get; private set; }
|
public DateTimeOffset CreatedDateTime { get; private set; }
|
||||||
|
|
||||||
private TextMatch(long userId,
|
private TextSubscription(long userId,
|
||||||
string chatUsername,
|
string chatUsername,
|
||||||
string template,
|
string template,
|
||||||
TextMatchRule rule,
|
TextSubscriptionRule rule,
|
||||||
DateTimeOffset createdDateTime,
|
DateTimeOffset createdDateTime,
|
||||||
bool active)
|
bool active)
|
||||||
{
|
{
|
||||||
@ -34,10 +34,10 @@ public sealed class TextMatch
|
|||||||
Active = active;
|
Active = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TextMatch Initialize(long userId,
|
public static TextSubscription Initialize(long userId,
|
||||||
string chatUsername,
|
string chatUsername,
|
||||||
string template,
|
string template,
|
||||||
TextMatchRule rule,
|
TextSubscriptionRule rule,
|
||||||
DateTimeOffset createdDateTime)
|
DateTimeOffset createdDateTime)
|
||||||
{
|
{
|
||||||
if (userId <= 0)
|
if (userId <= 0)
|
||||||
@ -52,14 +52,14 @@ public sealed class TextMatch
|
|||||||
if (chatUsername.StartsWith("@"))
|
if (chatUsername.StartsWith("@"))
|
||||||
throw new ArgumentException("Chat username should be without @", nameof(chatUsername));
|
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()
|
public void Disable()
|
||||||
{
|
{
|
||||||
if (!Active)
|
if (!Active)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Failed to disable inactive match");
|
throw new InvalidOperationException("Failed to disable inactive subscription");
|
||||||
}
|
}
|
||||||
|
|
||||||
Active = false;
|
Active = false;
|
||||||
@ -69,7 +69,7 @@ public sealed class TextMatch
|
|||||||
{
|
{
|
||||||
if (Active)
|
if (Active)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Failed to activate inactive match");
|
throw new InvalidOperationException("Failed to activate inactive subscription");
|
||||||
}
|
}
|
||||||
|
|
||||||
Active = true;
|
Active = true;
|
||||||
@ -82,12 +82,12 @@ public sealed class TextMatch
|
|||||||
|
|
||||||
switch (Rule)
|
switch (Rule)
|
||||||
{
|
{
|
||||||
case TextMatchRule.Full:
|
case TextSubscriptionRule.Full:
|
||||||
return text.Contains(Template, StringComparison.OrdinalIgnoreCase);
|
return text.Contains(Template, StringComparison.OrdinalIgnoreCase);
|
||||||
case TextMatchRule.AnyWord:
|
case TextSubscriptionRule.AnyWord:
|
||||||
var anyWords = Regex.Split(Template, @"\s+");
|
var anyWords = Regex.Split(Template, @"\s+");
|
||||||
return anyWords.Any(word => text.Contains(word, StringComparison.OrdinalIgnoreCase));
|
return anyWords.Any(word => text.Contains(word, StringComparison.OrdinalIgnoreCase));
|
||||||
case TextMatchRule.AllWords:
|
case TextSubscriptionRule.AllWords:
|
||||||
var allWords = Regex.Split(Template, @"\s+");
|
var allWords = Regex.Split(Template, @"\s+");
|
||||||
return allWords.All(word => text.Contains(word, StringComparison.OrdinalIgnoreCase));
|
return allWords.All(word => text.Contains(word, StringComparison.OrdinalIgnoreCase));
|
||||||
default:
|
default:
|
||||||
@ -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<long> 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<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)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<long> 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<TextSubscriptionData?> 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<IReadOnlyCollection<TextSubscriptionData>> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,9 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Nocr.TextMatcher.AppServices;
|
using Nocr.TextMatcher.AppServices;
|
||||||
using Nocr.TextMatcher.Core.Dates;
|
using Nocr.TextMatcher.Core.Dates;
|
||||||
using Nocr.TextMatcher.Core.Options;
|
using Nocr.TextMatcher.Core.Options;
|
||||||
|
using Nocr.TextMatcher.Persistence;
|
||||||
using Rebus.Bus;
|
using Rebus.Bus;
|
||||||
using Rebus.Config;
|
using Rebus.Config;
|
||||||
using Rebus.Routing.TypeBased;
|
using Rebus.Routing.TypeBased;
|
||||||
@ -28,6 +30,15 @@ public class Startup
|
|||||||
services.AddSwaggerGen();
|
services.AddSwaggerGen();
|
||||||
|
|
||||||
services.AddAppServices();
|
services.AddAppServices();
|
||||||
|
services.AddDbContext<TextMatcherContext>(
|
||||||
|
(ctx, context) =>
|
||||||
|
{
|
||||||
|
context.UseMySql(Configuration.GetConnectionString(nameof(TextMatcherContext)),
|
||||||
|
new MariaDbServerVersion(MariaDbServerVersion.LatestSupportedServerVersion),
|
||||||
|
builder => builder.MigrationsAssembly(typeof(TextMatcherContext).Assembly.FullName))
|
||||||
|
.UseLoggerFactory(ctx.GetRequiredService<ILoggerFactory>());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
services.Configure<RebusRabbitMqOptions>(Configuration.GetSection(nameof(RebusRabbitMqOptions)));
|
services.Configure<RebusRabbitMqOptions>(Configuration.GetSection(nameof(RebusRabbitMqOptions)));
|
||||||
services.AddRebus((builder, ctx) =>
|
services.AddRebus((builder, ctx) =>
|
||||||
@ -54,7 +65,11 @@ public class Startup
|
|||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
app.UseEndpoints(builder => builder.MapControllers());
|
app.UseEndpoints(builder => builder.MapControllers());
|
||||||
|
|
||||||
|
var rabbitMqOptions = app.ApplicationServices.GetRequiredService<IOptions<RebusRabbitMqOptions>>();
|
||||||
var bus = app.ApplicationServices.GetRequiredService<IBus>();
|
var bus = app.ApplicationServices.GetRequiredService<IBus>();
|
||||||
bus.Advanced.Topics.Subscribe("nocr.telegram.listener").GetAwaiter().GetResult();
|
foreach (var subscription in rabbitMqOptions.Value.Subscriptions)
|
||||||
|
{
|
||||||
|
bus.Advanced.Topics.Subscribe(subscription).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,6 +19,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Nocr.TextMatcher.Api.Contracts\Nocr.TextMatcher.Api.Contracts.csproj" />
|
<ProjectReference Include="..\Nocr.TextMatcher.Api.Contracts\Nocr.TextMatcher.Api.Contracts.csproj" />
|
||||||
<ProjectReference Include="..\Nocr.TextMatcher.AppServices\Nocr.TextMatcher.AppServices.csproj" />
|
<ProjectReference Include="..\Nocr.TextMatcher.AppServices\Nocr.TextMatcher.AppServices.csproj" />
|
||||||
|
<ProjectReference Include="..\Nocr.TextMatcher.Persistence\Nocr.TextMatcher.Persistence.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -11,5 +11,8 @@
|
|||||||
},
|
},
|
||||||
"RebusRabbitMqOptions": {
|
"RebusRabbitMqOptions": {
|
||||||
"ConnectionString": "amqp://admin:admin@localhost:5672/"
|
"ConnectionString": "amqp://admin:admin@localhost:5672/"
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"TextMatcherContext": "server=localhost;port=3306;database=nocr_text_matcher;uid=root;pwd=toor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,9 @@
|
|||||||
"RebusRabbitMqOptions": {
|
"RebusRabbitMqOptions": {
|
||||||
"InputQueueName": "nocr.text.matcher.queue",
|
"InputQueueName": "nocr.text.matcher.queue",
|
||||||
"DirectExchangeName": "nocr.direct",
|
"DirectExchangeName": "nocr.direct",
|
||||||
"TopicsExchangeName": "nocr.topics"
|
"TopicsExchangeName": "nocr.topics",
|
||||||
|
"Subscriptions": [
|
||||||
|
"nocr.telegram.listener"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Design;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Nocr.TextMatcher.Persistence;
|
||||||
|
|
||||||
|
public class DesignTimeTextMatcherContextFactory : IDesignTimeDbContextFactory<TextMatcherContext>
|
||||||
|
{
|
||||||
|
public TextMatcherContext CreateDbContext(string[] args)
|
||||||
|
{
|
||||||
|
var optionsBuilder = new DbContextOptionsBuilder<TextMatcherContext>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/Nocr.TextMatcher.Persistence/Migrations/20240328201810_InitialMigration.Designer.cs
generated
Normal file
65
src/Nocr.TextMatcher.Persistence/Migrations/20240328201810_InitialMigration.Designer.cs
generated
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
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
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
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<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("ChatUsername")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("varchar(1024)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedDateTime")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<int>("Rule")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Template")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("varchar(1024)");
|
||||||
|
|
||||||
|
b.Property<long>("UserId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("TextSubscriptions");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Nocr.TextMatcher.Persistence.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class InitialMigration : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterDatabase()
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "TextSubscriptions",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(type: "bigint", nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
UserId = table.Column<long>(type: "bigint", nullable: false),
|
||||||
|
ChatUsername = table.Column<string>(type: "varchar(1024)", maxLength: 1024, nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Template = table.Column<string>(type: "varchar(1024)", maxLength: 1024, nullable: false)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||||
|
Rule = table.Column<int>(type: "int", nullable: false),
|
||||||
|
Active = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||||
|
CreatedDateTime = table.Column<DateTimeOffset>(type: "datetime(6)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_TextSubscriptions", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "TextSubscriptions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
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<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<bool>("Active")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<string>("ChatUsername")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("varchar(1024)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedDateTime")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<int>("Rule")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Template")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(1024)
|
||||||
|
.HasColumnType("varchar(1024)");
|
||||||
|
|
||||||
|
b.Property<long>("UserId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("TextSubscriptions");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
|
||||||
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Nocr.TextMatcher.Domain\Nocr.TextMatcher.Domain.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="appsettings.json" />
|
||||||
|
<Content Include="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
25
src/Nocr.TextMatcher.Persistence/TextMatcherContext.cs
Normal file
25
src/Nocr.TextMatcher.Persistence/TextMatcherContext.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Nocr.TextMatcher.AppServices.TextMatches;
|
||||||
|
|
||||||
|
namespace Nocr.TextMatcher.Persistence;
|
||||||
|
|
||||||
|
public class TextMatcherContext : DbContext
|
||||||
|
{
|
||||||
|
public DbSet<TextSubscription> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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<TextSubscription>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<TextSubscription> builder)
|
||||||
|
{
|
||||||
|
builder.HasKey(x => x.Id);
|
||||||
|
builder.Property(x=> x.ChatUsername).IsRequired().HasMaxLength(1024);
|
||||||
|
builder.Property(x => x.Template).IsRequired().HasMaxLength(1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/Nocr.TextMatcher.Persistence/appsettings.json
Normal file
5
src/Nocr.TextMatcher.Persistence/appsettings.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"MariaLocal": "server=localhost;port=3306;database=nocr_text_matcher;uid=root;pwd=toor"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
using Nocr.TextMatcher.Api.Contracts.TextMatches;
|
|
||||||
using Nocr.TextMatcher.AppServices.TextMatches;
|
using Nocr.TextMatcher.AppServices.TextMatches;
|
||||||
|
using Nocr.TextMatcher.Contracts;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Nocr.TextMatcher.AppServices.UnitTests;
|
namespace Nocr.TextMatcher.AppServices.UnitTests;
|
||||||
|
|
||||||
public class TextMatchTests
|
public class TextSubscriptionTests
|
||||||
{
|
{
|
||||||
private const long UserId = 1;
|
private const long UserId = 1;
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ public class TextMatchTests
|
|||||||
public void IsMatches_SameChatId_FullRule_MatchesText()
|
public void IsMatches_SameChatId_FullRule_MatchesText()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var match = TextMatch.Initialize(UserId, "Барахолка", "велосипед", TextMatchRule.Full, CreatedDateTime);
|
var match = TextSubscription.Initialize(UserId, "Барахолка", "велосипед", TextSubscriptionRule.Full, CreatedDateTime);
|
||||||
var text = "Продам снежный велосипед 100 лари. Гудаури.";
|
var text = "Продам снежный велосипед 100 лари. Гудаури.";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
@ -28,7 +28,7 @@ public class TextMatchTests
|
|||||||
public void IsMatches_SameChatId_AnyWord_MatchesText()
|
public void IsMatches_SameChatId_AnyWord_MatchesText()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var match = TextMatch.Initialize(UserId, "Барахолка", "iphone айфон", TextMatchRule.AnyWord,
|
var match = TextSubscription.Initialize(UserId, "Барахолка", "iphone айфон", TextSubscriptionRule.AnyWord,
|
||||||
CreatedDateTime);
|
CreatedDateTime);
|
||||||
var text = "Продам айфон велосипед 100 лари. Гудаури.";
|
var text = "Продам айфон велосипед 100 лари. Гудаури.";
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ public class TextMatchTests
|
|||||||
public void IsMatches_SameChatId_AllWords_MatchesText()
|
public void IsMatches_SameChatId_AllWords_MatchesText()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var match = TextMatch.Initialize(UserId, "Барахолка", "iphone айфон", TextMatchRule.AnyWord,
|
var match = TextSubscription.Initialize(UserId, "Барахолка", "iphone айфон", TextSubscriptionRule.AnyWord,
|
||||||
CreatedDateTime);
|
CreatedDateTime);
|
||||||
var text = "Гомарджоба. Продам iphone (айфон) 1000 лари. Гудаури.";
|
var text = "Гомарджоба. Продам iphone (айфон) 1000 лари. Гудаури.";
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ public class TextMatchTests
|
|||||||
public void IsMatches_DifferentChatIdAndUserName_NotMatchesText()
|
public void IsMatches_DifferentChatIdAndUserName_NotMatchesText()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var match = TextMatch.Initialize(UserId, "Барахолка", "iphone", TextMatchRule.Full, CreatedDateTime);
|
var match = TextSubscription.Initialize(UserId, "Барахолка", "iphone", TextSubscriptionRule.Full, CreatedDateTime);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = match.IsMatches(string.Empty, "iphone");
|
var result = match.IsMatches(string.Empty, "iphone");
|
||||||
Loading…
Reference in New Issue
Block a user