using System.Text; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using JobTrackerApi.Data; namespace JobTrackerApi.Controllers { [ApiController] [Route("api/export")] public class ExportController : ControllerBase { private readonly JobTrackerContext _db; public ExportController(JobTrackerContext db) { _db = db; } [HttpGet("jobs")] public async Task ExportJobs( [FromQuery] string format = "json", [FromQuery] bool includeDeleted = false, CancellationToken cancellationToken = default ) { var query = _db.JobApplications .AsNoTracking() .Include(j => j.Company) .AsQueryable(); if (!includeDeleted) query = query.Where(j => !j.IsDeleted); var jobs = await query .OrderByDescending(j => j.DateApplied) .ToListAsync(cancellationToken); var stamp = DateTime.Now.ToString("yyyy-MM-dd"); if (string.Equals(format, "csv", StringComparison.OrdinalIgnoreCase)) { static string Esc(string? s) { s ??= ""; var needs = s.Contains(',') || s.Contains('"') || s.Contains('\n') || s.Contains('\r'); var q = s.Replace("\"", "\"\""); return needs ? $"\"{q}\"" : q; } var sb = new StringBuilder(); sb.AppendLine(string.Join(",", "Company", "CompanyLocation", "CompanySource", "JobTitle", "Status", "DateApplied", "Location", "Salary", "NextAction", "FollowUpAt", "JobUrl", "Notes", "CoverLetterText" )); foreach (var j in jobs) { sb.AppendLine(string.Join(",", Esc(j.Company?.Name), Esc(j.Company?.Location), Esc(j.Company?.Source), Esc(j.JobTitle), Esc(j.Status), Esc(j.DateApplied.ToString("o")), Esc(j.Location), Esc(j.Salary), Esc(j.NextAction), Esc(j.FollowUpAt?.ToString("o")), Esc(j.JobUrl), Esc(j.Notes), Esc(j.CoverLetterText) )); } return File(Encoding.UTF8.GetBytes(sb.ToString()), "text/csv", $"job-tracker-export-{stamp}.csv"); } return File(System.Text.Json.JsonSerializer.SerializeToUtf8Bytes(jobs), "application/json", $"job-tracker-export-{stamp}.json"); } } }