Skip to content

Getting changes from main - #32

Merged
iSiRaH merged 35 commits into
Devfrom
main
Mar 12, 2026
Merged

Getting changes from main#32
iSiRaH merged 35 commits into
Devfrom
main

Conversation

@iSiRaH

@iSiRaH iSiRaH commented Mar 12, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

iSiRaH and others added 30 commits January 31, 2026 15:54
… recognition data, including faces, embeddings, and associated metadata.
Configure Dependabot for Maven and GitHub Actions updates with specific schedules and ignore rules.
Update CodeQL workflow for Java 21 analysis
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the spring group with 2 updates: [org.springframework.boot:spring-boot-starter-parent](https://github.com/spring-projects/spring-boot) and [org.springframework.boot:spring-boot-configuration-processor](https://github.com/spring-projects/spring-boot).


Updates `org.springframework.boot:spring-boot-starter-parent` from 3.5.8 to 4.0.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](spring-projects/spring-boot@v3.5.8...v4.0.2)

Updates `org.springframework.boot:spring-boot-configuration-processor` from 3.5.8 to 4.0.2
- [Release notes](https://github.com/spring-projects/spring-boot/releases)
- [Commits](spring-projects/spring-boot@v3.5.8...v4.0.2)

---
updated-dependencies:
- dependency-name: org.springframework.boot:spring-boot-starter-parent
  dependency-version: 4.0.2
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: spring
- dependency-name: org.springframework.boot:spring-boot-configuration-processor
  dependency-version: 4.0.2
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: spring
...

Signed-off-by: dependabot[bot] <support@github.com>
…s/checkout-6

Bump actions/checkout from 4 to 6
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4 to 5.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](actions/setup-java@v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
…s/setup-java-5

Bump actions/setup-java from 4 to 5
Added locations tracking
Merge Python Services with the Main
Copilot AI review requested due to automatic review settings March 12, 2026 14:06
public ResponseEntity<String> uploadEvidence(@RequestParam("file") MultipartFile file) throws Exception {

String fileUrl = supabaseService.uploadFile(file);
return ResponseEntity.ok(fileUrl);

Check failure

Code scanning / CodeQL

Cross-site scripting High

Cross-site scripting vulnerability due to a
user-provided value
.
Cross-site scripting vulnerability due to a
user-provided value
.

Copilot Autofix

AI 5 months ago

General approach: Ensure that user-controlled input incorporated into values returned to clients is constrained to a safe character set and/or encoded so it cannot be interpreted as executable HTML/JavaScript, even if a client misuses it. For file names and URLs, this typically means either sanitizing the name portion or returning a fully encoded/signed URL obtained from a trusted API.

Best concrete fix here:

  1. In SupabaseService.uploadFile, stop propagating raw file.getOriginalFilename() characters into the stored file name and ultimately to clients. Instead:

    • Extract the original file extension (if any).
    • Sanitize the base file name to a conservative character set (e.g., letters, digits, dots, underscores, hyphens), replacing anything else with _.
    • Keep the random UUID prefix to avoid collisions.
    • Optionally limit the overall length.
  2. In CrimeReportController.uploadEvidence, don’t expose the raw storage key directly. Instead, use the existing SupabaseService.getFileUrl method to return a signed, absolute URL for that key. This also better matches the method’s name (fileUrl) and reduces the likelihood that clients will treat a storage key as arbitrary HTML.

These changes are local to the shown snippets:

  • SupabaseService.java: add a private sanitizeFileName helper and use it in uploadFile when building fileName.
  • CrimeReportController.java: after uploadFile, call supabaseService.getFileUrl(fileName) and return that result.

No changes to external APIs are required, and existing functionality (uploading and later retrieving evidence) is preserved, with added safety.


Suggested changeset 2
src/main/java/com/crimeLink/analyzer/controller/CrimeReportController.java

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/main/java/com/crimeLink/analyzer/controller/CrimeReportController.java b/src/main/java/com/crimeLink/analyzer/controller/CrimeReportController.java
--- a/src/main/java/com/crimeLink/analyzer/controller/CrimeReportController.java
+++ b/src/main/java/com/crimeLink/analyzer/controller/CrimeReportController.java
@@ -57,7 +57,8 @@
     @PostMapping("/upload-evidence")
     public ResponseEntity<String> uploadEvidence(@RequestParam("file") MultipartFile file) throws Exception {
 
-        String fileUrl = supabaseService.uploadFile(file);
+        String fileName = supabaseService.uploadFile(file);
+        String fileUrl = supabaseService.getFileUrl(fileName);
         return ResponseEntity.ok(fileUrl);
     }
 
EOF
@@ -57,7 +57,8 @@
@PostMapping("/upload-evidence")
public ResponseEntity<String> uploadEvidence(@RequestParam("file") MultipartFile file) throws Exception {

String fileUrl = supabaseService.uploadFile(file);
String fileName = supabaseService.uploadFile(file);
String fileUrl = supabaseService.getFileUrl(fileName);
return ResponseEntity.ok(fileUrl);
}

src/main/java/com/crimeLink/analyzer/service/SupabaseService.java
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/main/java/com/crimeLink/analyzer/service/SupabaseService.java b/src/main/java/com/crimeLink/analyzer/service/SupabaseService.java
--- a/src/main/java/com/crimeLink/analyzer/service/SupabaseService.java
+++ b/src/main/java/com/crimeLink/analyzer/service/SupabaseService.java
@@ -39,7 +39,9 @@
             throw new RuntimeException("File size exceeds the limit of 10MB");
         }
 
-        String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
+        String originalFilename = file.getOriginalFilename();
+        String safeOriginalFilename = sanitizeFileName(originalFilename);
+        String fileName = UUID.randomUUID() + "_" + safeOriginalFilename;
 
         String uploadUrl = supabaseUrl + "/storage/v1/object/" + bucket + "/" + fileName;
 
@@ -55,6 +57,37 @@
         return fileName;
     }
 
