diff --git a/build.gradle b/build.gradle index d1db3a9..5281d1f 100644 --- a/build.gradle +++ b/build.gradle @@ -35,6 +35,9 @@ // Lombok (optional convenience) compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' + // Exporting to CSV + implementation 'com.opencsv:opencsv:5.9' + // Testing testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/src/main/java/com/kpaudel/controller/ApiController.java b/src/main/java/com/kpaudel/controller/ApiController.java index bedac12..1a2529e 100644 --- a/src/main/java/com/kpaudel/controller/ApiController.java +++ b/src/main/java/com/kpaudel/controller/ApiController.java @@ -6,13 +6,19 @@ import com.kpaudel.repository.CompanyRepository; import com.kpaudel.repository.JobApplicationRepository; import com.kpaudel.service.JobService; +import com.opencsv.CSVWriter; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ContentDisposition; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; @RestController @RequestMapping("/api") @@ -34,15 +40,16 @@ } @GetMapping("/jobs/{id}") - public ResponseEntity getJob(@PathVariable UUID id){ + public ResponseEntity getJob(@PathVariable UUID id) { return this.jobRepo.findById(id).map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } @PostMapping("/jobs") - public JobApplication createJob(@RequestBody JobApplication job){ - return this.service.create(job.getCompany().getId(),job); + public JobApplication createJob(@RequestBody JobApplication job) { + return this.service.create(job.getCompany().getId(), job); } + @PutMapping("/jobs/{id}") public ResponseEntity updateJob(@PathVariable UUID id, @RequestBody JobApplication updated) { return jobRepo.findById(id) @@ -54,9 +61,9 @@ } @PatchMapping("/jobs/{id}/status") - public JobApplication updateStatus(@PathVariable UUID id, @RequestBody Map body){ - ApplicationStatus status=ApplicationStatus.valueOf(body.get("status")); - return service.updateStatus(id,status); + public JobApplication updateStatus(@PathVariable UUID id, @RequestBody Map body) { + ApplicationStatus status = ApplicationStatus.valueOf(body.get("status")); + return service.updateStatus(id, status); } @DeleteMapping("/jobs/{id}") @@ -69,7 +76,7 @@ } @GetMapping("/companies") - public List listCompanies(){ + public List listCompanies() { return this.companyRepo.findAll(); } @@ -79,6 +86,7 @@ .map(ResponseEntity::ok) .orElse(ResponseEntity.notFound().build()); } + @GetMapping("/companies/{id}/jobs") public List listJobsByCompany(@PathVariable UUID id) { return jobRepo.findByCompanyId(id); @@ -109,4 +117,63 @@ return ResponseEntity.notFound().build(); } + @GetMapping("/jobs/export") + public ResponseEntity exportJobs() throws IOException { + List jobs = this.jobRepo.findAll(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + CSVWriter writer = new CSVWriter(new java.io.OutputStreamWriter(out)); + //Add headers + writer.writeNext(new String[]{"ID", "Role", "Company","JobUrl", "Applied Date", "Source", "Salary Expectation","Status", "Location", "Last Updated", "Notes"}); + //Add Data + for (JobApplication job : jobs) { + writer.writeNext(new String[]{ + job.getId().toString(), + job.getRole(), + job.getCompany().getName(), + job.getJobUrl(), + job.getAppliedDate().toString(), + job.getSource(), + job.getSalaryExpectation(), + job.getStatus().name(), + job.getLocation(), + job.getLastUpdated().toString(), + job.getNotes() + }); + } + writer.close(); + byte[] data = out.toByteArray(); + String timestamp = java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.parseMediaType("text/csv")); + headers.setContentDisposition(ContentDisposition.attachment().filename("jobs_" + timestamp + ".csv").build()); + + return new ResponseEntity<>(data, headers, HttpStatus.OK); + } + @GetMapping("/companies/export") + public ResponseEntity exportCompanies() throws IOException { + List companies = this.companyRepo.findAll(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + CSVWriter writer = new CSVWriter(new java.io.OutputStreamWriter(out)); + //Add headers + writer.writeNext(new String[]{"ID", "Name", "Website", "Notes"}); + //Add Data + for (Company company : companies) { + writer.writeNext(new String[]{ + company.getId().toString(), + company.getName(), + company.getWebsite(), + company.getNotes() + }); + } + writer.close(); + byte[] data = out.toByteArray(); + String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.parseMediaType("text/csv")); + headers.setContentDisposition(ContentDisposition.attachment().filename("companies_" + timestamp + ".csv").build()); + + return new ResponseEntity<>(data, headers, HttpStatus.OK); + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3bef056..3539f0f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,4 +1,4 @@ -spring.profiles.active=dev +spring.profiles.active=prod spring.mvc.pathmatch.matching-strategy=ant_path_matcher #JPA/HIBERNATE