feat: add correspondence inbox and gmail ingestion contract
This commit is contained in:
@@ -25,6 +25,84 @@ namespace JobTrackerApi.Controllers
|
||||
.FirstOrDefaultAsync(c => c.Id == correspondenceId, cancellationToken);
|
||||
}
|
||||
|
||||
public sealed record CorrespondenceInboxItemDto(
|
||||
int Id,
|
||||
int JobApplicationId,
|
||||
string? CompanyName,
|
||||
string? JobTitle,
|
||||
string From,
|
||||
string? Direction,
|
||||
string? Subject,
|
||||
string? Channel,
|
||||
DateTime Date,
|
||||
string ContentPreview,
|
||||
string? ExternalThreadId,
|
||||
string? ExternalFrom,
|
||||
string? ExternalTo,
|
||||
int LabelCount,
|
||||
int AttachmentCount);
|
||||
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<List<CorrespondenceInboxItemDto>>> GetInbox(
|
||||
[FromQuery] string? q,
|
||||
[FromQuery] string? direction,
|
||||
[FromQuery] string? linkState,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var query = _db.Correspondences
|
||||
.Include(c => c.JobApplication)
|
||||
.ThenInclude(j => j.Company)
|
||||
.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(q))
|
||||
{
|
||||
var needle = q.Trim();
|
||||
query = query.Where(c =>
|
||||
(c.Subject != null && EF.Functions.Like(c.Subject, $"%{needle}%")) ||
|
||||
EF.Functions.Like(c.Content, $"%{needle}%") ||
|
||||
(c.ExternalFrom != null && EF.Functions.Like(c.ExternalFrom, $"%{needle}%")) ||
|
||||
(c.JobApplication.JobTitle != null && EF.Functions.Like(c.JobApplication.JobTitle, $"%{needle}%")) ||
|
||||
(c.JobApplication.Company.Name != null && EF.Functions.Like(c.JobApplication.Company.Name, $"%{needle}%")));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(direction) && !string.Equals(direction, "all", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
query = query.Where(c => c.Direction == direction);
|
||||
}
|
||||
|
||||
if (string.Equals(linkState, "linked", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
query = query.Where(c => c.ExternalThreadId != null);
|
||||
}
|
||||
else if (string.Equals(linkState, "manual", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
query = query.Where(c => c.ExternalThreadId == null);
|
||||
}
|
||||
|
||||
var items = await query
|
||||
.OrderByDescending(c => c.Date)
|
||||
.Take(200)
|
||||
.Select(c => new CorrespondenceInboxItemDto(
|
||||
c.Id,
|
||||
c.JobApplicationId,
|
||||
c.JobApplication.Company != null ? c.JobApplication.Company.Name : null,
|
||||
c.JobApplication.JobTitle,
|
||||
c.From,
|
||||
c.Direction,
|
||||
c.Subject,
|
||||
c.Channel,
|
||||
c.Date,
|
||||
c.Content.Length <= 220 ? c.Content : c.Content.Substring(0, 220),
|
||||
c.ExternalThreadId,
|
||||
c.ExternalFrom,
|
||||
c.ExternalTo,
|
||||
c.ExternalLabelsJson != null ? 1 : 0,
|
||||
c.AttachmentMetadataJson != null ? 1 : 0))
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Ok(items);
|
||||
}
|
||||
|
||||
// GET all messages for a job
|
||||
[HttpGet("{jobId:int}")]
|
||||
public async Task<ActionResult<List<Correspondence>>> GetForJob([FromRoute] int jobId, CancellationToken cancellationToken)
|
||||
|
||||
Reference in New Issue
Block a user