Move hardcoded HtmlPage shell into html.job-search.shell DB template
The job-search status page HTML wrapper was baked into a static helper
method in CvMatcherController. Extracted to a new template key
html.job-search.shell (*) with {{title}} and {{message}} placeholders.
Added to AddTemplates seed and a new AddHtmlJobSearchShell migration
for existing DBs. Controller now calls _templates.Render() for all paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -246,38 +246,24 @@ public sealed class CvMatcherController : ControllerBase
|
|||||||
{
|
{
|
||||||
var result = await _jobSearchApi.StartSearchAsync(t, ct);
|
var result = await _jobSearchApi.StartSearchAsync(t, ct);
|
||||||
var lang = "en";
|
var lang = "en";
|
||||||
var html = result.Status switch
|
var (title, message) = result.Status switch
|
||||||
{
|
{
|
||||||
StartJobSearchStatus.Started =>
|
StartJobSearchStatus.Started => (_templates.Get("html.job-search.started.title", lang), _templates.Get("html.job-search.started.message", lang)),
|
||||||
HtmlPage(_templates.Get("html.job-search.started.title", lang), _templates.Get("html.job-search.started.message", lang)),
|
StartJobSearchStatus.AlreadyUsed => (_templates.Get("html.job-search.already-used.title", lang), _templates.Get("html.job-search.already-used.message", lang)),
|
||||||
StartJobSearchStatus.AlreadyUsed =>
|
StartJobSearchStatus.Expired => (_templates.Get("html.job-search.expired.title", lang), _templates.Get("html.job-search.expired.message", lang)),
|
||||||
HtmlPage(_templates.Get("html.job-search.already-used.title", lang), _templates.Get("html.job-search.already-used.message", lang)),
|
_ => (_templates.Get("html.job-search.invalid.title", lang), _templates.Get("html.job-search.invalid.message", lang))
|
||||||
StartJobSearchStatus.Expired =>
|
|
||||||
HtmlPage(_templates.Get("html.job-search.expired.title", lang), _templates.Get("html.job-search.expired.message", lang)),
|
|
||||||
_ =>
|
|
||||||
HtmlPage(_templates.Get("html.job-search.invalid.title", lang), _templates.Get("html.job-search.invalid.message", lang))
|
|
||||||
};
|
};
|
||||||
return Content(html, "text/html");
|
return Content(_templates.Render("html.job-search.shell", "*", ("title", title), ("message", message)), "text/html");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Job search start failed for token {Token}.", t);
|
_logger.LogError(ex, "Job search start failed for token {Token}.", t);
|
||||||
return Content(HtmlPage(_templates.Get("html.job-search.error.title", "en"), _templates.Get("html.job-search.error.message", "en")), "text/html");
|
var title = _templates.Get("html.job-search.error.title", "en");
|
||||||
|
var message = _templates.Get("html.job-search.error.message", "en");
|
||||||
|
return Content(_templates.Render("html.job-search.shell", "*", ("title", title), ("message", message)), "text/html");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string HtmlPage(string title, string message) => $$"""
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head><meta charset="utf-8"><title>{{title}} - MyAi.ro</title>
|
|
||||||
<style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f5f5f5}
|
|
||||||
.card{background:#fff;padding:2rem 3rem;border-radius:12px;box-shadow:0 2px 12px rgba(0,0,0,.1);text-align:center;max-width:480px}
|
|
||||||
h1{font-size:1.4rem;margin-bottom:.5rem}p{color:#555}</style>
|
|
||||||
</head>
|
|
||||||
<body><div class="card"><h1>{{title}}</h1><p>{{message}}</p></div></body>
|
|
||||||
</html>
|
|
||||||
""";
|
|
||||||
|
|
||||||
private async Task CacheUploadedCvAsync(IFormFile file, string documentId, CancellationToken ct)
|
private async Task CacheUploadedCvAsync(IFormFile file, string documentId, CancellationToken ct)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -71,6 +71,11 @@ namespace MyAi.Data.Migrations
|
|||||||
Row("email.search-results.empty", "en", "MyAi.ro found no jobs matching your CV. Try again later or update your CV.", "No results message for job search results email");
|
Row("email.search-results.empty", "en", "MyAi.ro found no jobs matching your CV. Try again later or update your CV.", "No results message for job search results email");
|
||||||
Row("email.search-results.empty", "ro", "MyAi.ro nu a gasit joburi care sa corespunda CV-ului tau. Incercati mai tarziu sau ajustati CV-ul.", "Mesaj fara rezultate pentru emailul de cautare joburi");
|
Row("email.search-results.empty", "ro", "MyAi.ro nu a gasit joburi care sa corespunda CV-ului tau. Incercati mai tarziu sau ajustati CV-ul.", "Mesaj fara rezultate pentru emailul de cautare joburi");
|
||||||
|
|
||||||
|
// HTML job-search page shell — wraps title + message in a centered card page
|
||||||
|
Row("html.job-search.shell", "*",
|
||||||
|
"<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>{{title}} - MyAi.ro</title><style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f5f5f5}.card{background:#fff;padding:2rem 3rem;border-radius:12px;box-shadow:0 2px 12px rgba(0,0,0,.1);text-align:center;max-width:480px}h1{font-size:1.4rem;margin-bottom:.5rem;color:#2c5282}p{color:#555}</style></head><body><div class=\"card\"><h1>{{title}}</h1><p>{{message}}</p></div></body></html>",
|
||||||
|
"Full HTML shell for job-search status pages. Placeholders: {{title}}, {{message}}.");
|
||||||
|
|
||||||
// HTML job-search start page messages
|
// HTML job-search start page messages
|
||||||
Row("html.job-search.started.title", "en", "Job search started", "Title for job search started page");
|
Row("html.job-search.started.title", "en", "Job search started", "Title for job search started page");
|
||||||
Row("html.job-search.started.message", "en", "Your job search has started. Results will be sent to your email shortly.", "Message for job search started page");
|
Row("html.job-search.started.message", "en", "Your job search has started. Results will be sent to your email shortly.", "Message for job search started page");
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using MyAi.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace MyAi.Data.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddHtmlJobSearchShell : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "Templates",
|
||||||
|
columns: ["Key", "Language", "Value", "Description"],
|
||||||
|
values: new object[]
|
||||||
|
{
|
||||||
|
"html.job-search.shell",
|
||||||
|
"*",
|
||||||
|
"<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>{{title}} - MyAi.ro</title><style>body{font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#f5f5f5}.card{background:#fff;padding:2rem 3rem;border-radius:12px;box-shadow:0 2px 12px rgba(0,0,0,.1);text-align:center;max-width:480px}h1{font-size:1.4rem;margin-bottom:.5rem;color:#2c5282}p{color:#555}</style></head><body><div class=\"card\"><h1>{{title}}</h1><p>{{message}}</p></div></body></html>",
|
||||||
|
"Full HTML shell for job-search status pages. Placeholders: {{title}}, {{message}}."
|
||||||
|
},
|
||||||
|
schema: MigrationConstants.SchemaName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "Templates",
|
||||||
|
keyColumns: ["Key", "Language"],
|
||||||
|
keyValues: new object[] { "html.job-search.shell", "*" },
|
||||||
|
schema: MigrationConstants.SchemaName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user