+    private String sanitizeFileName(String originalFilename) {
+        if (originalFilename == null || originalFilename.isBlank()) {
+            return "file";
+        }
+
+        String trimmed = originalFilename.trim();
+
+        int lastDotIndex = trimmed.lastIndexOf('.');
+        String baseName;
+        String extension;
+
+        if (lastDotIndex > 0 && lastDotIndex < trimmed.length() - 1) {
+            baseName = trimmed.substring(0, lastDotIndex);
+            extension = trimmed.substring(lastDotIndex);
+        } else {
+            baseName = trimmed;
+            extension = "";
+        }
+
+        String safeBaseName = baseName.replaceAll("[^A-Za-z0-9._-]", "_");
+        if (safeBaseName.isBlank()) {
+            safeBaseName = "file";
+        }
+
+        if (safeBaseName.length() > 100) {
+            safeBaseName = safeBaseName.substring(0, 100);
+        }
+
+        return safeBaseName + extension;
+    }
+
     public String getFileUrl(String fileName) {
         String url = supabaseUrl + "/storage/v1/object/sign/" + bucket + "/" + fileName;
 
EOF
@@ -39,7 +39,9 @@
throw new RuntimeException("File size exceeds the limit of 10MB");
}

String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
String originalFilename = file.getOriginalFilename();
String safeOriginalFilename = sanitizeFileName(originalFilename);
String fileName = UUID.randomUUID() + "_" + safeOriginalFilename;

String uploadUrl = supabaseUrl + "/storage/v1/object/" + bucket + "/" + fileName;

@@ -55,6 +57,37 @@
return fileName;
}

private String sanitizeFileName(String originalFilename) {
if (originalFilename == null || originalFilename.isBlank()) {
return "file";
}

String trimmed = originalFilename.trim();

int lastDotIndex = trimmed.lastIndexOf('.');
String baseName;
String extension;

if (lastDotIndex > 0 && lastDotIndex < trimmed.length() - 1) {
baseName = trimmed.substring(0, lastDotIndex);
extension = trimmed.substring(lastDotIndex);
} else {
baseName = trimmed;
extension = "";
}

String safeBaseName = baseName.replaceAll("[^A-Za-z0-9._-]", "_");
if (safeBaseName.isBlank()) {
safeBaseName = "file";
}

if (safeBaseName.length() > 100) {
safeBaseName = safeBaseName.substring(0, 100);
}

return safeBaseName + extension;
}

