Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/main/java/backendlab/team4you/Team4youApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,32 @@ ApplicationRunner init(UserRepository repository, BCryptPasswordEncoder encoder)

repository.save(devUser);
System.out.println("✅ User created");

UserEntity officer1 = new UserEntity(
Bytes.fromBase64("YLRtaW5="),
"officer1",
"caseofficer1"
);

officer1.setPasswordHash(encoder.encode("officer1"));
officer1.setRole(UserRole.CASE_OFFICER);
officer1.setEmail("devcaseofficer@gmail.com");

repository.save(officer1);
System.out.println("✅ Case officer 1 created");

UserEntity officer2 = new UserEntity(
Bytes.fromBase64("YLRtaG6="),
"officer2",
"caseofficer2"
);

officer2.setPasswordHash(encoder.encode("officer2"));
officer2.setRole(UserRole.CASE_OFFICER);
officer2.setEmail("devcaseofficer2@gmail.com");

repository.save(officer2);
System.out.println("✅ Case officer 2 created");
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,17 @@ public CaseFile uploadFile(
ConfidentialityLevel effectiveConfidentialityLevel =
confidentialityLevel != null ? confidentialityLevel : ConfidentialityLevel.OPEN;

if (!caseFileAccessService.canUploadFile(actor, caseRecordId, effectiveConfidentialityLevel)) {
CaseRecord caseRecord = caseRecordRepository.findByIdWithLock(caseRecordId)
.orElseThrow(() -> new CaseRecordNotFoundException(caseRecordId));

if (!caseFileAccessService.canUploadFile(actor, caseRecord, effectiveConfidentialityLevel)) {
throw new AccessDeniedException("Du har inte behörighet att ladda upp denna fil.");
}

if (file.getSize() > MAX_FILE_SIZE_BYTES) {
throw new FileTooLargeException(MAX_FILE_SIZE_BYTES);
}

CaseRecord caseRecord = caseRecordRepository.findByIdWithLock(caseRecordId)
.orElseThrow(() -> new CaseRecordNotFoundException(caseRecordId));

int nextDocumentNumber = allocateNextDocumentNumber(caseRecord.getId());
String documentReference = caseRecord.getCaseNumber() + "-" + nextDocumentNumber;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package backendlab.team4you.casefile.access;

import backendlab.team4you.casefile.CaseFile;
import backendlab.team4you.caserecord.CaseRecord;
import backendlab.team4you.caserecord.CaseRecordRepository;
import backendlab.team4you.common.ConfidentialityLevel;
import backendlab.team4you.user.UserEntity;
import backendlab.team4you.user.UserRole;
Expand Down Expand Up @@ -28,6 +30,9 @@ public boolean canViewFile(UserEntity user, CaseFile caseFile) {
return true;
}

if (isAssignedOfficer(user, caseFile.getCaseRecord()))
return true;

return hasConfidentialFileAccess(user, caseFile);
}

Expand All @@ -40,10 +45,13 @@ public boolean canDeleteFile(UserEntity user, CaseFile caseFile) {
return true;
}

if (isAssignedOfficer(user, caseFile.getCaseRecord()))
return true;

return hasConfidentialFileAccess(user, caseFile);
}

