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
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.hospital.hms.base.service;

import com.hospital.hms.base.request.BaseRequest;
import com.hospital.hms.config.JwtContextExtractor;
import com.hospital.hms.exception.BusinessException;
import com.hospital.hms.exception.NotFoundException;
import com.hospital.hms.exception.ValidationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;

import java.util.Optional;

Expand Down Expand Up @@ -87,6 +91,10 @@ protected void validate(REQ request) {
public RES execute(REQ request) {
if (request != null) {
request.initialize();
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication instanceof JwtAuthenticationToken authenticationToken) {
request.setUserContext(JwtContextExtractor.extractUserContext(authenticationToken.getToken()));
}
}
validate(request);
return doProcess(request);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.hospital.hms.config;

import com.hospital.hms.base.UserContext;
import com.hospital.hms.exception.IdentityProviderException;
import org.springframework.security.oauth2.jwt.Jwt;

import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

public class JwtContextExtractor {

public static UserContext extractUserContext(Jwt jwt) {
Object sub = jwt.getClaims().get("sub");

if (sub == null) {
throw new IdentityProviderException("Missing sub claim");
}

Object username = jwt.getClaims().get("preferred_username");
Object email = jwt.getClaims().get("email");

Map<String, Object> realmAccess = (Map<String, Object>) jwt.getClaims().get("realm_access");

if (realmAccess == null || realmAccess.isEmpty()) {
throw new IdentityProviderException("Missing real_access in JWT.");
}

Collection<String> roles = (Collection<String>) realmAccess.get("roles");

if (roles == null || roles.isEmpty()) {
throw new IdentityProviderException("Missing roles in JWT.");
}

return UserContext.builder()
.userId(UUID.fromString((String) sub))
.username((String) username)
.email((String) email)
.roles(roles.stream().map(role -> "ROLE_" + role.toUpperCase()).collect(Collectors.toSet()))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.hospital.hms.employee.entity.EmployeeInfo;
import com.hospital.hms.employee.repository.EmployeeInfoRepository;
import com.hospital.hms.employee.request.EmployeeIdRequest;
import com.hospital.hms.exception.BusinessException;
import com.hospital.hms.exception.IdentityProviderException;
import com.hospital.hms.exception.NotFoundException;
import com.hospital.hms.keycloak.service.KeycloakService;
Expand All @@ -25,6 +26,10 @@ protected Void doProcess(EmployeeIdRequest request) {
() -> new NotFoundException("Employee with id: " + request.getId() + " not found")
);

if (employee.getAccount().getIsActive()) {
throw new BusinessException("Employee is already active");
}

employee.getAccount().setIsActive(true);
employeeInfoRepository.save(employee);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.hospital.hms.employee.entity.EmployeeInfo;
import com.hospital.hms.employee.repository.EmployeeInfoRepository;
import com.hospital.hms.employee.request.EmployeeIdRequest;
import com.hospital.hms.exception.BusinessException;
import com.hospital.hms.exception.IdentityProviderException;
import com.hospital.hms.exception.NotFoundException;
import com.hospital.hms.keycloak.service.KeycloakService;
Expand All @@ -25,6 +26,10 @@ protected Void doProcess(EmployeeIdRequest request) {
() -> new NotFoundException("Employee with id: " + request.getId() + " not found")
);

if (!employee.getAccount().getIsActive()) {
throw new BusinessException("Employee is already de-active");
}

employee.getAccount().setIsActive(false);
employeeInfoRepository.save(employee);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.hospital.hms.employee.repository.EmployeeInfoRepository;
import com.hospital.hms.employee.request.UpdateEmployeeRequest;
import com.hospital.hms.employee.response.EmployeeResponse;
import com.hospital.hms.exception.BusinessException;
import com.hospital.hms.exception.DuplicateResourceException;
import com.hospital.hms.exception.IdentityProviderException;
import com.hospital.hms.exception.NotFoundException;
Expand Down Expand Up @@ -41,7 +42,6 @@ protected EmployeeResponse doProcess(UpdateEmployeeRequest request) {
throw new DuplicateResourceException("Code already exists: " + request.getCode());
}


if (request.getFirstName() != null) employee.getAccount().setFirstName(request.getFirstName());
if (request.getLastName() != null) employee.getAccount().setLastName(request.getLastName());
if (request.getDob() != null) employee.getAccount().setDob(request.getDob());
Expand All @@ -51,8 +51,6 @@ protected EmployeeResponse doProcess(UpdateEmployeeRequest request) {
if (request.getCode() != null) employee.setCode(request.getCode());
if (request.getHireDate() != null) employee.setHireDate(request.getHireDate());

String oldRoleName = employee.getAccount().getRole().getName();

if (request.getRole() != null) {
Role role = roleRepository.findByNameIgnoreCase(request.getRole())
.orElseThrow(() -> new NotFoundException("Role not found: " + request.getRole()));
Expand All @@ -67,6 +65,11 @@ protected EmployeeResponse doProcess(UpdateEmployeeRequest request) {
EmployeeInfo updated = employeeInfoRepository.save(employee);

if (request.getRole() != null) {
String oldRoleName = employee.getAccount().getRole().getName();

if (employee.getAccount().getRole() == null)
throw new BusinessException("Employee account has no role assigned");

try {
keycloakService.updateRole(employee.getAccount().getId().toString(), request.getRole(), oldRoleName);
} catch (Exception e) {
Expand All @@ -78,11 +81,6 @@ protected EmployeeResponse doProcess(UpdateEmployeeRequest request) {
return EmployeeResponse.from(updated);
}

@Override
protected void validate(UpdateEmployeeRequest request) {
super.validate(request);
}

@Override
@Transactional
public EmployeeResponse execute(UpdateEmployeeRequest request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
Expand Down Expand Up @@ -165,7 +165,7 @@ public ResponseEntity<ApiResponse<Object>> handleDataIntegrityViolationException
"A record with the provided data already exists. Please contact support with trace ID: " + traceId,
"DUPLICATE_RESOURCE"
);
return buildErrorResponse(HttpStatus.CONFLICT, "handleDataIntegrityViolationException", List.of(error), traceId, request);
return buildErrorResponse(HttpStatus.CONFLICT, "Duplicate resource.", List.of(error), traceId, request);
}

// ==================== Private Helpers ====================
Expand Down
Loading