From 96410308146c8dee80439827d0ec5c9c36a30f45 Mon Sep 17 00:00:00 2001 From: Mehara Rothila Ranawaka Date: Fri, 7 Nov 2025 00:43:53 +0530 Subject: [PATCH 1/2] Update time log controller --- .../controller/TimeLogController.java | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/time-logging-service/src/main/java/com/techtorque/time_logging_service/controller/TimeLogController.java b/time-logging-service/src/main/java/com/techtorque/time_logging_service/controller/TimeLogController.java index ea48ceb..7ef40f9 100644 --- a/time-logging-service/src/main/java/com/techtorque/time_logging_service/controller/TimeLogController.java +++ b/time-logging-service/src/main/java/com/techtorque/time_logging_service/controller/TimeLogController.java @@ -4,6 +4,7 @@ import com.techtorque.time_logging_service.dto.request.TimeLogUpdateRequest; import com.techtorque.time_logging_service.dto.response.TimeLogResponse; import com.techtorque.time_logging_service.dto.response.TimeLogSummaryResponse; +import com.techtorque.time_logging_service.exception.UnauthorizedAccessException; import com.techtorque.time_logging_service.service.TimeLogService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -63,12 +64,12 @@ public TimeLogController(TimeLogService timeLogService) { @ApiResponse(responseCode = "403", description = "Forbidden - insufficient permissions") }) @PostMapping - @PreAuthorize("hasRole('EMPLOYEE')") + @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") public ResponseEntity createTimeLog( @Parameter(description = "Employee ID from authentication token", required = true) @RequestHeader(value = "X-User-Subject") String employeeId, @Valid @RequestBody TimeLogRequest request) { - + TimeLogResponse response = timeLogService.createTimeLog(employeeId, request); return ResponseEntity.status(HttpStatus.CREATED).body(response); } @@ -88,7 +89,7 @@ public ResponseEntity createTimeLog( @ApiResponse(responseCode = "403", description = "Forbidden") }) @GetMapping - @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN')") + @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") public ResponseEntity> getMyTimeLogs( @Parameter(description = "Employee ID from authentication token", required = true) @RequestHeader("X-User-Subject") String userId, @@ -97,11 +98,11 @@ public ResponseEntity> getMyTimeLogs( @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from, @Parameter(description = "End date for filtering (YYYY-MM-DD)") @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to) { - + List responses; - - // Admin can see all time logs - if (roles.contains("ADMIN")) { + + // Admin and Super Admin can see all time logs + if (roles.contains("ADMIN") || roles.contains("SUPER_ADMIN")) { if (from != null && to != null) { // For admin with date range, get all logs and filter (or create new method) responses = timeLogService.getAllTimeLogs().stream() @@ -118,7 +119,7 @@ public ResponseEntity> getMyTimeLogs( responses = timeLogService.getAllTimeLogsByEmployee(userId); } } - + return ResponseEntity.ok(responses); } @@ -138,7 +139,7 @@ public ResponseEntity> getMyTimeLogs( @ApiResponse(responseCode = "404", description = "Time log not found") }) @GetMapping("/{logId}") - @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN')") + @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") public ResponseEntity getTimeLogById( @Parameter(description = "Time log ID", required = true) @PathVariable String logId, @@ -146,7 +147,7 @@ public ResponseEntity getTimeLogById( @RequestHeader(value = "X-User-Subject", required = false) String userId, @Parameter(description = "User role from authentication token") @RequestHeader(value = "X-User-Role", required = false) String userRole) { - + TimeLogResponse response = timeLogService.getTimeLogByIdWithAuthorization(logId, userId, userRole); return ResponseEntity.ok(response); } @@ -167,14 +168,14 @@ public ResponseEntity getTimeLogById( @ApiResponse(responseCode = "404", description = "Time log not found") }) @PutMapping("/{logId}") - @PreAuthorize("hasRole('EMPLOYEE')") + @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") public ResponseEntity updateTimeLog( @Parameter(description = "Time log ID", required = true) @PathVariable String logId, @Parameter(description = "Employee ID from authentication token", required = true) @RequestHeader("X-User-Subject") String employeeId, @Valid @RequestBody TimeLogUpdateRequest request) { - + TimeLogResponse response = timeLogService.updateTimeLogWithAuthorization(logId, employeeId, request); return ResponseEntity.ok(response); } @@ -194,13 +195,20 @@ public ResponseEntity updateTimeLog( @ApiResponse(responseCode = "404", description = "Time log not found") }) @DeleteMapping("/{logId}") - @PreAuthorize("hasRole('EMPLOYEE')") + @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") public ResponseEntity deleteTimeLog( @Parameter(description = "Time log ID", required = true) @PathVariable String logId, - @Parameter(description = "Employee ID from authentication token", required = true) - @RequestHeader("X-User-Subject") String employeeId) { - + @Parameter(description = "Employee ID from authentication token", required = false) + @RequestHeader(value = "X-User-Subject", required = false) String employeeId, + @Parameter(description = "User role from authentication token", required = false) + @RequestHeader(value = "X-User-Roles", required = false) String userRoles) { + + // If header is missing, check if user is admin (can delete any log) + if (employeeId == null || employeeId.isEmpty()) { + throw new UnauthorizedAccessException("User identification missing. Please ensure you are logged in."); + } + timeLogService.deleteTimeLogWithAuthorization(logId, employeeId); return ResponseEntity.noContent().build(); } @@ -246,7 +254,7 @@ public ResponseEntity> getTimeLogsForService( @ApiResponse(responseCode = "403", description = "Forbidden") }) @GetMapping("/summary") - @PreAuthorize("hasRole('EMPLOYEE')") + @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") public ResponseEntity getSummary( @Parameter(description = "Employee ID from authentication token", required = true) @RequestHeader("X-User-Subject") String employeeId, @@ -254,7 +262,7 @@ public ResponseEntity getSummary( @RequestParam String period, @Parameter(description = "Reference date (YYYY-MM-DD)", required = true) @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) { - + TimeLogSummaryResponse summary = timeLogService.getEmployeeSummaryByPeriod(employeeId, period, date); return ResponseEntity.ok(summary); } @@ -288,11 +296,11 @@ public ResponseEntity> getTimeLogsForProject( description = "Get quick statistics including total hours logged, number of logs, and breakdown by service/project." ) @GetMapping("/stats") - @PreAuthorize("hasRole('EMPLOYEE')") + @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") public ResponseEntity> getEmployeeStats( @Parameter(description = "Employee ID from authentication token", required = true) @RequestHeader("X-User-Subject") String employeeId) { - + Map stats = timeLogService.getEmployeeStatistics(employeeId); return ResponseEntity.ok(stats); } From d7a18c1af0d896de4d33115435bd2f190239838c Mon Sep 17 00:00:00 2001 From: RandithaK Date: Wed, 12 Nov 2025 00:32:24 +0530 Subject: [PATCH 2/2] fix: Restrict pull request triggers to specific branches in build workflow --- .github/workflows/buildtest.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/buildtest.yaml b/.github/workflows/buildtest.yaml index 1360d67..f89d785 100644 --- a/.github/workflows/buildtest.yaml +++ b/.github/workflows/buildtest.yaml @@ -1,12 +1,11 @@ name: Build and Test Time Logging Service on: - push: - branches: - - '**' pull_request: branches: - - '**' + - main + - dev + - devOps jobs: build-test: