Skip to content

Commit d221350

Browse files
committed
feat: Enhance event registration and unregistration processes with improved session profile management and entity handling
1 parent 82f4b0f commit d221350

4 files changed

Lines changed: 129 additions & 19 deletions

File tree

src/main/java/com/digitalsanctuary/spring/demo/event/EventAPIController.java

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,18 +74,27 @@ public ResponseEntity<Void> deleteEvent(@PathVariable Long id) {
7474
@PreAuthorize("hasAuthority('REGISTER_FOR_EVENT_PRIVILEGE')")
7575
@Transactional
7676
public ResponseEntity<Event> registerForEvent(@PathVariable Long eventId) {
77+
// Validate event exists first
7778
Optional<Event> event = eventService.getEventById(eventId);
7879
if (event.isEmpty()) {
7980
log.info("Event not found with id: {}", eventId);
8081
return ResponseEntity.notFound().build();
8182
}
83+
84+
// Get user profile from session
8285
DemoUserProfile userProfile = demoSessionProfile.getUserProfile();
83-
if (userProfile == null) {
84-
log.info("User not found in session");
86+
if (userProfile == null || userProfile.getId() == null) {
87+
log.info("User profile not found in session");
8588
return ResponseEntity.badRequest().build();
8689
}
87-
demoUserProfileService.registerForEvent(userProfile, event.get());
88-
log.info("User registered for event: {}", eventId);
90+
91+
// Register using IDs to ensure managed entities
92+
demoUserProfileService.registerForEvent(userProfile.getId(), eventId);
93+
log.info("User {} registered for event: {}", userProfile.getId(), eventId);
94+
95+
// Refresh the session profile to include the new registration
96+
demoSessionProfile.refreshProfile();
97+
8998
return ResponseEntity.ok(event.get());
9099
}
91100

@@ -98,19 +107,27 @@ public ResponseEntity<Event> registerForEvent(@PathVariable Long eventId) {
98107
@PostMapping("/{eventId}/unregister")
99108
@PreAuthorize("hasAuthority('REGISTER_FOR_EVENT_PRIVILEGE')")
100109
public ResponseEntity<Event> unregisterFromEvent(@PathVariable Long eventId) {
110+
// Validate event exists first
101111
Optional<Event> event = eventService.getEventById(eventId);
102112
if (event.isEmpty()) {
103113
log.info("Event not found with id: {}", eventId);
104114
return ResponseEntity.notFound().build();
105115
}
116+
117+
// Get user profile from session
106118
DemoUserProfile userProfile = demoSessionProfile.getUserProfile();
107-
if (userProfile == null) {
108-
log.info("User not found in session");
119+
if (userProfile == null || userProfile.getId() == null) {
120+
log.info("User profile not found in session");
109121
return ResponseEntity.badRequest().build();
110122
}
111123

112-
demoUserProfileService.unregisterFromEvent(userProfile, event.get());
113-
log.info("User unregistered from event: {}", eventId);
124+
// Unregister using IDs to ensure managed entities
125+
demoUserProfileService.unregisterFromEvent(userProfile.getId(), eventId);
126+
log.info("User {} unregistered from event: {}", userProfile.getId(), eventId);
127+
128+
// Refresh the session profile to reflect the unregistration
129+
demoSessionProfile.refreshProfile();
130+
114131
return ResponseEntity.ok(event.get());
115132
}
116133

src/main/java/com/digitalsanctuary/spring/demo/event/EventPageController.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,12 @@ public String eventDetails(@PathVariable("eventId") String eventId, Model model)
6060
// Add registration flag for authenticated users
6161
DemoUserProfile profile = demoSessionProfile.getUserProfile();
6262
if (profile != null) {
63-
boolean isRegistered = profile.isRegisteredForEvent(event);
64-
model.addAttribute("isRegistered", isRegistered);
63+
// Refresh profile to get latest registration status
64+
profile = demoSessionProfile.refreshProfile();
65+
if (profile != null) {
66+
boolean isRegistered = profile.isRegisteredForEvent(event);
67+
model.addAttribute("isRegistered", isRegistered);
68+
}
6569
}
6670
return "/event/details";
6771

@@ -94,7 +98,11 @@ public String myEvents(Model model) {
9498
DemoUserProfile profile = demoSessionProfile.getUserProfile();
9599
List<Event> myEvents = new ArrayList<>();
96100
if (profile != null) {
97-
myEvents = profile.getEventRegistrations().stream().map(EventRegistration::getEvent).collect(Collectors.toList());
101+
// Refresh the profile to ensure we have latest event registrations
102+
profile = demoSessionProfile.refreshProfile();
103+
if (profile != null) {
104+
myEvents = profile.getEventRegistrations().stream().map(EventRegistration::getEvent).collect(Collectors.toList());
105+
}
98106
}
99107
model.addAttribute("myEvents", myEvents);
100108
return "/event/my-events";

src/main/java/com/digitalsanctuary/spring/demo/user/profile/DemoUserProfileService.java

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.springframework.stereotype.Service;
44
import org.springframework.transaction.annotation.Transactional;
55
import com.digitalsanctuary.spring.demo.event.Event;
6+
import com.digitalsanctuary.spring.demo.event.EventRepository;
67
import com.digitalsanctuary.spring.user.persistence.model.User;
78
import com.digitalsanctuary.spring.user.persistence.repository.UserRepository;
89
import com.digitalsanctuary.spring.user.profile.UserProfileService;
@@ -114,6 +115,7 @@ public class DemoUserProfileService implements UserProfileService<DemoUserProfil
114115

115116
private final DemoUserProfileRepository profileRepository;
116117
private final UserRepository userRepository;
118+
private final EventRepository eventRepository;
117119

118120
/**
119121
* Retrieves an existing profile for the given user or creates a new one if none exists.
@@ -159,8 +161,44 @@ public DemoUserProfile updateProfile(DemoUserProfile profile) {
159161
return profileRepository.save(profile);
160162
}
161163

164+
/**
165+
* Registers a user profile for a specific event using IDs to ensure entities are managed.
166+
*
167+
* <p>
168+
* This method loads the profile and event as managed entities within the transaction,
169+
* avoiding issues with detached entities and cascade operations.
170+
*
171+
* @param profileId the ID of the profile to register for the event
172+
* @param eventId the ID of the event to register for
173+
* @return the updated profile with the event registration
174+
* @throws IllegalArgumentException if the profile or event is not found
175+
*/
176+
@Transactional
177+
public DemoUserProfile registerForEvent(Long profileId, Long eventId) {
178+
// Load managed entities within the transaction
179+
DemoUserProfile profile = profileRepository.findById(profileId)
180+
.orElseThrow(() -> new IllegalArgumentException("Profile not found with id: " + profileId));
181+
Event event = eventRepository.findById(eventId)
182+
.orElseThrow(() -> new IllegalArgumentException("Event not found with id: " + eventId));
183+
184+
// Check if already registered
185+
if (profile.isRegisteredForEvent(event)) {
186+
log.info("Profile {} is already registered for event {}", profileId, eventId);
187+
return profile;
188+
}
189+
190+
EventRegistration registration = new EventRegistration();
191+
registration.setEvent(event);
192+
profile.addEventRegistration(registration);
193+
194+
// No explicit save needed - transaction will persist changes to managed entities
195+
return profile;
196+
}
197+
162198
/**
163199
* Registers the given profile for a specific event.
200+
*
201+
* @deprecated Use {@link #registerForEvent(Long, Long)} instead to avoid issues with detached entities.
164202
*
165203
* <p>
166204
* This method demonstrates how to extend profile functionality with application-specific logic.
@@ -170,23 +208,47 @@ public DemoUserProfile updateProfile(DemoUserProfile profile) {
170208
* @return the updated profile with the event registration
171209
* @throws IllegalArgumentException if the profile or event is null
172210
*/
173-
@Transactional // added to ensure the session remains active
211+
@Deprecated
212+
@Transactional
174213
public DemoUserProfile registerForEvent(DemoUserProfile profile, Event event) {
175214
if (profile == null) {
176215
throw new IllegalArgumentException("Profile must not be null");
177216
}
178217
if (event == null) {
179218
throw new IllegalArgumentException("Event must not be null");
180219
}
220+
221+
// Delegate to the ID-based method to ensure we work with managed entities
222+
return registerForEvent(profile.getId(), event.getId());
223+
}
181224

182-
EventRegistration registration = new EventRegistration();
183-
registration.setEvent(event);
184-
profile.addEventRegistration(registration);
185-
return profileRepository.save(profile);
225+
/**
226+
* Unregisters a user profile from a specific event using IDs to ensure entities are managed.
227+
*
228+
* @param profileId the ID of the profile to unregister from the event
229+
* @param eventId the ID of the event to unregister from
230+
* @return the updated profile without the event registration
231+
* @throws IllegalArgumentException if the profile or event is not found
232+
*/
233+
@Transactional
234+
public DemoUserProfile unregisterFromEvent(Long profileId, Long eventId) {
235+
// Load managed entities within the transaction
236+
DemoUserProfile profile = profileRepository.findById(profileId)
237+
.orElseThrow(() -> new IllegalArgumentException("Profile not found with id: " + profileId));
238+
Event event = eventRepository.findById(eventId)
239+
.orElseThrow(() -> new IllegalArgumentException("Event not found with id: " + eventId));
240+
241+
profile.removeEventRegistration(event);
242+
log.info("Unregistered profile {} from event {}", profileId, eventId);
243+
244+
// No explicit save needed - transaction will persist changes to managed entities
245+
return profile;
186246
}
187247

188248
/**
189249
* Unregisters the given profile from a specific event.
250+
*
251+
* @deprecated Use {@link #unregisterFromEvent(Long, Long)} instead to avoid issues with detached entities.
190252
*
191253
* <p>
192254
* This method demonstrates how to extend profile functionality with application-specific logic.
@@ -196,15 +258,16 @@ public DemoUserProfile registerForEvent(DemoUserProfile profile, Event event) {
196258
* @return the updated profile without the event registration
197259
* @throws IllegalArgumentException if the profile or event is null
198260
*/
261+
@Deprecated
199262
public DemoUserProfile unregisterFromEvent(DemoUserProfile profile, Event event) {
200263
if (profile == null) {
201264
throw new IllegalArgumentException("Profile must not be null");
202265
}
203266
if (event == null) {
204267
throw new IllegalArgumentException("Event must not be null");
205268
}
206-
profile.removeEventRegistration(event);
207-
log.info("Unregistered profile {} from event {}", profile.getId(), event.getId());
208-
return profileRepository.save(profile);
269+
270+
// Delegate to the ID-based method to ensure we work with managed entities
271+
return unregisterFromEvent(profile.getId(), event.getId());
209272
}
210273
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,40 @@
11
package com.digitalsanctuary.spring.demo.user.profile.session;
22

3+
import org.springframework.beans.factory.annotation.Autowired;
34
import org.springframework.stereotype.Component;
45
import com.digitalsanctuary.spring.demo.event.Event;
56
import com.digitalsanctuary.spring.demo.user.profile.DemoUserProfile;
7+
import com.digitalsanctuary.spring.demo.user.profile.DemoUserProfileRepository;
68
import com.digitalsanctuary.spring.user.profile.session.BaseSessionProfile;
79

810
@Component
911
public class DemoSessionProfile extends BaseSessionProfile<DemoUserProfile> {
1012

13+
@Autowired
14+
private DemoUserProfileRepository profileRepository;
15+
1116
public boolean isRegisteredForEvent(Event event) {
1217
return getUserProfile() != null && getUserProfile().getEventRegistrations().stream().anyMatch(reg -> reg.getEvent().equals(event));
1318
}
1419

1520
public String getFavoriteColor() {
1621
return getUserProfile() != null ? getUserProfile().getFavoriteColor() : null;
1722
}
23+
24+
/**
25+
* Refreshes the user profile from the database to ensure we have the latest data
26+
* @return the refreshed user profile or null if no profile exists
27+
*/
28+
public DemoUserProfile refreshProfile() {
29+
DemoUserProfile currentProfile = getUserProfile();
30+
if (currentProfile != null && currentProfile.getId() != null) {
31+
DemoUserProfile refreshedProfile = profileRepository.findById(currentProfile.getId()).orElse(null);
32+
if (refreshedProfile != null) {
33+
// Update the session with the refreshed profile
34+
setUserProfile(refreshedProfile);
35+
return refreshedProfile;
36+
}
37+
}
38+
return currentProfile;
39+
}
1840
}

0 commit comments

Comments
 (0)