@@ -44,18 +44,22 @@ public CareerResourceService(CareerResourceRepository resourceRepository,
4444
4545 @ Transactional (readOnly = true )
4646 @ Cacheable (value = "resourcePages" ,
47- key = "{#page, #size, #query ?: '', #category ?: '', #type ?: '', #viewerEmail ?: 'anon'}" )
47+ key = "{#page, #size, #query ?: '', #category ?: '', #type ?: '', #location ?: '', #listingType ?: '', # viewerEmail ?: 'anon'}" )
4848 public CareerResourcePageResponse getResourcePage (int page , int size , String query ,
49- String category , String type , String viewerEmail ) {
49+ String category , String type ,
50+ String location , String listingType ,
51+ String viewerEmail ) {
5052 int sanitizedPage = Math .max (0 , page );
5153 int sanitizedSize = Math .max (1 , Math .min (size , MAX_PAGE_SIZE ));
5254
5355 String normalizedQuery = normalizeFilter (query );
5456 String normalizedCategory = normalizeFilter (category );
5557 String normalizedType = normalizeType (type );
58+ String normalizedLocation = normalizeFilter (location );
59+ String normalizedListingType = normalizeFilter (listingType );
5660
57- var pageable = PageRequest .of (sanitizedPage , sanitizedSize , Sort .by (Sort .Order .asc ( "category" ), Sort . Order . asc ( "title " )));
58- var resourcePage = resourceRepository .findAll (buildResourceFilter (normalizedQuery , normalizedCategory , normalizedType ), pageable );
61+ var pageable = PageRequest .of (sanitizedPage , sanitizedSize , Sort .by (Sort .Order .desc ( "createdAt " )));
62+ var resourcePage = resourceRepository .findAll (buildExploreFilter (normalizedQuery , normalizedCategory , normalizedType , normalizedLocation , normalizedListingType ), pageable );
5963
6064 var content = resourcePage .getContent ().stream ()
6165 .map (resource -> toDTO (resource , viewerEmail ))
@@ -68,9 +72,12 @@ public CareerResourcePageResponse getResourcePage(int page, int size, String que
6872 }
6973
7074 @ Transactional (readOnly = true )
71- @ Cacheable (value = "resourceCategories" )
72- public List <String > getAllCategories () {
73- return resourceRepository .findDistinctCategories ();
75+ @ Cacheable (value = "resourceCategories" , key = "#listingType ?: 'ALL'" )
76+ public List <String > getAllCategories (String listingType ) {
77+ if (listingType == null || listingType .isBlank () || "ALL" .equalsIgnoreCase (listingType )) {
78+ return resourceRepository .findDistinctCategories ();
79+ }
80+ return resourceRepository .findDistinctCategoriesByListingType (listingType .trim ().toUpperCase (Locale .ROOT ));
7481 }
7582
7683 @ Transactional (readOnly = true )
@@ -100,7 +107,7 @@ public CareerResourceDTO createResource(String email, CreateCareerResourceReques
100107 resource .setUrl (normalizedUrl );
101108 resource .setCategory (request .getCategory ().trim ());
102109 resource .setDescription (request .getDescription () == null ? null : request .getDescription ().trim ());
103- resource . setResourceType ( "LINK" );
110+ applyMetadata ( resource , request . getLocation (), request . getCompany (), request . getEventDate (), request . getListingType () );
104111 applySubmitter (resource , user );
105112
106113 return toDTO (resourceRepository .save (resource ), email );
@@ -111,22 +118,22 @@ public CareerResourceDTO createResource(String email, CreateCareerResourceReques
111118 @ CacheEvict (value = "resourceCategories" , allEntries = true ),
112119 @ CacheEvict (value = "userResources" , key = "#email" )
113120 })
114- public CareerResourceDTO createResourceFromFile (String email , String title , String category ,
115- String description , MultipartFile file ) {
121+ public CareerResourceDTO createResourceFromFile (String email , CreateCareerResourceRequest request , MultipartFile file ) {
116122 if (file == null || file .isEmpty ()) throw new IllegalArgumentException ("File required" );
117- validateCommonFields (title , category );
118-
123+ validateCommonFields (request . getTitle (), request . getCategory () );
124+
119125 User user = getUser (email );
120126 String fileUrl = storageService .uploadResourceFile (file , user .getId ().toString ());
121127
122128 CareerResource resource = new CareerResource ();
123- resource .setTitle (title .trim ());
124- resource .setCategory (category .trim ());
125- resource .setDescription (description == null ? null : description .trim ());
129+ resource .setTitle (request . getTitle () .trim ());
130+ resource .setCategory (request . getCategory () .trim ());
131+ resource .setDescription (request . getDescription () == null ? null : request . getDescription () .trim ());
126132 resource .setUrl (fileUrl );
127133 resource .setResourceType ("FILE" );
128134 resource .setOriginalFileName (file .getOriginalFilename ());
129135 resource .setFileSizeBytes (file .getSize ());
136+ applyMetadata (resource , request .getLocation (), request .getCompany (), request .getEventDate (), request .getListingType ());
130137 applySubmitter (resource , user );
131138
132139 return toDTO (resourceRepository .save (resource ), email );
@@ -173,10 +180,12 @@ public CareerResourceDTO updateResource(String email, UUID resourceId, UpdateCar
173180 resource .setUrl (normalizeUrl (request .getUrl ()));
174181 }
175182
183+ applyMetadata (resource , request .getLocation (), request .getCompany (), request .getEventDate (), request .getListingType ());
184+
176185 return toDTO (resourceRepository .save (resource ), email );
177186 }
178187
179- private Specification <CareerResource > buildResourceFilter (String query , String category , String type ) {
188+ private Specification <CareerResource > buildExploreFilter (String query , String category , String type , String location , String listingType ) {
180189 return (root , criteriaQuery , criteriaBuilder ) -> {
181190 var predicates = new ArrayList <Predicate >();
182191 if (query != null ) {
@@ -185,6 +194,8 @@ private Specification<CareerResource> buildResourceFilter(String query, String c
185194 criteriaBuilder .like (criteriaBuilder .lower (root .get ("title" )), likeQuery ),
186195 criteriaBuilder .like (criteriaBuilder .lower (root .get ("category" )), likeQuery ),
187196 criteriaBuilder .like (criteriaBuilder .lower (root .get ("description" )), likeQuery ),
197+ criteriaBuilder .like (criteriaBuilder .lower (root .get ("location" )), likeQuery ),
198+ criteriaBuilder .like (criteriaBuilder .lower (root .get ("company" )), likeQuery ),
188199 criteriaBuilder .like (criteriaBuilder .lower (root .get ("submittedByName" )), likeQuery )
189200 ));
190201 }
@@ -194,6 +205,12 @@ private Specification<CareerResource> buildResourceFilter(String query, String c
194205 if (type != null ) {
195206 predicates .add (criteriaBuilder .equal (criteriaBuilder .upper (root .get ("resourceType" )), type ));
196207 }
208+ if (location != null ) {
209+ predicates .add (criteriaBuilder .equal (criteriaBuilder .lower (root .get ("location" )), location .toLowerCase (Locale .ROOT )));
210+ }
211+ if (listingType != null ) {
212+ predicates .add (criteriaBuilder .equal (criteriaBuilder .upper (root .get ("listingType" )), listingType .toUpperCase (Locale .ROOT )));
213+ }
197214 return predicates .isEmpty () ? criteriaBuilder .conjunction () : criteriaBuilder .and (predicates .toArray (new Predicate [0 ]));
198215 };
199216 }
@@ -254,6 +271,24 @@ private CareerResourceDTO toDTO(CareerResource resource, String viewerEmail) {
254271 dto .setOwnedByCurrentUser (viewerEmail != null && resource .getSubmittedByEmail ().equalsIgnoreCase (viewerEmail ));
255272 dto .setSubmittedByName (resource .getSubmittedByName ());
256273 dto .setCreatedAt (resource .getCreatedAt ());
274+ dto .setLocation (resource .getLocation ());
275+ dto .setCompany (resource .getCompany ());
276+ dto .setEventDate (resource .getEventDate ());
277+ dto .setListingType (resource .getListingType ());
257278 return dto ;
258279 }
280+
281+ private void applyMetadata (CareerResource resource , String location , String company , String eventDate , String listingType ) {
282+ if (location != null ) resource .setLocation (location .trim ());
283+ if (company != null ) resource .setCompany (company .trim ());
284+ if (listingType != null ) resource .setListingType (listingType .trim ().toUpperCase (Locale .ROOT ));
285+
286+ if (eventDate != null && !eventDate .isBlank ()) {
287+ try {
288+ resource .setEventDate (java .time .LocalDateTime .parse (eventDate ));
289+ } catch (Exception e ) {
290+ // Ignore parsing errors for now or handle gracefully
291+ }
292+ }
293+ }
259294}
0 commit comments