fix: keep opportunity data synchronized
This commit is contained in:
@@ -239,6 +239,7 @@ public sealed class JobApplicationsEndpointBehaviorTests
|
|||||||
SalaryMax = 60000m,
|
SalaryMax = 60000m,
|
||||||
SalaryCurrency = "NOK",
|
SalaryCurrency = "NOK",
|
||||||
SalaryPeriod = "year",
|
SalaryPeriod = "year",
|
||||||
|
Job = new Job { CompanyId = company.Id, JobTitle = "Backend Dev", Source = "nav", CountryCode = "NO" },
|
||||||
};
|
};
|
||||||
db.JobApplications.Add(job);
|
db.JobApplications.Add(job);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
@@ -278,6 +279,12 @@ public sealed class JobApplicationsEndpointBehaviorTests
|
|||||||
Assert.Null(saved.SalaryMax);
|
Assert.Null(saved.SalaryMax);
|
||||||
Assert.Null(saved.SalaryCurrency);
|
Assert.Null(saved.SalaryCurrency);
|
||||||
Assert.Null(saved.SalaryPeriod);
|
Assert.Null(saved.SalaryPeriod);
|
||||||
|
var opportunity = await db.Jobs.SingleAsync();
|
||||||
|
Assert.Equal(saved.JobTitle, opportunity.JobTitle);
|
||||||
|
Assert.Null(opportunity.SalaryMin);
|
||||||
|
Assert.Null(opportunity.SalaryPeriod);
|
||||||
|
Assert.Equal("nav", opportunity.Source);
|
||||||
|
Assert.Equal("NO", opportunity.CountryCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JobApplicationsController CreateController(JobTrackerContext db, string userId)
|
private static JobApplicationsController CreateController(JobTrackerContext db, string userId)
|
||||||
|
|||||||
@@ -707,6 +707,27 @@ Canonical profile:
|
|||||||
return Ok(dtos);
|
return Ok(dtos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void SyncOpportunity(JobApplication application, Job opportunity)
|
||||||
|
{
|
||||||
|
opportunity.OwnerUserId = application.OwnerUserId;
|
||||||
|
opportunity.CompanyId = application.CompanyId;
|
||||||
|
opportunity.JobTitle = application.JobTitle;
|
||||||
|
opportunity.Location = application.Location;
|
||||||
|
opportunity.JobUrl = application.JobUrl;
|
||||||
|
opportunity.Description = application.Description;
|
||||||
|
opportunity.TranslatedDescription = application.TranslatedDescription;
|
||||||
|
opportunity.DescriptionLanguage = application.DescriptionLanguage;
|
||||||
|
opportunity.ShortSummary = application.ShortSummary;
|
||||||
|
opportunity.Tags = application.Tags;
|
||||||
|
opportunity.Deadline = application.Deadline;
|
||||||
|
opportunity.Salary = application.Salary;
|
||||||
|
opportunity.SalaryMin = application.SalaryMin;
|
||||||
|
opportunity.SalaryMax = application.SalaryMax;
|
||||||
|
opportunity.SalaryCurrency = application.SalaryCurrency;
|
||||||
|
opportunity.SalaryPeriod = application.SalaryPeriod;
|
||||||
|
opportunity.SavedAt = application.SavedAt;
|
||||||
|
}
|
||||||
|
|
||||||
private static (decimal? Min, decimal? Max, string? Currency, string? Period) NormalizeSalary(
|
private static (decimal? Min, decimal? Max, string? Currency, string? Period) NormalizeSalary(
|
||||||
decimal? min, decimal? max, string? currency, string? period)
|
decimal? min, decimal? max, string? currency, string? period)
|
||||||
{
|
{
|
||||||
@@ -766,23 +787,7 @@ Canonical profile:
|
|||||||
if (source?.Length > 32) source = source[..32];
|
if (source?.Length > 32) source = source[..32];
|
||||||
var countryCode = string.IsNullOrWhiteSpace(request.CountryCode) ? null : request.CountryCode.Trim().ToUpperInvariant();
|
var countryCode = string.IsNullOrWhiteSpace(request.CountryCode) ? null : request.CountryCode.Trim().ToUpperInvariant();
|
||||||
if (countryCode?.Length != 2) countryCode = null;
|
if (countryCode?.Length != 2) countryCode = null;
|
||||||
job.Job = new Job
|
job.Job = new Job { Source = source, CountryCode = countryCode };
|
||||||
{
|
|
||||||
OwnerUserId = job.OwnerUserId,
|
|
||||||
CompanyId = job.CompanyId,
|
|
||||||
JobTitle = job.JobTitle,
|
|
||||||
Location = job.Location,
|
|
||||||
JobUrl = job.JobUrl,
|
|
||||||
Description = job.Description,
|
|
||||||
TranslatedDescription = job.TranslatedDescription,
|
|
||||||
DescriptionLanguage = job.DescriptionLanguage,
|
|
||||||
Tags = job.Tags,
|
|
||||||
Deadline = job.Deadline,
|
|
||||||
Salary = job.Salary,
|
|
||||||
Source = source,
|
|
||||||
CountryCode = countryCode,
|
|
||||||
SavedAt = job.SavedAt,
|
|
||||||
};
|
|
||||||
|
|
||||||
// A job created straight into a pre-application stage has not been applied to, so it
|
// A job created straight into a pre-application stage has not been applied to, so it
|
||||||
// must not carry an applied date. SyncAppliedDate also covers the reverse: a create
|
// must not carry an applied date. SyncAppliedDate also covers the reverse: a create
|
||||||
@@ -791,23 +796,19 @@ Canonical profile:
|
|||||||
|
|
||||||
(job.SalaryMin, job.SalaryMax, job.SalaryCurrency, job.SalaryPeriod) =
|
(job.SalaryMin, job.SalaryMax, job.SalaryCurrency, job.SalaryPeriod) =
|
||||||
NormalizeSalary(request.SalaryMin, request.SalaryMax, request.SalaryCurrency, request.SalaryPeriod);
|
NormalizeSalary(request.SalaryMin, request.SalaryMax, request.SalaryCurrency, request.SalaryPeriod);
|
||||||
job.Job.SalaryMin = job.SalaryMin;
|
|
||||||
job.Job.SalaryMax = job.SalaryMax;
|
|
||||||
job.Job.SalaryCurrency = job.SalaryCurrency;
|
|
||||||
job.Job.SalaryPeriod = job.SalaryPeriod;
|
|
||||||
|
|
||||||
// Generate and persist a short summary at creation time to avoid repeated model calls.
|
// Generate and persist a short summary at creation time to avoid repeated model calls.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var shortSum = await _summarizer.SummarizeAsync(BuildSummarySource(job), 160, 60);
|
var shortSum = await _summarizer.SummarizeAsync(BuildSummarySource(job), 160, 60);
|
||||||
job.ShortSummary = shortSum;
|
job.ShortSummary = shortSum;
|
||||||
job.Job.ShortSummary = shortSum;
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// ignore summarizer failures at create time
|
// ignore summarizer failures at create time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SyncOpportunity(job, job.Job);
|
||||||
_db.JobApplications.Add(job);
|
_db.JobApplications.Add(job);
|
||||||
await _db.SaveChangesAsync(cancellationToken);
|
await _db.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
@@ -830,7 +831,7 @@ Canonical profile:
|
|||||||
[HttpPut("{id:int}")]
|
[HttpPut("{id:int}")]
|
||||||
public async Task<IActionResult> Update([FromRoute] int id, [FromBody] UpdateJobApplicationRequest request, CancellationToken cancellationToken)
|
public async Task<IActionResult> Update([FromRoute] int id, [FromBody] UpdateJobApplicationRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var job = await _db.JobApplications.FirstOrDefaultAsync(j => j.Id == id, cancellationToken);
|
var job = await _db.JobApplications.Include(j => j.Job).FirstOrDefaultAsync(j => j.Id == id, cancellationToken);
|
||||||
if (job is null) return NotFound();
|
if (job is null) return NotFound();
|
||||||
|
|
||||||
var oldStatus = job.Status;
|
var oldStatus = job.Status;
|
||||||
@@ -881,6 +882,7 @@ Canonical profile:
|
|||||||
// Records StatusChanged plus any lifecycle event the transition implies.
|
// Records StatusChanged plus any lifecycle event the transition implies.
|
||||||
JobLifecycleEvents.RecordStatusChange(_db, job, oldStatus, request.StatusChangedAt ?? DateTime.Now);
|
JobLifecycleEvents.RecordStatusChange(_db, job, oldStatus, request.StatusChangedAt ?? DateTime.Now);
|
||||||
|
|
||||||
|
if (job.Job is not null) SyncOpportunity(job, job.Job);
|
||||||
await _db.SaveChangesAsync(cancellationToken);
|
await _db.SaveChangesAsync(cancellationToken);
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user