public boolean canUploadFile(UserEntity user, Long caseRecordId, ConfidentialityLevel confidentialityLevel) {
public boolean canUploadFile(UserEntity user, CaseRecord caseRecord, ConfidentialityLevel confidentialityLevel) {
if (user == null) {
return false;
}
Expand All @@ -52,6 +60,9 @@ public boolean canUploadFile(UserEntity user, Long caseRecordId, Confidentiality
return true;
}

if (isAssignedOfficer(user, caseRecord))
return true;

ConfidentialityLevel effectiveLevel =
confidentialityLevel != null ? confidentialityLevel : ConfidentialityLevel.OPEN;

Expand All @@ -60,7 +71,7 @@ public boolean canUploadFile(UserEntity user, Long caseRecordId, Confidentiality
}

return caseFileAccessRepository.existsByCaseRecordIdAndUserIdAndCanViewConfidentialFilesTrue(
caseRecordId,
caseRecord.getId(),
user.getIdAsString()
);
}
Expand All @@ -75,4 +86,11 @@ private boolean hasConfidentialFileAccess(UserEntity user, CaseFile caseFile) {
private boolean isAdmin(UserEntity user) {
return user.getRole() == UserRole.ADMIN;
}

private boolean isAssignedOfficer(UserEntity user, CaseRecord caseRecord) {
if (user.getRole() != UserRole.CASE_OFFICER)
return false;
UserEntity assignedUser = caseRecord.getAssignedUser();
return assignedUser != null && assignedUser.getIdAsString().equals(user.getIdAsString());
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package backendlab.team4you.caserecord;

import jakarta.persistence.LockModeType;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
Expand All @@ -16,4 +19,7 @@ public interface CaseRecordRepository extends JpaRepository<CaseRecord, Long> {
@Query("select c from CaseRecord c where c.id = :id")
Optional<CaseRecord> findByIdWithLock(Long id);
boolean existsByCaseNumber(String caseNumber);

@Query("SELECT c FROM CaseRecord c WHERE c.assignedUser.id = :officerId")
Page<CaseRecord> findByAssignedUserId(String officerId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,14 @@ public void onAuthenticationSuccess(HttpServletRequest request,
if (isAdmin)
getRedirectStrategy().sendRedirect(request, response, "/admin");
else {
getRedirectStrategy().sendRedirect(request, response, "/home");
boolean isCaseOfficer = authorities.stream()
.anyMatch(a -> a.getAuthority().equals("ROLE_CASE_OFFICER"));

if(isCaseOfficer)
getRedirectStrategy().sendRedirect(request, response, "/case-officer");
else {
getRedirectStrategy().sendRedirect(request, response, "/home");
}
}
}
}
8 changes: 5 additions & 3 deletions src/main/java/backendlab/team4you/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class SecurityConfig {

private static final String ADMIN = "ADMIN";
private static final String LOGIN = "/login";
private static final String CASE_OFFICER = "CASE_OFFICER";

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http,
Expand All @@ -42,10 +43,11 @@ SecurityFilterChain securityFilterChain(HttpSecurity http,
.requestMatchers(HttpMethod.GET, "/api/files/download/**").hasRole(ADMIN)
.requestMatchers(HttpMethod.DELETE, "/api/files/delete/**").hasRole(ADMIN)

.requestMatchers("/webauthn/**").hasAnyRole("USER", ADMIN)
.requestMatchers("/webauthn/**").hasAnyRole("USER", ADMIN, CASE_OFFICER)
.requestMatchers("/admin/**").hasRole(ADMIN)
.requestMatchers("/home", "/profile/**").hasAnyRole("USER", ADMIN)
.requestMatchers("/add-passkey", "/webauthn/register/**").hasAnyRole("USER", ADMIN)
.requestMatchers("/case-officer/**").hasRole(CASE_OFFICER)
.requestMatchers("/home", "/profile/**").hasAnyRole("USER", ADMIN, CASE_OFFICER)
.requestMatchers("/add-passkey", "/webauthn/register/**").hasAnyRole("USER", ADMIN, CASE_OFFICER)

.anyRequest().authenticated()
)
Expand Down
75 changes: 58 additions & 17 deletions src/main/java/backendlab/team4you/controller/AdminController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
import backendlab.team4you.application.ApplicationRepository;
import backendlab.team4you.application.ApplicationService;
import backendlab.team4you.booking.BookingService;
import backendlab.team4you.caserecord.CaseRecord;
import backendlab.team4you.caserecord.CaseRecordRepository;
import backendlab.team4you.exceptions.CaseRecordNotFoundException;
import backendlab.team4you.exceptions.UserNotFoundException;
import backendlab.team4you.service.LogService;
import backendlab.team4you.user.UserEntity;
import backendlab.team4you.user.UserRepository;
import backendlab.team4you.user.UserRole;
import backendlab.team4you.user.UserService;
import groovy.util.logging.Slf4j;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
Expand All @@ -26,8 +30,10 @@

import java.util.List;

import static backendlab.team4you.user.UserRole.CASE_OFFICER;



@Slf4j
@Controller
@PreAuthorize("hasRole('ADMIN')")
public class AdminController {
Expand All @@ -39,16 +45,20 @@ public class AdminController {
private final ApplicationService applicationService;
private final ApplicationRepository applicationRepository;
private final UserRepository userRepository;

public AdminController(UserService userService, BookingService bookingService, ApplicationService applicationService, ApplicationRepository applicationRepository, UserRepository userRepository) {
private final CaseRecordRepository caseRecordRepository;

public AdminController(UserService userService,
BookingService bookingService,
ApplicationService applicationService,
ApplicationRepository applicationRepository,
UserRepository userRepository,
CaseRecordRepository caseRecordRepository) {
this.userService = userService;
this.bookingService = bookingService;
this.applicationService = applicationService;
this.applicationRepository = applicationRepository;
this.userRepository = userRepository;



this.caseRecordRepository = caseRecordRepository;
}

@GetMapping("/admin/logs")
Expand All @@ -63,9 +73,6 @@ public String logs(Model model) {
return "fragments/admin-logs :: content";
}




@PostMapping("/admin/users")
public String deleteUser(@RequestParam String id, Model model){

Expand All @@ -82,24 +89,18 @@ public String deleteLog(@RequestParam String log) {
return "";
}




@GetMapping("/admin")
public String admin(Authentication auth) {
System.out.println(auth.getAuthorities());

return "admin";
}


@GetMapping("/admin/applications")
public String adminApplications(
@RequestParam(defaultValue = "0") int page,
Model model
) {


Page<ApplicationEntity> applications =
applicationRepository.findAll(PageRequest.of(page, 5));

Expand All @@ -110,7 +111,6 @@ public String adminApplications(
return "fragments/admin-applications :: content";
}


@GetMapping("/admin/bookings")
public String adminBookings(Model model){

Expand Down Expand Up @@ -170,4 +170,45 @@ public String deleteApplication(@RequestParam Long id, Model model) {

return "fragments/alert :: success";
}

@GetMapping("/admin/cases")
public String listCases(
@RequestParam(defaultValue = "0") int page,
Model model
) {
Page<CaseRecord> cases = caseRecordRepository.findAll(PageRequest.of(page, 10));
List<UserEntity> officers = userRepository.findByRole(UserRole.CASE_OFFICER);

model.addAttribute("cases", cases.getContent());
model.addAttribute("officers", officers);
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", cases.getTotalPages());

return "fragments/admin-cases :: content";
}

@PostMapping("/admin/cases/assign")
public String assignCase(
@RequestParam Long caseId,
@RequestParam String officerId,
Model model
) {
CaseRecord caseRecord = caseRecordRepository.findById(caseId)
.orElseThrow(() -> new CaseRecordNotFoundException(caseId));

UserEntity officer = userRepository.findById(officerId)
.orElseThrow(() -> new UserNotFoundException("Officer not found"));

if (officer.getRole() != UserRole.CASE_OFFICER) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Selected user is not a case officer");
}

caseRecord.setAssignedUser(officer);
caseRecordRepository.save(caseRecord);

model.addAttribute("message", "Ärende tilldelat till " + officer.getDisplayName());
return "fragments/alert :: success";
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package backendlab.team4you.controller;

import backendlab.team4you.caserecord.CaseRecord;
import backendlab.team4you.caserecord.CaseRecordRepository;
import backendlab.team4you.caserecord.CaseRecordService;
import backendlab.team4you.caserecord.CaseStatus;
import backendlab.team4you.exceptions.CaseRecordNotFoundException;
import backendlab.team4you.exceptions.UserNotFoundException;
import backendlab.team4you.user.UserEntity;
import backendlab.team4you.user.UserRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.server.ResponseStatusException;

@Controller
@PreAuthorize("hasRole('CASE_OFFICER')")
public class CaseOfficerController {

private final CaseRecordRepository caseRecordRepository;
private final UserRepository userRepository;

public CaseOfficerController(CaseRecordRepository caseRecordRepository, UserRepository userRepository) {
this.caseRecordRepository = caseRecordRepository;
this.userRepository = userRepository;
}

@GetMapping("/case-officer")
public String caseOfficerHome() {
return "case-officer";
}

@GetMapping("/case-officer/cases")
public String listCases(
@RequestParam(defaultValue = "0") int page,
Authentication auth,
Model model
) {
UserEntity officer = userRepository.findByName(auth.getName())
.orElseThrow(() -> new UserNotFoundException("Case Officer not found"));

Page<CaseRecord> cases =
caseRecordRepository.findByAssignedUserId(officer.getIdAsString(), PageRequest.of(page, 5));

model.addAttribute("cases", cases.getContent());
model.addAttribute("currentPage", page);
model.addAttribute("totalPages", cases.getTotalPages());

return "fragments/case-officer-cases :: content";
}

@PostMapping("/case-officer/cases/close")
@ResponseBody
public String closeCase(@RequestParam String id, Authentication auth) {
UserEntity officer = userRepository.findByName(auth.getName())
.orElseThrow(() -> new UserNotFoundException("Case Officer not found"));

CaseRecord caseRecord = caseRecordRepository.findById(Long.valueOf(id))
.orElseThrow(() -> new CaseRecordNotFoundException(id));

if (!caseRecord.getAssignedUser().getId().equals(officer.getId())) {
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Not assigned to this officer");
}

caseRecord.setStatus(CaseStatus.CLOSED);
caseRecordRepository.save(caseRecord);

return "";
}
}
Loading