feat(cv): qualify templates and reliable local import processing
This commit is contained in:
@@ -45,6 +45,8 @@ public sealed record CoverLetterDto(
|
||||
int Revision = 1,
|
||||
CoverLetterDocumentSettings? DocumentSettings = null);
|
||||
|
||||
public sealed class CoverLetterThemeAccessException() : Exception("This theme requires Pro.");
|
||||
|
||||
public interface IApplicationAssetsService
|
||||
{
|
||||
Task<ApplicationCvDto?> GetCvAsync(string ownerUserId, int jobApplicationId, CancellationToken ct);
|
||||
@@ -293,7 +295,9 @@ public sealed class ApplicationAssetsService : IApplicationAssetsService
|
||||
public async Task<CoverLetterRenderDto?> PreviewCoverLetterAsync(string ownerUserId, int jobApplicationId, string? text, CoverLetterDocumentSettings? settings, CancellationToken ct)
|
||||
{
|
||||
var job = await LoadJobAsync(ownerUserId, jobApplicationId, ct);
|
||||
return job is null ? null : _letters.Render(text, settings ?? CoverLetterDocumentSettingsJson.Deserialize(job.CoverLetterDocumentSettingsJson));
|
||||
if (job is null) return null;
|
||||
await RequireLetterThemeAsync(_db, job, settings, ct);
|
||||
return _letters.Render(text, settings ?? CoverLetterDocumentSettingsJson.Deserialize(job.CoverLetterDocumentSettingsJson));
|
||||
}
|
||||
|
||||
public async Task<CoverLetterRenderDto?> RenderSavedCoverLetterAsync(string ownerUserId, int jobApplicationId, int? expectedVersion, CancellationToken ct)
|
||||
@@ -331,6 +335,7 @@ public sealed class ApplicationAssetsService : IApplicationAssetsService
|
||||
internal static async Task StageCoverLetterAsync(JobTrackerContext db, JobApplication job, string? text,
|
||||
string source, string? aiAction, CancellationToken ct, CoverLetterDocumentSettings? settings = null)
|
||||
{
|
||||
await RequireLetterThemeAsync(db, job, settings, ct);
|
||||
var currentSettings = CoverLetterDocumentSettingsJson.Serialize(CoverLetterDocumentSettingsJson.Deserialize(job.CoverLetterDocumentSettingsJson));
|
||||
var nextSettings = settings is null ? currentSettings : CoverLetterDocumentSettingsJson.Serialize(settings);
|
||||
if (string.Equals(job.CoverLetterText, text, StringComparison.Ordinal) && nextSettings == currentSettings) return;
|
||||
@@ -362,6 +367,21 @@ public sealed class ApplicationAssetsService : IApplicationAssetsService
|
||||
if (settings is not null) job.CoverLetterDocumentSettingsJson = nextSettings;
|
||||
}
|
||||
|
||||
private static async Task RequireLetterThemeAsync(JobTrackerContext db, JobApplication job, CoverLetterDocumentSettings? settings, CancellationToken ct)
|
||||
{
|
||||
if (settings is null) return;
|
||||
var next = CoverLetterDocumentSettingsJson.Normalize(settings);
|
||||
if (next.DesignVersion != 2 || CvThemeCatalog.CanUse(next.ThemeId, false)) return;
|
||||
var current = CoverLetterDocumentSettingsJson.Deserialize(job.CoverLetterDocumentSettingsJson);
|
||||
if (current.DesignVersion == 2 && current.ThemeId == next.ThemeId) return;
|
||||
var roles = await (from userRole in db.UserRoles.AsNoTracking()
|
||||
join role in db.Roles.AsNoTracking() on userRole.RoleId equals role.Id
|
||||
where userRole.UserId == job.OwnerUserId && role.Name != null
|
||||
select role.Name!).ToListAsync(ct);
|
||||
if (!CvThemeCatalog.CanUse(next.ThemeId, AccountPlans.ForRoles(roles).ProThemes))
|
||||
throw new CoverLetterThemeAccessException();
|
||||
}
|
||||
|
||||
private Task<JobApplication?> LoadJobAsync(string ownerUserId, int jobApplicationId, CancellationToken ct) =>
|
||||
_db.JobApplications.AsNoTracking()
|
||||
.FirstOrDefaultAsync(j => j.Id == jobApplicationId && j.OwnerUserId == ownerUserId, ct);
|
||||
|
||||
Reference in New Issue
Block a user