package com.kpaudel.controller;
import com.kpaudel.model.ApplicationStatus;
import com.kpaudel.model.Company;
import com.kpaudel.model.JobApplication;
import com.kpaudel.model.User;
import com.kpaudel.repository.CompanyRepository;
import com.kpaudel.repository.JobApplicationRepository;
import com.kpaudel.repository.UserRepository;
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.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.UUID;
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:3000") // frontend dev CORS
public class ApiController {
private final JobService service;
private final CompanyRepository companyRepo;
private final JobApplicationRepository jobRepo;
private final UserRepository userRepo;
public ApiController(JobService service, CompanyRepository companyRepo, JobApplicationRepository jobRepo, UserRepository userRepo) {
this.service = service;
this.companyRepo = companyRepo;
this.jobRepo = jobRepo;
this.userRepo = userRepo;
}
private User getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
return userRepo.findByUsername(username).orElseThrow(() -> new RuntimeException("User not found"));
}
private UUID getCurrentUserId() {
return getCurrentUser().getId();
}
@GetMapping("/jobs")
public List<JobApplication> listJobs(@RequestParam Optional<ApplicationStatus> status) {
UUID userId = getCurrentUserId();
if (status.isPresent()) {
return service.listByUserAndStatus(userId, status.get());
}
return service.listAllByUser(userId);
}
@GetMapping("/jobs/{id}")
public ResponseEntity<JobApplication> getJob(@PathVariable UUID id) {
UUID userId = getCurrentUserId();
JobApplication job = this.jobRepo.findById(id).orElse(null);
if (job == null || !job.getUser().getId().equals(userId)) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok(job);
}
@PostMapping("/jobs")
public JobApplication createJob(@RequestBody JobApplication job) {
UUID userId = getCurrentUserId();
return this.service.create(job, userId);
}
@PutMapping("/jobs/{id}")
public ResponseEntity<JobApplication> updateJob(@PathVariable UUID id, @RequestBody JobApplication updated) {
UUID userId = getCurrentUserId();
JobApplication existing = jobRepo.findById(id).orElse(null);
if (existing == null || !existing.getUser().getId().equals(userId)) {
return ResponseEntity.notFound().build();
}
updated.setId(id);
updated.setUser(existing.getUser()); // Preserve user
return ResponseEntity.ok(jobRepo.save(updated));
}
@PatchMapping("/jobs/{id}/status")
public JobApplication updateStatus(@PathVariable UUID id, @RequestBody Map<String, String> body) {
UUID userId = getCurrentUserId();
ApplicationStatus status = ApplicationStatus.valueOf(body.get("status"));
return service.updateStatus(id, status, userId);
}
@DeleteMapping("/jobs/{id}")
public ResponseEntity<Void> deleteJob(@PathVariable UUID id) {
UUID userId = getCurrentUserId();
JobApplication job = jobRepo.findById(id).orElse(null);
if (job == null || !job.getUser().getId().equals(userId)) {
return ResponseEntity.notFound().build();
}
jobRepo.deleteById(id);
return ResponseEntity.noContent().build();
}
@GetMapping("/companies")
public List<Company> listCompanies() {
return this.companyRepo.findAll();
}
@GetMapping("/companies/{id}")
public ResponseEntity<Company> getCompany(@PathVariable UUID id) {
return companyRepo.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@GetMapping("/companies/{id}/jobs")
public List<JobApplication> listJobsByCompany(@PathVariable UUID id) {
UUID userId = getCurrentUserId();
return service.listByCompanyAndUser(id, userId);
}
@PostMapping("/companies")
public Company createCompany(@RequestBody Company company) {
return this.companyRepo.save(company);
}
@PutMapping("/companies/{id}")
public ResponseEntity<Company> updateCompany(@PathVariable UUID id, @RequestBody Company updated) {
return companyRepo.findById(id)
.map(existing -> {
updated.setId(id);
return ResponseEntity.ok(companyRepo.save(updated));
})
.orElse(ResponseEntity.notFound().build());
}
@DeleteMapping("/companies/{id}")
public ResponseEntity<Void> deleteCompany(@PathVariable UUID id) {
if (companyRepo.existsById(id)) {
companyRepo.deleteById(id);
return ResponseEntity.noContent().build();
}
return ResponseEntity.notFound().build();
}
@GetMapping("/jobs/export")
public ResponseEntity<byte[]> exportJobs() throws IOException {
UUID userId = getCurrentUserId();
List<JobApplication> jobs = service.listAllByUser(userId);
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);
}
// Add to service if needed
public List<JobApplication> listByUserAndStatus(UUID userId, ApplicationStatus status) {
return this.jobRepo.findByUserIdAndStatus(userId, status);
}
public List<JobApplication> listByCompanyAndUser(UUID userId, UUID companyId) {
return this.jobRepo.findByUserIdAndCompanyId(userId, companyId);
}
@GetMapping("/user/profile")
public ResponseEntity<Map<String, Object>> getProfile() {
User user = getCurrentUser();
Map<String, Object> profile = new HashMap<>();
profile.put("id", user.getId());
profile.put("username", user.getUsername());
profile.put("email", user.getEmail());
profile.put("firstName", user.getFirstName());
profile.put("lastName", user.getLastName());
profile.put("status", user.getStatus().name());
return ResponseEntity.ok(profile);
}
@GetMapping("/companies/export")
public ResponseEntity<byte[]> exportCompanies() throws IOException {
List<Company> 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);
}
}