public String getFileUrl(String fileName) {
String url = supabaseUrl + "/storage/v1/object/sign/" + bucket + "/" + fileName;

Copilot is powered by AI and may make mistakes. Always verify output.
* @param input the object whose string representation should be sanitized
* @return a sanitized string safe for logging; never {@code null}
*/
public static String sanitize(Object input) {

Check notice

Code scanning / CodeQL

Confusing overloading of methods Note

Method LogSanitizer.sanitize(..) could be confused with overloaded method
sanitize
, since dispatch depends on static types.

Copilot Autofix

AI 5 months ago

In general, to fix confusing overloading where one overload takes Object and another takes String, you should avoid having both overloads share the same name. Instead, keep the specific, type-safe method (sanitize(String)) as is and rename the broad-typed convenience method (sanitize(Object)) to a distinct name that clearly describes its behavior, then update its Javadoc accordingly.

In this file, the best fix with no functional change is:

  • Keep public static String sanitize(String input) exactly as it is.
  • Rename public static String sanitize(Object input) to a clearer, non-overloaded name such as sanitizeObject(Object input) (or similar).
  • Update the Javadoc @link and description above that method to reference the new name and make clear it’s a convenience wrapper around toString() plus sanitize(String).
  • Do not change the method body logic: still handle null by returning "null" and otherwise delegate to sanitize(input.toString()).

No additional imports or helper methods are required; all changes are local to LogSanitizer.java around the second method declaration and its Javadoc.

Suggested changeset 1
src/main/java/com/crimeLink/analyzer/util/LogSanitizer.java

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/main/java/com/crimeLink/analyzer/util/LogSanitizer.java b/src/main/java/com/crimeLink/analyzer/util/LogSanitizer.java
--- a/src/main/java/com/crimeLink/analyzer/util/LogSanitizer.java
+++ b/src/main/java/com/crimeLink/analyzer/util/LogSanitizer.java
@@ -72,13 +72,13 @@
     }
 
     /**
-     * Convenience overload that accepts any {@link Object}.
-     * Calls {@link Object#toString()} before sanitizing.
+     * Convenience method that accepts any {@link Object}.
+     * Calls {@link Object#toString()} before sanitizing via {@link #sanitize(String)}.
      *
      * @param input the object whose string representation should be sanitized
      * @return a sanitized string safe for logging; never {@code null}
      */
-    public static String sanitize(Object input) {
+    public static String sanitizeObject(Object input) {
         if (input == null) {
             return "null";
         }
EOF
@@ -72,13 +72,13 @@
}

/**
* Convenience overload that accepts any {@link Object}.
* Calls {@link Object#toString()} before sanitizing.
* Convenience method that accepts any {@link Object}.
* Calls {@link Object#toString()} before sanitizing via {@link #sanitize(String)}.
*
* @param input the object whose string representation should be sanitized
* @return a sanitized string safe for logging; never {@code null}
*/
public static String sanitize(Object input) {
public static String sanitizeObject(Object input) {
if (input == null) {
return "null";
}
Copilot is powered by AI and may make mistakes. Always verify output.
@iSiRaH
iSiRaH merged commit 00dc00e into Dev Mar 12, 2026
12 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR pulls in changes that expand the Spring Boot backend with (1) ML microservice gateway endpoints (call analysis + facial recognition), (2) officer location tracking, and (3) Supabase-backed evidence upload/signed download support, alongside security and build/config updates.

Changes:

  • Add new controllers/services for call analysis and facial recognition microservices, plus a shared RestTemplate config.
  • Add officer location tracking persistence + APIs (DTO/entity/repo/service/controller).
  • Add Supabase storage integration for evidence upload and signed download URLs; refresh-token rotation changes; SecurityConfig updates; CI/security automation files.

Reviewed changes

Copilot reviewed 37 out of 37 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
src/main/resources/application.properties Adds Supabase properties and multipart upload limits
src/main/java/com/crimeLink/analyzer/util/LogSanitizer.java Adds log sanitization utility to mitigate log injection
src/main/java/com/crimeLink/analyzer/service/impl/LocationServiceImpl.java Implements bulk location save and history/last-location queries
src/main/java/com/crimeLink/analyzer/service/SupabaseService.java Implements Supabase storage upload + signed URL retrieval
src/main/java/com/crimeLink/analyzer/service/RefreshTokenService.java Adds token rotation + “valid token” lookup behavior
src/main/java/com/crimeLink/analyzer/service/LocationService.java Introduces location service interface
src/main/java/com/crimeLink/analyzer/service/FacialRecognitionService.java Adds gateway service for facial recognition microservice
src/main/java/com/crimeLink/analyzer/service/DutyScheduleService.java Adds distinct-duty-location retrieval w/ defaults
src/main/java/com/crimeLink/analyzer/service/CrimeReportService.java Adds evidence persistence and signed URL enrichment
src/main/java/com/crimeLink/analyzer/service/CallAnalysisService.java Refactors to JSON passthrough gateway for call analysis microservice
src/main/java/com/crimeLink/analyzer/repository/RefreshTokenRepository.java Adds fetch-join query for refresh token + user
src/main/java/com/crimeLink/analyzer/repository/LocationPointRepository.java Adds repository for location point queries
src/main/java/com/crimeLink/analyzer/repository/DutyScheduleRepository.java Adds query for distinct duty locations
src/main/java/com/crimeLink/analyzer/repository/CallAnalysisRepository.java Removes persisted call analysis record repository
src/main/java/com/crimeLink/analyzer/mapper/CrimeReportMapper.java Adds evidence mapping into CrimeReportDTO
src/main/java/com/crimeLink/analyzer/entity/LocationPoint.java Adds location_points entity with JSON meta
src/main/java/com/crimeLink/analyzer/entity/Evidence.java Adds evidence entity linked to crime reports
src/main/java/com/crimeLink/analyzer/entity/CrimeReport.java Adds @OneToMany evidences relationship
src/main/java/com/crimeLink/analyzer/entity/CallAnalysisRecord.java Removes persisted call analysis record entity
src/main/java/com/crimeLink/analyzer/dto/LocationPointDTO.java Adds DTO for incoming location points
src/main/java/com/crimeLink/analyzer/dto/EvidenceDTO.java Adds DTO for evidence + download URL
src/main/java/com/crimeLink/analyzer/dto/CrimeReportDTO.java Adds evidence list field
src/main/java/com/crimeLink/analyzer/dto/CallAnalysisResultDTO.java Removes typed call analysis result DTO
src/main/java/com/crimeLink/analyzer/controller/LocationController.java Adds endpoints for location uploads/history/debug
src/main/java/com/crimeLink/analyzer/controller/FacialRecognitionController.java Adds REST API gateway endpoints for facial recognition
src/main/java/com/crimeLink/analyzer/controller/DutyScheduleController.java Adds endpoint to fetch duty locations
src/main/java/com/crimeLink/analyzer/controller/CrimeReportController.java Adds evidence upload + evidence download endpoints
src/main/java/com/crimeLink/analyzer/controller/CallAnalysisController.java Refactors call analysis controller to new gateway endpoints
src/main/java/com/crimeLink/analyzer/controller/AuthController.java Updates refresh-token handling to use rotation
src/main/java/com/crimeLink/analyzer/config/SecurityConfig.java Updates route authorization rules + exception handling
src/main/java/com/crimeLink/analyzer/config/RestTemplateConfig.java Adds configured RestTemplate bean (timeouts)
src/main/java/com/crimeLink/analyzer/config/JwtAuthenticationFilter.java Modifies JWT filter behavior and adds debug logging
pom.xml Adds dependencies/plugins and build-helper configuration
database/facial_recognition_tables.sql Adds DB schema for facial recognition feature
.github/workflows/codeql.yml Adds CodeQL analysis workflow
.github/dependabot.yml Adds Dependabot configuration
.env.example Adds example env vars for JWT + Supabase

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +63 to +80
@GetMapping("/debug/whoami")
public Map<String, Object> whoAmI(@AuthenticationPrincipal User user) {
Map<String, Object> info = new HashMap<>();
if (user != null) {
info.put("email", user.getEmail());
info.put("name", user.getName());
info.put("role", user.getRole());
info.put("authorities", user.getAuthorities().stream()
.map(auth -> auth.getAuthority())
.toList());
info.put("userId", user.getUserId());
info.put("badgeNo", user.getBadgeNo());
} else {
info.put("error", "No authenticated user");
}
return info;
}

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The /api/debug/whoami endpoint exposes user identity and authorities. Combined with permitAll on /api/debug/** in SecurityConfig, this can be used for reconnaissance; restrict this endpoint to admin roles or remove it before merging.

Suggested change
@GetMapping("/debug/whoami")
public Map<String, Object> whoAmI(@AuthenticationPrincipal User user) {
Map<String, Object> info = new HashMap<>();
if (user != null) {
info.put("email", user.getEmail());
info.put("name", user.getName());
info.put("role", user.getRole());
info.put("authorities", user.getAuthorities().stream()
.map(auth -> auth.getAuthority())
.toList());
info.put("userId", user.getUserId());
info.put("badgeNo", user.getBadgeNo());
} else {
info.put("error", "No authenticated user");
}
return info;
}

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +45
String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();

String uploadUrl = supabaseUrl + "/storage/v1/object/" + bucket + "/" + fileName;

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

file.getOriginalFilename() is incorporated into the stored object key. If the original filename contains path separators or control characters, this can create unexpected object paths (or confusing keys). Normalize/sanitize the filename (e.g., strip directories and disallow //\\ and control chars) before building fileName/uploadUrl.

Copilot uses AI. Check for mistakes.
Comment on lines +57 to +62
@PostMapping("/upload-evidence")
public ResponseEntity<String> uploadEvidence(@RequestParam("file") MultipartFile file) throws Exception {

String fileUrl = supabaseService.uploadFile(file);
return ResponseEntity.ok(fileUrl);
}

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This controller endpoint returns the value from uploadFile, but the variable is named fileUrl even though uploadFile returns a file name/key. This is confusing for API consumers; return a typed JSON object (e.g., {fileName, bucket} or a signed download URL) and rename the variable accordingly.

Copilot uses AI. Check for mistakes.
Comment on lines +40 to +44
try {
e.setMeta(p.meta() == null ? null : mapper.valueToTree(p.meta()));
} catch (Exception er) {
e.setMeta(null);
}

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The meta JSON conversion swallows all exceptions and silently drops the metadata. This makes failures hard to diagnose and can lead to unexpected data loss; at minimum, log the exception (sanitizing user-controlled values) and consider rejecting the point if metadata is malformed.

Copilot uses AI. Check for mistakes.
Comment on lines +41 to +43
#Supabase Configuration
supabase.url=${SUPABASE_URL}
supabase.service-key=${SUPABASE_SERVICE_KEY}

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These placeholders have no default values, so the app will fail to start if SUPABASE_URL / SUPABASE_SERVICE_KEY are not provided. If this is optional per environment, provide safe defaults (or use profile-specific properties) to avoid local/dev startup failures.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +30
private final RestTemplate restTemplate = new RestTemplate();
private final ObjectMapper objectMapper = new ObjectMapper();

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SupabaseService creates its own RestTemplate and ObjectMapper instances, bypassing the shared configuration (timeouts, interceptors, custom Jackson config). Prefer constructor injection of the existing RestTemplate bean and a shared ObjectMapper bean.

Copilot uses AI. Check for mistakes.
Comment thread pom.xml
Comment on lines +163 to +181
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding src/main/java as a test source directory will cause main production sources to be compiled again in the test scope and can lead to duplicate-class/packaging issues and longer builds. Remove this build-helper configuration unless there is a very specific, documented reason for it.

Suggested change
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>

Copilot uses AI. Check for mistakes.
// Allow duty schedule operations for OIC
.requestMatchers("/api/duty-schedules/**").hasRole("OIC")
// Public endpoints
.requestMatchers("/api/vehicle**").permitAll()

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The matcher /api/vehicle** does not cover the existing vehicles endpoints (e.g., @RequestMapping("/api/vehicles")), so vehicle routes will no longer be permitted as intended. Update the matcher to target /api/vehicles/** (or the exact vehicle routes you want public).

Suggested change
.requestMatchers("/api/vehicle**").permitAll()
.requestMatchers("/api/vehicles/**").permitAll()

Copilot uses AI. Check for mistakes.
Comment on lines +31 to +35
public void uploadMyLocations(@AuthenticationPrincipal User user, @RequestBody List<LocationPointDTO> points) {
System.out.println("Received locations: " + points.size()); // REMOVE: for testing
if (user == null) {
throw new RuntimeException("Unauthorized");
}

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover System.out.println debug output should not be in a controller method (noise + potential data leakage). Replace with proper logger calls at DEBUG level or remove entirely.

Copilot uses AI. Check for mistakes.
Comment on lines +33 to +44
if (user == null) {
throw new RuntimeException("Unauthorized");
}

if (!"FieldOfficer".equalsIgnoreCase(user.getRole())) {
throw new RuntimeException("Only field officers can upload locations");
}

String officerBadgeNo = user.getBadgeNo();
if (officerBadgeNo == null || officerBadgeNo.isBlank()) {
throw new RuntimeException("Badge number missing");
}

Copilot AI Mar 12, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throwing generic RuntimeException for auth/authorization failures will typically return HTTP 500. Use a Spring mechanism that maps to the correct status (401/403), such as ResponseStatusException or a dedicated exception annotated with @ResponseStatus.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants