-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/visa view controller #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
88b923c
30ce174
a25a984
0568740
7237829
9717435
47dfe1a
64a70cb
c5ec8b2
584de54
378519f
1322f3c
2fd457a
77e4e58
d16cec6
ea89dab
0f4002a
f17034a
b84820b
03701f6
4ffd190
5f4d789
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,7 +1,12 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| package org.example.visacasemanagementsystem; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.example.visacasemanagementsystem.user.UserAuthorization; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.example.visacasemanagementsystem.user.entity.User; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.example.visacasemanagementsystem.user.repository.UserRepository; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.boot.CommandLineRunner; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.boot.SpringApplication; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.context.annotation.Bean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.data.jpa.repository.config.EnableJpaAuditing; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @SpringBootApplication | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -12,4 +17,39 @@ public static void main(String[] args) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SpringApplication.run(VisaCaseManagementSystemApplication.class, args); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Bean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public CommandLineRunner initData(UserRepository userRepository) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return args -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Skapa en vanlig användare (Applicant) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (userRepository.findByEmail("user@test.com").isEmpty()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| User user = new User(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user.setFullName("USER"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user.setEmail("user@test.com"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user.setPassword("password"); // Notera: Du behöver sätta lösenord om din entitet kräver det | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user.setUserAuthorization(UserAuthorization.USER); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userRepository.save(user); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("Testanvändare skapad med ID: " + user.getId()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| User admin = new User(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| admin.setFullName("ADMIN"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| admin.setEmail("user@test.com2"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| admin.setPassword("password"); // Notera: Du behöver sätta lösenord om din entitet kräver det | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| admin.setUserAuthorization(UserAuthorization.ADMIN); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userRepository.save(admin); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("Test-admin skapad med ID: " + admin.getId()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Skapa en admin (Handler) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (userRepository.findByEmail("admin@test.com").isEmpty()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| User sysadmin = new User(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sysadmin.setFullName("SYSTEM ADMIN"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sysadmin.setEmail("admin@test.com"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sysadmin.setPassword("password"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sysadmin.setUserAuthorization(UserAuthorization.SYSADMIN); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userRepository.save(sysadmin); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| System.out.println("Test-sysadmin skapad med ID: " + sysadmin.getId()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+20
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard this seed runner behind a non-production profile. This bean creates known accounts with predictable credentials on every startup. In any shared or production-like environment, that becomes a built-in backdoor rather than test data. 🔒 Safer baseline+import org.springframework.context.annotation.Profile;
...
- `@Bean`
+ `@Bean`
+ `@Profile`("dev")
public CommandLineRunner initData(UserRepository userRepository) {📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package org.example.visacasemanagementsystem.config; | ||
|
|
||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
| import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||
| import org.springframework.security.web.SecurityFilterChain; | ||
|
|
||
| @Configuration | ||
| public class SecurityConfig { | ||
|
|
||
| @Bean | ||
| public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { | ||
| http | ||
| .authorizeHttpRequests(auth -> auth | ||
| .anyRequest().permitAll() | ||
| ) | ||
| .csrf(csrf -> csrf.disable()) | ||
| .headers(headers -> headers.frameOptions(frame -> frame.disable())); | ||
|
Comment on lines
+13
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, locate and examine SecurityConfig.java
fd -t f "SecurityConfig.java"Repository: ithsjava25/visa-case-management-system Length of output: 159 🏁 Script executed: # Read the SecurityConfig.java file to verify the exact code
fd -t f "SecurityConfig.java" -x cat -n {}Repository: ithsjava25/visa-case-management-system Length of output: 984 🏁 Script executed: # Examine VisaViewController to confirm currentUserId RequestParam usage
fd -t f "VisaViewController.java" -x head -100 {}Repository: ithsjava25/visa-case-management-system Length of output: 4013 🏁 Script executed: # Search for all handler methods in VisaViewController that use currentUserId
fd -t f "VisaViewController.java" -x rg -A 2 "@PostMapping|@GetMapping|@PutMapping" {}Repository: ithsjava25/visa-case-management-system Length of output: 1686 This config exposes every visa mutation to unauthenticated request parameter substitution. The combination of Require authentication for application routes, limit CSRF exceptions to H2 only, and use 🛡️ Safer baseline http
.authorizeHttpRequests(auth -> auth
- .anyRequest().permitAll()
+ .requestMatchers("/h2-console/**", "/error").permitAll()
+ .anyRequest().authenticated()
)
- .csrf(csrf -> csrf.disable())
- .headers(headers -> headers.frameOptions(frame -> frame.disable()));
+ .csrf(csrf -> csrf.ignoringRequestMatchers("/h2-console/**"))
+ .headers(headers -> headers.frameOptions(frame -> frame.sameOrigin()));
return http.build();🤖 Prompt for AI Agents |
||
| return http.build(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,6 @@ | |
|
|
||
| public enum VisaStatus { | ||
| SUBMITTED, | ||
| UNASSIGNED, | ||
| ASSIGNED, | ||
| INCOMPLETE, | ||
| GRANTED, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,230 @@ | ||
| package org.example.visacasemanagementsystem.visa.controller; | ||
|
|
||
| import jakarta.persistence.EntityNotFoundException; | ||
| import jakarta.validation.Valid; | ||
| import org.example.visacasemanagementsystem.comment.service.CommentService; | ||
| import org.example.visacasemanagementsystem.exception.UnauthorizedException; | ||
| import org.example.visacasemanagementsystem.user.UserAuthorization; | ||
| import org.example.visacasemanagementsystem.user.dto.UserDTO; | ||
| import org.example.visacasemanagementsystem.user.service.UserService; | ||
| import org.example.visacasemanagementsystem.visa.VisaType; | ||
| import org.example.visacasemanagementsystem.visa.dto.CreateVisaDTO; | ||
| import org.example.visacasemanagementsystem.visa.dto.UpdateVisaDTO; | ||
| import org.example.visacasemanagementsystem.visa.dto.VisaDTO; | ||
| import org.example.visacasemanagementsystem.visa.service.VisaService; | ||
| import org.springframework.stereotype.Controller; | ||
| import org.springframework.ui.Model; | ||
| import org.springframework.validation.BindingResult; | ||
| import org.springframework.web.bind.annotation.*; | ||
| import org.springframework.web.servlet.mvc.support.RedirectAttributes; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Controller | ||
| @RequestMapping("/visas") | ||
| public class VisaViewController { | ||
|
|
||
| private final VisaService visaService; | ||
| private final CommentService commentService; | ||
| private final UserService userService; | ||
|
|
||
| public VisaViewController(VisaService visaService, CommentService commentService, UserService userService) { | ||
| this.visaService = visaService; | ||
| this.commentService = commentService; | ||
| this.userService = userService; | ||
| } | ||
|
|
||
| @GetMapping("/dashboard") | ||
| public String showDashboard(@RequestParam Long currentUserId, Model model) { | ||
| // Find current user | ||
| UserDTO user = userService.findById(currentUserId) | ||
| .orElseThrow(() -> new EntityNotFoundException("User not found.")); | ||
|
Comment on lines
+38
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Spring Security artifacts:\n'
fd -i 'SecurityUser|UserDetailsServiceImpl|SecurityConfig' src/main/java
printf '\nRequest-supplied identity in VisaViewController:\n'
rg -n --type=java '@RequestParam\s+Long\s+currentUserId|findById\(currentUserId\)|findVisasByApplicant\(currentUserId\)|approveVisa\(id,\s*currentUserId\)|requestMoreInformation\(id,\s*currentUserId\)|rejectVisa\(id,\s*currentUserId\)|assignHandler\(id,\s*currentUserId\)' src/main/java/org/example/visacasemanagementsystem/visa/controller/VisaViewController.java
printf '\nAuthenticated-principal lookups in the web layer:\n'
rg -n --type=java '@AuthenticationPrincipal|SecurityContextHolder|getAuthentication\(' src/main/javaRepository: ithsjava25/visa-case-management-system Length of output: 1532 🏁 Script executed: # Check for build configuration and Spring Security dependency
fd -i 'pom\.xml|build\.gradle' src/ . | head -20
# Search for authentication/security-related code that might indicate integration
rg -n 'PasswordEncoder|BCrypt|UserDetailsService|AuthenticationManager|WebSecurityConfigurerAdapter' src/main/java --type=java
# Look for any Spring Security imports
rg -n 'import.*springframework\.security' src/main/java --type=java
# Check if user service has security-related methods
rg -n 'class.*UserService|implements.*UserDetailsService' src/main/java --type=java -A 5Repository: ithsjava25/visa-case-management-system Length of output: 781 🏁 Script executed: # Check pom.xml for Spring Security dependency
cat pom.xml | grep -A 2 -B 2 'security\|spring-security' || echo "No Spring Security found in pom.xml"
# Also verify the actual state of authentication in the application
rg -n 'public class.*Controller' src/main/java/org/example/visacasemanagementsystem/visa/controller/ --type=java -A 3 | head -40Repository: ithsjava25/visa-case-management-system Length of output: 1539 🏁 Script executed: # View the specific lines mentioned in the review to confirm the vulnerability
sed -n '38,41p' src/main/java/org/example/visacasemanagementsystem/visa/controller/VisaViewController.java
# Check if there's any authentication context usage in this controller
rg -n 'SecurityContextHolder|@AuthenticationPrincipal|getAuthentication|getPrincipal' src/main/java/org/example/visacasemanagementsystem/visa/controller/VisaViewController.javaRepository: ithsjava25/visa-case-management-system Length of output: 334 🏁 Script executed: # Check the processUpdate method and the missing statusInformation regression (around lines 146-152)
sed -n '140,160p' src/main/java/org/example/visacasemanagementsystem/visa/controller/VisaViewController.java
# Also check if there's a similar pattern in other methods to see the full scope of the issue
rg -n 'model\.addAttribute.*statusInformation|BindingResult|IllegalArgumentException' src/main/java/org/example/visacasemanagementsystem/visa/controller/VisaViewController.javaRepository: ithsjava25/visa-case-management-system Length of output: 1422 Stop trusting Every ownership/admin check in this controller is derived from a query/form parameter. A caller can impersonate another applicant—or an admin—just by supplying an admin id in the request, and Also add Applies to all handler methods: 38–41, 62–64, 77–80, 101–103, 131–135, 157–166, 174–185, 189–196, 216–218. 🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will later be resolved when we implement the missing Spring Security There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
✏️ Learnings added
🧠 Learnings used |
||
|
|
||
| List<VisaDTO> visas; | ||
|
|
||
| // If the current user = ADMIN/SYSADMIN show everything | ||
| if (user.userAuthorization() == UserAuthorization.ADMIN || | ||
| user.userAuthorization() == UserAuthorization.SYSADMIN) { | ||
| visas = visaService.findAll(); | ||
| } else { | ||
| // Normal user/applicant can only se their own visa applications | ||
| visas = visaService.findVisasByApplicant(currentUserId); | ||
| } | ||
|
|
||
| // Send data to Thymeleaf | ||
| model.addAttribute("visas", visas); | ||
| model.addAttribute("currentUser", user); | ||
|
|
||
| return "visa/dashboard"; | ||
| } | ||
|
|
||
| @GetMapping("/apply") | ||
| public String showApplyForm(@RequestParam Long currentUserId, Model model) { | ||
| UserDTO user = userService.findById(currentUserId) | ||
| .orElseThrow(() -> new EntityNotFoundException("User not found.")); | ||
|
|
||
| model.addAttribute("currentUser", user); | ||
| model.addAttribute("visaTypes", VisaType.values()); | ||
|
|
||
| if (!model.containsAttribute("createVisaDTO")) { | ||
| model.addAttribute("createVisaDTO", new CreateVisaDTO(null, "", "", null, currentUserId)); | ||
| } | ||
|
|
||
| return "visa/apply-form"; | ||
| } | ||
|
|
||
| @PostMapping("/apply") | ||
| public String submitApplication( | ||
| @Valid @ModelAttribute("createVisaDTO") CreateVisaDTO createVisaDTO, | ||
| BindingResult bindingResult, | ||
| @RequestParam Long currentUserId, | ||
| RedirectAttributes redirectAttributes, | ||
| Model model) { | ||
|
|
||
| if (bindingResult.hasErrors()) { | ||
| prepareApplyModel(currentUserId, model); | ||
| return "visa/apply-form"; | ||
| } | ||
|
|
||
| try { | ||
| visaService.applyForVisa(createVisaDTO, currentUserId); | ||
| } catch (IllegalArgumentException e) { | ||
| bindingResult.rejectValue("travelDate", "error.travelDate", e.getMessage()); | ||
| prepareApplyModel(currentUserId, model); | ||
| return "visa/apply-form"; | ||
| } | ||
|
|
||
| return "redirect:/visas/dashboard?currentUserId=" + currentUserId; | ||
| } | ||
|
|
||
| @GetMapping("/{id}/edit") | ||
| public String showEditForm(@PathVariable Long id, @RequestParam Long currentUserId, Model model) { | ||
| UserDTO userDTO = userService.findById(currentUserId) | ||
| .orElseThrow(() -> new EntityNotFoundException("User not found.")); | ||
|
|
||
| VisaDTO visa = visaService.findVisaDtoById(id); | ||
|
|
||
| if (!visa.applicantId().equals(currentUserId)) { | ||
| throw new UnauthorizedException("You can only edit your own applications."); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| UpdateVisaDTO updateDto = new UpdateVisaDTO( | ||
| visa.id(), | ||
| visa.visaType(), | ||
| visa.visaStatus(), | ||
| visa.nationality(), | ||
| visa.passportNumber(), | ||
| visa.travelDate(), | ||
| visa.handlerId() | ||
| ); | ||
|
|
||
| model.addAttribute("updateVisaDto", updateDto); | ||
| model.addAttribute("currentUser", userDTO); | ||
| model.addAttribute("visaTypes", VisaType.values()); | ||
| model.addAttribute("isEdit", true); | ||
| model.addAttribute("statusInformation", visa.statusInformation()); | ||
|
|
||
| return "visa/edit-form"; | ||
| } | ||
|
|
||
| @PostMapping("/{id}/edit") | ||
| public String processUpdate( | ||
| @PathVariable Long id, | ||
| @Valid @ModelAttribute ("updateVisaDto") UpdateVisaDTO updateVisaDTO, | ||
| BindingResult bindingResult, | ||
| @RequestParam Long currentUserId, | ||
| Model model) { | ||
|
|
||
| if (bindingResult.hasErrors()) { | ||
| prepareApplyModel(currentUserId, model); | ||
| model.addAttribute("isEdit", true); | ||
| VisaDTO visa = visaService.findVisaDtoById(id); | ||
| model.addAttribute("statusInformation", visa.statusInformation()); | ||
| return "visa/edit-form"; | ||
| } | ||
|
|
||
| try { | ||
| visaService.updateVisa(id, updateVisaDTO, currentUserId); | ||
| } catch (IllegalArgumentException e) { | ||
| if (e.getMessage().contains("date")) { | ||
| bindingResult.rejectValue("travelDate", "error.travelDate", e.getMessage()); | ||
| } else { | ||
| bindingResult.reject("globalError",e.getMessage()); | ||
| } | ||
|
|
||
| prepareApplyModel(currentUserId, model); | ||
| model.addAttribute("isEdit", true); | ||
| VisaDTO visa = visaService.findVisaDtoById(id); | ||
| model.addAttribute("statusInformation", visa.statusInformation()); | ||
|
|
||
| return "visa/edit-form"; | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
coderabbitai[bot] marked this conversation as resolved.
|
||
| return "redirect:/visas/" + id + "?currentUserId=" + currentUserId; | ||
| } | ||
|
|
||
| @PostMapping("/{id}/approve") | ||
| public String approveVisa(@PathVariable Long id, @RequestParam Long currentUserId) { | ||
| visaService.approveVisa(id, currentUserId); | ||
| return "redirect:/visas/" + id + "?currentUserId=" + currentUserId; | ||
| } | ||
|
|
||
| @PostMapping("/{id}/request-info") | ||
| public String requestMoreInformation(@PathVariable Long id, | ||
| @RequestParam Long currentUserId, | ||
| @RequestParam String reason) { | ||
|
|
||
| visaService.requestMoreInformation(id, currentUserId, reason); | ||
|
|
||
| return "redirect:/visas/" + id + "?currentUserId=" + currentUserId; | ||
| } | ||
|
|
||
|
|
||
| @PostMapping("/{id}/reject") | ||
| public String rejectVisa(@PathVariable Long id, | ||
| @RequestParam Long currentUserId, | ||
| @RequestParam String reason) { | ||
| visaService.rejectVisa(id, currentUserId, reason); | ||
| return "redirect:/visas/" + id + "?currentUserId=" + currentUserId; | ||
| } | ||
|
|
||
|
|
||
| @PostMapping("/{id}/assign") | ||
| public String assignCaseToHandler(@PathVariable Long id, @RequestParam Long currentUserId) { | ||
| visaService.assignHandler(id, currentUserId); | ||
| return "redirect:/visas/" + id + "?currentUserId=" + currentUserId; | ||
| } | ||
|
|
||
| @GetMapping("/{id}") | ||
| public String viewDetails(@PathVariable Long id, @RequestParam Long currentUserId, Model model) { | ||
| // Get visa | ||
| VisaDTO visa = visaService.findVisaDtoById(id); | ||
|
|
||
| // Get user | ||
| UserDTO user = userService.findById(currentUserId) | ||
| .orElseThrow(() -> new EntityNotFoundException("User not found.")); | ||
|
|
||
| // Authorization check: regular users can only view their own applications | ||
| if (user.userAuthorization() == UserAuthorization.USER && !visa.applicantId().equals(currentUserId)) { | ||
| throw new UnauthorizedException("You can only view your own applications."); | ||
| } | ||
|
|
||
| // Get comments | ||
| var comments = commentService.getCommentsByVisaId(id); | ||
|
|
||
|
|
||
| model.addAttribute("visa", visa); | ||
| model.addAttribute("comments", comments); | ||
| model.addAttribute("currentUser", user); | ||
|
|
||
| return "visa/details"; | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| // Helper methods | ||
|
|
||
| public void prepareApplyModel(Long currentUserId, Model model) { | ||
| UserDTO user = userService.findById(currentUserId) | ||
| .orElseThrow(() -> new EntityNotFoundException("User not found.")); | ||
| model.addAttribute("currentUser", user); | ||
| model.addAttribute("visaTypes", VisaType.values()); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seed each account behind its own lookup.
Lines 24-39 gate both the applicant and admin inserts on
findByEmail("user@test.com"), even though the admin is saved with a different email on Line 35. If the applicant exists but the admin row is missing, the admin will never be recreated.🧩 Suggested fix
📝 Committable suggestion
🤖 Prompt for AI Agents