feat(cv-search-job): replace MyAiDbContext+ITemplateService with IEmailTemplateService
- Add ProjectReference to email-api-data; remove myai-data reference
- Program.cs: register EmailApiDbContext (no migrate), IEmailTemplateRepository
(scoped), IEmailTemplateService (singleton); remove MyAiDbContext +
ITemplateService registrations and their migration call
- CvSearchEmailSender: inject IEmailTemplateService; replace
_config["Contact:ToEmail"] with GetOperatorCopy("email.search-results.subject")
for operator copy logic; remove IConfiguration injection
- docker-compose: remove Contact__ToEmail from cv-search-job service block;
add Database__* env vars to email-api service (needed for EmailApiDbContext)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,10 @@ using CvMatcher.Models.Settings;
|
|||||||
using CvSearch.Data;
|
using CvSearch.Data;
|
||||||
using CvSearchJob.Clients;
|
using CvSearchJob.Clients;
|
||||||
using CvSearchJob.Services;
|
using CvSearchJob.Services;
|
||||||
|
using EmailApi.Data;
|
||||||
|
using EmailApi.Data.Repositories;
|
||||||
|
using EmailApi.Data.Repositories.Contracts;
|
||||||
|
using EmailApi.Data.Services;
|
||||||
using EmailApi.Models.Clients;
|
using EmailApi.Models.Clients;
|
||||||
using CvSearchJob.Tasks;
|
using CvSearchJob.Tasks;
|
||||||
using JobScheduler.Scheduling;
|
using JobScheduler.Scheduling;
|
||||||
@@ -10,8 +14,6 @@ using JobScheduler.Tasks;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using MyAi.Data;
|
|
||||||
using MyAi.Data.Services;
|
|
||||||
using Refit;
|
using Refit;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using Common.Settings;
|
using Common.Settings;
|
||||||
@@ -54,16 +56,18 @@ try
|
|||||||
client.DefaultRequestHeaders.Add("X-Internal-Api-Key", key);
|
client.DefaultRequestHeaders.Add("X-Internal-Api-Key", key);
|
||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddDbContext<MyAiDbContext>(options =>
|
builder.Services.AddDbContext<EmailApiDbContext>(options =>
|
||||||
{
|
{
|
||||||
var connectionString = builder.Services.GetConfiguredDbConnectionString(builder.Configuration);
|
var connectionString = builder.Services.GetConfiguredDbConnectionString(builder.Configuration);
|
||||||
options.UseSqlServer(connectionString, sql =>
|
options.UseSqlServer(connectionString, sql =>
|
||||||
{
|
{
|
||||||
sql.MigrationsAssembly("myai-data");
|
sql.MigrationsHistoryTable(EmailApiDbContext.MigrationTableName, EmailApiDbContext.SchemaName);
|
||||||
sql.MigrationsHistoryTable(MyAiDbContext.MigrationTableName, MyAiDbContext.SchemaName);
|
sql.MigrationsAssembly("email-api-data");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
builder.Services.AddSingleton<ITemplateService, DbTemplateService>();
|
|
||||||
|
builder.Services.AddScoped<IEmailTemplateRepository, EfEmailTemplateRepository>();
|
||||||
|
builder.Services.AddSingleton<IEmailTemplateService, EmailTemplateService>();
|
||||||
|
|
||||||
builder.Services.AddRefitClient<IEmailApiClient>()
|
builder.Services.AddRefitClient<IEmailApiClient>()
|
||||||
.ConfigureHttpClient((sp, client) =>
|
.ConfigureHttpClient((sp, client) =>
|
||||||
@@ -98,11 +102,6 @@ try
|
|||||||
var db = scope.ServiceProvider.GetRequiredService<CvSearchDbContext>();
|
var db = scope.ServiceProvider.GetRequiredService<CvSearchDbContext>();
|
||||||
db.Database.Migrate();
|
db.Database.Migrate();
|
||||||
}
|
}
|
||||||
using (var scope = host.Services.CreateScope())
|
|
||||||
{
|
|
||||||
var db = scope.ServiceProvider.GetRequiredService<MyAiDbContext>();
|
|
||||||
db.Database.Migrate();
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.Information("{Service} startup complete. Background scheduler is running.", ServiceName);
|
Log.Information("{Service} startup complete. Background scheduler is running.", ServiceName);
|
||||||
await host.RunAsync();
|
await host.RunAsync();
|
||||||
|
|||||||
@@ -1,29 +1,25 @@
|
|||||||
using CvMatcher.Models.Responses;
|
using CvMatcher.Models.Responses;
|
||||||
using CvSearch.Data.Entities;
|
using CvSearch.Data.Entities;
|
||||||
|
using EmailApi.Data.Services;
|
||||||
using EmailApi.Models.Clients;
|
using EmailApi.Models.Clients;
|
||||||
using EmailApi.Models.Requests;
|
using EmailApi.Models.Requests;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using MyAi.Data.Services;
|
|
||||||
|
|
||||||
namespace CvSearchJob.Services;
|
namespace CvSearchJob.Services;
|
||||||
|
|
||||||
public sealed class CvSearchEmailSender
|
public sealed class CvSearchEmailSender
|
||||||
{
|
{
|
||||||
private readonly IEmailApiClient _emailApi;
|
private readonly IEmailApiClient _emailApi;
|
||||||
private readonly ITemplateService _templates;
|
private readonly IEmailTemplateService _emailTemplates;
|
||||||
private readonly IConfiguration _config;
|
|
||||||
private readonly ILogger<CvSearchEmailSender> _logger;
|
private readonly ILogger<CvSearchEmailSender> _logger;
|
||||||
|
|
||||||
public CvSearchEmailSender(
|
public CvSearchEmailSender(
|
||||||
IEmailApiClient emailApi,
|
IEmailApiClient emailApi,
|
||||||
ITemplateService templates,
|
IEmailTemplateService emailTemplates,
|
||||||
IConfiguration config,
|
|
||||||
ILogger<CvSearchEmailSender> logger)
|
ILogger<CvSearchEmailSender> logger)
|
||||||
{
|
{
|
||||||
_emailApi = emailApi;
|
_emailApi = emailApi;
|
||||||
_templates = templates;
|
_emailTemplates = emailTemplates;
|
||||||
_config = config;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,18 +30,18 @@ public sealed class CvSearchEmailSender
|
|||||||
string language,
|
string language,
|
||||||
CancellationToken ct)
|
CancellationToken ct)
|
||||||
{
|
{
|
||||||
var contactToEmail = _config["Contact:ToEmail"];
|
var operatorCopy = _emailTemplates.GetOperatorCopy("email.search-results.subject", language);
|
||||||
|
|
||||||
var recipients = new List<string>();
|
var recipients = new List<string>();
|
||||||
if (!string.IsNullOrWhiteSpace(toEmail)) recipients.Add(toEmail);
|
if (!string.IsNullOrWhiteSpace(toEmail)) recipients.Add(toEmail);
|
||||||
if (!string.IsNullOrWhiteSpace(contactToEmail) &&
|
if (!string.IsNullOrWhiteSpace(operatorCopy) &&
|
||||||
!recipients.Any(r => string.Equals(r, contactToEmail, StringComparison.OrdinalIgnoreCase)))
|
!recipients.Any(r => string.Equals(r, operatorCopy, StringComparison.OrdinalIgnoreCase)))
|
||||||
recipients.Add(contactToEmail);
|
recipients.Add(operatorCopy);
|
||||||
|
|
||||||
if (recipients.Count == 0) return;
|
if (recipients.Count == 0) return;
|
||||||
|
|
||||||
var htmlBody = BuildBody(results, language);
|
var htmlBody = BuildBody(results, language);
|
||||||
var subject = _templates.Render("email.search-results.subject", language,
|
var subject = _emailTemplates.Render("email.search-results.subject", language,
|
||||||
("count", results.Count.ToString()));
|
("count", results.Count.ToString()));
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -71,7 +67,7 @@ public sealed class CvSearchEmailSender
|
|||||||
private string BuildBody(IReadOnlyList<JobSearchResultEntity> results, string language)
|
private string BuildBody(IReadOnlyList<JobSearchResultEntity> results, string language)
|
||||||
{
|
{
|
||||||
if (results.Count == 0)
|
if (results.Count == 0)
|
||||||
return _templates.Get("email.search-results.empty", language);
|
return _emailTemplates.Get("email.search-results.empty", language);
|
||||||
|
|
||||||
var items = new System.Text.StringBuilder();
|
var items = new System.Text.StringBuilder();
|
||||||
for (int i = 0; i < results.Count; i++)
|
for (int i = 0; i < results.Count; i++)
|
||||||
@@ -91,7 +87,7 @@ public sealed class CvSearchEmailSender
|
|||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
return _templates.Render("email.search-results.body", language,
|
return _emailTemplates.Render("email.search-results.body", language,
|
||||||
("count", results.Count.ToString()),
|
("count", results.Count.ToString()),
|
||||||
("items", items.ToString()));
|
("items", items.ToString()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,12 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Apis\cv-matcher-api-models\cv-matcher-api-models.csproj" />
|
<ProjectReference Include="..\..\Apis\cv-matcher-api-models\cv-matcher-api-models.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Apis\email-api-data\email-api-data.csproj" />
|
||||||
<ProjectReference Include="..\..\Apis\email-api-models\email-api-models.csproj" />
|
<ProjectReference Include="..\..\Apis\email-api-models\email-api-models.csproj" />
|
||||||
<ProjectReference Include="..\..\Apis\cv-search-data\cv-search-data.csproj" />
|
<ProjectReference Include="..\..\Apis\cv-search-data\cv-search-data.csproj" />
|
||||||
<ProjectReference Include="..\..\Apis\common\common.csproj" />
|
<ProjectReference Include="..\..\Apis\common\common.csproj" />
|
||||||
<ProjectReference Include="..\..\Helpers\startup-helpers\startup-helpers.csproj" />
|
<ProjectReference Include="..\..\Helpers\startup-helpers\startup-helpers.csproj" />
|
||||||
<ProjectReference Include="..\job-scheduler\job-scheduler.csproj" />
|
<ProjectReference Include="..\job-scheduler\job-scheduler.csproj" />
|
||||||
<ProjectReference Include="..\..\Apis\myai-data\myai-data.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -108,6 +108,13 @@ services:
|
|||||||
- ASPNETCORE_URLS=${ASPNETCORE_URLS:-http://+:8080}
|
- ASPNETCORE_URLS=${ASPNETCORE_URLS:-http://+:8080}
|
||||||
- APP_ENVIRONMENT_NAME=${APP_ENVIRONMENT_NAME:-myai.staging}
|
- APP_ENVIRONMENT_NAME=${APP_ENVIRONMENT_NAME:-myai.staging}
|
||||||
|
|
||||||
|
- Database__Host=${Database__Host:-sqlserver}
|
||||||
|
- Database__Port=${Database__Port:-1433}
|
||||||
|
- Database__Name=${Database__Name:-MyAiDb}
|
||||||
|
- Database__User=${Database__User:-sa}
|
||||||
|
- Database__Password=${Database__Password:-}
|
||||||
|
- Database__TrustServerCertificate=${Database__TrustServerCertificate:-true}
|
||||||
|
|
||||||
- InternalApi__ApiKey=${EmailApi__InternalApiKey:-}
|
- InternalApi__ApiKey=${EmailApi__InternalApiKey:-}
|
||||||
- InternalApi__RequireApiKey=true
|
- InternalApi__RequireApiKey=true
|
||||||
|
|
||||||
@@ -261,8 +268,6 @@ services:
|
|||||||
- EmailApi__BaseUrl=${EmailApi__BaseUrl:-http://email-api:8080}
|
- EmailApi__BaseUrl=${EmailApi__BaseUrl:-http://email-api:8080}
|
||||||
- EmailApi__InternalApiKey=${EmailApi__InternalApiKey:-}
|
- EmailApi__InternalApiKey=${EmailApi__InternalApiKey:-}
|
||||||
|
|
||||||
- Contact__ToEmail=${Contact__ToEmail:-}
|
|
||||||
|
|
||||||
- FileStorage__Path=${FileStorage__Path:-Files}
|
- FileStorage__Path=${FileStorage__Path:-Files}
|
||||||
|
|
||||||
- JobSearch__Enabled=${JobSearch__Enabled:-true}
|
- JobSearch__Enabled=${JobSearch__Enabled:-true}
|
||||||
|
|||||||
Reference in New Issue
Block a user