1212import org .bounswe .jobboardbackend .jobapplication .repository .JobApplicationRepository ;
1313import org .bounswe .jobboardbackend .jobpost .model .JobPost ;
1414import org .bounswe .jobboardbackend .jobpost .repository .JobPostRepository ;
15+ import org .bounswe .jobboardbackend .workplace .service .WorkplaceService ;
16+ import org .bounswe .jobboardbackend .workplace .repository .EmployerWorkplaceRepository ;
17+ import org .bounswe .jobboardbackend .workplace .repository .WorkplaceRepository ;
1518import org .springframework .beans .factory .annotation .Value ;
19+ import org .springframework .security .access .AccessDeniedException ;
1620import org .springframework .security .access .prepost .PreAuthorize ;
1721import org .springframework .security .core .Authentication ;
1822import org .springframework .security .core .context .SecurityContextHolder ;
@@ -36,6 +40,9 @@ public class JobApplicationService {
3640 private final JobApplicationRepository applicationRepository ;
3741 private final UserRepository userRepository ;
3842 private final JobPostRepository jobPostRepository ;
43+ private final WorkplaceService workplaceService ;
44+ private final EmployerWorkplaceRepository employerWorkplaceRepository ;
45+ private final WorkplaceRepository workplaceRepository ;
3946
4047 // === GCS config ===
4148 @ Value ("${app.gcs.bucket:bounswe-jobboard}" )
@@ -55,26 +62,51 @@ public class JobApplicationService {
5562
5663 public JobApplicationService (JobApplicationRepository applicationRepository ,
5764 UserRepository userRepository ,
58- JobPostRepository jobPostRepository ) {
65+ JobPostRepository jobPostRepository ,
66+ WorkplaceService workplaceService ,
67+ EmployerWorkplaceRepository employerWorkplaceRepository ,
68+ WorkplaceRepository workplaceRepository ) {
5969 this .applicationRepository = applicationRepository ;
6070 this .userRepository = userRepository ;
6171 this .jobPostRepository = jobPostRepository ;
72+ this .workplaceService = workplaceService ;
73+ this .employerWorkplaceRepository = employerWorkplaceRepository ;
74+ this .workplaceRepository = workplaceRepository ;
6275 }
6376
6477 @ Transactional (readOnly = true )
6578 public List <JobApplicationResponse > getByJobSeekerId (Long jobSeekerId ) {
79+ // Verify job seeker exists
80+ userRepository .findById (jobSeekerId )
81+ .orElseThrow (() -> new HandleException (ErrorCode .USER_NOT_FOUND , "Job seeker with ID " + jobSeekerId + " not found" ));
82+
6683 return applicationRepository .findByJobSeekerId (jobSeekerId ).stream ()
6784 .map (this ::toResponseDto )
6885 .collect (Collectors .toList ());
6986 }
7087
7188 @ Transactional (readOnly = true )
7289 public List <JobApplicationResponse > getByJobPostId (Long jobPostId ) {
90+ // Verify job post exists
91+ jobPostRepository .findById (jobPostId )
92+ .orElseThrow (() -> new HandleException (ErrorCode .JOB_POST_NOT_FOUND , "Job post with ID " + jobPostId + " not found" ));
93+
7394 return applicationRepository .findByJobPostId (jobPostId ).stream ()
7495 .map (this ::toResponseDto )
7596 .collect (Collectors .toList ());
7697 }
7798
99+ @ Transactional (readOnly = true )
100+ public List <JobApplicationResponse > getByWorkplaceId (Long workplaceId ) {
101+ // Verify workplace exists
102+ workplaceRepository .findById (workplaceId )
103+ .orElseThrow (() -> new HandleException (ErrorCode .WORKPLACE_NOT_FOUND , "Workplace with ID " + workplaceId + " not found" ));
104+
105+ return applicationRepository .findByJobPost_Workplace_Id (workplaceId ).stream ()
106+ .map (this ::toResponseDto )
107+ .collect (Collectors .toList ());
108+ }
109+
78110 @ Transactional (readOnly = true )
79111 public JobApplicationResponse getById (Long id ) {
80112 return applicationRepository .findById (id )
@@ -87,12 +119,15 @@ public JobApplicationResponse getById(Long id) {
87119 public JobApplicationResponse create (CreateJobApplicationRequest dto ) {
88120 User jobSeeker = getCurrentUser ();
89121
90-
91-
92122 // Get job post
93123 JobPost jobPost = jobPostRepository .findById (dto .getJobPostId ())
94124 .orElseThrow (() -> new HandleException (ErrorCode .JOB_POST_NOT_FOUND , "Job post with ID " + dto .getJobPostId () + " not found" ));
95125
126+ // Check if jobseeker already applied to this job post
127+ if (applicationRepository .existsByJobSeekerIdAndJobPostId (jobSeeker .getId (), dto .getJobPostId ())) {
128+ throw new HandleException (ErrorCode .APPLICATION_ALREADY_EXISTS , "You have already applied to this job post" );
129+ }
130+
96131 // Create application
97132 JobApplication application = JobApplication .builder ()
98133 .jobSeeker (jobSeeker )
@@ -107,16 +142,15 @@ public JobApplicationResponse create(CreateJobApplicationRequest dto) {
107142 }
108143
109144 @ Transactional
145+ @ PreAuthorize ("hasRole('ROLE_EMPLOYER')" )
110146 public JobApplicationResponse approve (Long id , String feedback ) {
111147 JobApplication application = applicationRepository .findById (id )
112148 .orElseThrow (() -> new HandleException (ErrorCode .JOB_APPLICATION_NOT_FOUND , "Application with ID " + id + " not found" ));
113149
114- // Check authorization: only the employer who posted the job can approve
150+ // Check authorization: any employer of the workplace can approve
115151 User employer = getCurrentUser ();
116-
117- if (!application .getJobPost ().getEmployer ().getId ().equals (employer .getId ())) {
118- throw new HandleException (ErrorCode .USER_UNAUTHORIZED , "Only the employer who posted the job can approve applications" );
119- }
152+ Long workplaceId = application .getJobPost ().getWorkplace ().getId ();
153+ assertEmployerOfWorkplace (workplaceId , employer .getId ());
120154
121155 // Update status
122156 application .setStatus (JobApplicationStatus .APPROVED );
@@ -128,16 +162,15 @@ public JobApplicationResponse approve(Long id, String feedback) {
128162 }
129163
130164 @ Transactional
165+ @ PreAuthorize ("hasRole('ROLE_EMPLOYER')" )
131166 public JobApplicationResponse reject (Long id , String feedback ) {
132167 JobApplication application = applicationRepository .findById (id )
133168 .orElseThrow (() -> new HandleException (ErrorCode .JOB_APPLICATION_NOT_FOUND , "Application with ID " + id + " not found" ));
134169
135- // Check authorization: only the employer who posted the job can reject
170+ // Check authorization: any employer of the workplace can reject
136171 User employer = getCurrentUser ();
137-
138- if (!application .getJobPost ().getEmployer ().getId ().equals (employer .getId ())) {
139- throw new HandleException (ErrorCode .USER_UNAUTHORIZED , "Only the employer who posted the job can reject applications" );
140- }
172+ Long workplaceId = application .getJobPost ().getWorkplace ().getId ();
173+ assertEmployerOfWorkplace (workplaceId , employer .getId ());
141174
142175 // Update status
143176 application .setStatus (JobApplicationStatus .REJECTED );
@@ -173,7 +206,7 @@ private JobApplicationResponse toResponseDto(JobApplication application) {
173206 .applicantName (jobSeeker .getUsername ())
174207 .jobPostId (jobPost .getId ())
175208 .title (jobPost .getTitle ())
176- .company ( jobPost .getCompany ( ))
209+ .workplace ( workplaceService . toBriefResponse ( jobPost .getWorkplace () ))
177210 .status (application .getStatus ())
178211 .specialNeeds (application .getSpecialNeeds ())
179212 .feedback (application .getFeedback ())
@@ -354,4 +387,11 @@ public void deleteCv(Long applicationId) {
354387 applicationRepository .save (application );
355388 }
356389 }
390+
391+ private void assertEmployerOfWorkplace (Long workplaceId , Long userId ) {
392+ boolean isEmployer = employerWorkplaceRepository .existsByWorkplace_IdAndUser_Id (workplaceId , userId );
393+ if (!isEmployer ) {
394+ throw new HandleException (ErrorCode .WORKPLACE_UNAUTHORIZED , "You are not an employer of this workplace" );
395+ }
396+ }
357397}
0 commit comments