Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ed9c251
Added api endpoints to get weapons issued to users
iSiRaH Mar 6, 2026
5b4946d
Added weapon requesting endpoints and services
iSiRaH Mar 8, 2026
83d9544
Fix errors
iSiRaH Mar 8, 2026
0951f88
Added bullet count and fixed bugs
iSiRaH Mar 8, 2026
b35b4d6
feat: Update role-based access for field-officers and admin routes to…
JinethBosilu Feb 28, 2026
ad9fb93
feat: Enhance criminal management with CRUD operations and update sec…
JinethBosilu Feb 28, 2026
301372e
feat: Implement CRUD operations for criminal records with photo uploa…
JinethBosilu Feb 28, 2026
8d69c7e
create BulletController
dasunithimasha Feb 9, 2026
3c7bfac
add BUlletAddDTO.java
dasunithimasha Feb 9, 2026
7865a71
add BulletResponse.java
dasunithimasha Feb 9, 2026
068b02e
Add BulletUpdateDTO
dasunithimasha Feb 9, 2026
bf69eed
Add entity for bullets
dasunithimasha Feb 9, 2026
35ccadd
add BUlletRepository
dasunithimasha Feb 9, 2026
ded7d7d
add BulletService
dasunithimasha Feb 9, 2026
bdc5bc7
add BulletServiceImpl
dasunithimasha Feb 9, 2026
c9de1db
update all for bullets managemant
dasunithimasha Feb 9, 2026
e0cc41d
fix errors in weapon and bullets return
dasunithimasha Feb 13, 2026
57c0a25
Add 'Dev' branch to CodeQL workflow triggers
iSiRaH Mar 12, 2026
5062526
Sanitize log messages in CriminalService and SupabaseStorageService; …
JinethBosilu Mar 12, 2026
1fed442
feat: add database backup and restore functionality with system setti…
LPK98 Mar 12, 2026
918770e
feat: implement database backup and restore service with SQL file gen…
LPK98 Mar 12, 2026
c74b4ca
feat: enhance logging by sanitizing inputs in BackupService and Syste…
JinethBosilu Mar 13, 2026
a7e0d7e
feat: implement database backup and restore functionality with file s…
LPK98 Mar 13, 2026
c6f3857
feat: Update role-based access for field-officers and admin routes to…
JinethBosilu Feb 28, 2026
f68bad4
Merge branch 'main' into isira
iSiRaH Mar 14, 2026
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
Expand Up @@ -76,7 +76,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti

// OIC-only routes
.requestMatchers("/api/duty-schedules/**").hasRole("OIC")
.requestMatchers("/api/weapon/**").hasRole("OIC")
.requestMatchers("/api/weapon/**").permitAll()
.requestMatchers("/api/weapon-issue/**").hasRole("OIC")
Comment on lines +85 to 86

// Admin/OIC routes (officer data, locations, users)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.crimeLink.analyzer.controller;

public @interface ReqquiredArgsConstructor {

}
Comment on lines +3 to +5
Comment on lines +3 to +5
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public ResponseEntity<?> getAllWeaponsWithDetails() {
List<WeaponResponseDTO> weapons = weaponService.getAllWeaponsWithDetails();
return ResponseEntity.ok(weapons);
} catch (Exception e) {
e.printStackTrace(); // Log the full stack trace
e.printStackTrace(); // Log the full stack trace
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(createErrorResponse("Failed to fetch weapons with details: " + e.getMessage()));
}
Expand All @@ -89,6 +89,11 @@ public ResponseEntity<?> getWeaponBySerial(@PathVariable String serialNumber) {
}
}

@GetMapping("/officer/{officerId}")
public List<Weapon> getWeaponsIssuedToOfficer(@PathVariable Integer officerId) {
return weaponService.getWeaponsIssuedToOfficer(officerId);
Comment on lines +93 to +94
Comment on lines +93 to +94
}

private Map<String, String> createErrorResponse(String message) {
Map<String, String> response = new HashMap<>();
response.put("error", message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.crimeLink.analyzer.dto.OfficerDTO;
import com.crimeLink.analyzer.dto.ReturnWeaponRequestDTO;
import com.crimeLink.analyzer.dto.WeaponAddDTO;
import com.crimeLink.analyzer.entity.WeaponIssue;
import com.crimeLink.analyzer.repository.WeaponIssueRepository;
import com.crimeLink.analyzer.service.WeaponIssueService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
Expand All @@ -21,6 +23,7 @@
public class WeaponIssueController {

private final WeaponIssueService weaponIssueService;
private final WeaponIssueRepository weaponIssueRepository;

Comment on lines 25 to 27
@PostMapping("/issue")
public ResponseEntity<?> issueWeapon(@RequestBody IssueWeaponRequestDTO dto) {
Expand Down Expand Up @@ -83,6 +86,16 @@ public ResponseEntity<?> getAllOfficers() {
}
}

@GetMapping("/issued/{officerId}")
public List<WeaponIssue> getActiveWeapons(@PathVariable Integer officerId) {
return weaponIssueRepository.findByIssuedTo_UserIdAndReturnedAtIsNullOrderByIssuedAtDesc(officerId);
}
Comment on lines +89 to +92

@GetMapping("/history/{officerId}")
public List<WeaponIssue> getWeaponIssueHistory(@PathVariable Integer officerId) {
return weaponIssueRepository.findByIssuedTo_UserIdOrderByIssuedAtDesc(officerId);
}
Comment on lines +89 to +97
Comment on lines +94 to +97
Comment on lines +89 to +97
Comment on lines +89 to +97

private Map<String, String> createErrorResponse(String message) {
Map<String, String> response = new HashMap<>();
response.put("error", message);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.crimeLink.analyzer.controller;

import java.util.List;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.crimeLink.analyzer.dto.WeaponRequestDto;
import com.crimeLink.analyzer.service.WeaponRequestService;

import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/api/weapon/requests")
@RequiredArgsConstructor
public class WeaponRequestController {

private final WeaponRequestService weaponRequestService;

@PostMapping
public ResponseEntity<WeaponRequestDto> createRequest(@RequestBody WeaponRequestDto dto) {
WeaponRequestDto createRequest = weaponRequestService.createRequest(dto);
return ResponseEntity.ok(createRequest);
}

@GetMapping
public ResponseEntity<List<WeaponRequestDto>> getAllRequests() {
List<WeaponRequestDto> requests = weaponRequestService.getAllRequests();
return ResponseEntity.ok(requests);
}

@GetMapping("user/{userId}")
public ResponseEntity<List<WeaponRequestDto>> getRequestsByUser(@PathVariable Integer userId) {
List<WeaponRequestDto> requests = weaponRequestService.getRequestsByUser(userId);
return ResponseEntity.ok(requests);
}

@PutMapping("/{requestId}/approve")
public ResponseEntity<WeaponRequestDto> approveRequest(@PathVariable Integer requestId) {
WeaponRequestDto approvedRequest = weaponRequestService.approvedRequest(requestId);

return ResponseEntity.ok(approvedRequest);
}

@PutMapping("/{requestId}/reject")
public ResponseEntity<WeaponRequestDto> rejectRequest(@PathVariable Integer requestId) {
WeaponRequestDto rejectedRequest = weaponRequestService.rejectedRequest(requestId);

return ResponseEntity.ok(rejectedRequest);
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/crimeLink/analyzer/dto/WeaponRequestDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.crimeLink.analyzer.dto;

import java.time.LocalDateTime;

import lombok.Data;

@Data
public class WeaponRequestDto {
private Integer requestId;
private String weaponSerial;
private Integer ammoCount;
private Integer requestedById;
private String requestNote;
private String status;
private LocalDateTime requestedAt;
private LocalDateTime resolvedAt;
}
47 changes: 47 additions & 0 deletions src/main/java/com/crimeLink/analyzer/entity/WeaponRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.crimeLink.analyzer.entity;

import java.time.LocalDateTime;

import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
@Table(name = "weapon_requests")
public class WeaponRequest {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer requestId;

/* Weapon */
@ManyToOne
@JoinColumn(name = "weapon_serial", referencedColumnName = "serial_number")
private Weapon weapon;

/* Issued to */
@ManyToOne
@JoinColumn(name = "requested_by", referencedColumnName = "user_id")
private User requestedBy;

private Integer ammoCount;

private LocalDateTime requestedAt;
private LocalDateTime resolvedAt;
private String requestNote;

@Enumerated(EnumType.STRING)
private WeaponRequestStatus status;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.crimeLink.analyzer.entity;

public enum WeaponRequestStatus {
PENDING,
APPROVED,
REJECTED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.crimeLink.analyzer.mapper;

import com.crimeLink.analyzer.dto.WeaponRequestDto;
import com.crimeLink.analyzer.entity.User;
import com.crimeLink.analyzer.entity.Weapon;
import com.crimeLink.analyzer.entity.WeaponRequest;

public class WeaponRequestMapper {
public static WeaponRequestDto mapToWeaponRequestDto(WeaponRequest entity) {

WeaponRequestDto dto = new WeaponRequestDto();

dto.setRequestId(entity.getRequestId());
dto.setWeaponSerial(entity.getWeapon().getSerialNumber());
dto.setAmmoCount(entity.getAmmoCount());
dto.setRequestedById(entity.getRequestedBy().getUserId());
dto.setRequestNote(entity.getRequestNote());
dto.setStatus(entity.getStatus().name());
dto.setRequestedAt(entity.getRequestedAt());
dto.setResolvedAt(entity.getResolvedAt());
return dto;
}

public static WeaponRequest mapToWeaponRequest(WeaponRequestDto dto, Weapon weapon, User user) {

WeaponRequest entity = new WeaponRequest();

entity.setWeapon(weapon);
entity.setRequestedBy(user);
entity.setRequestNote(dto.getRequestNote());
entity.setAmmoCount(dto.getAmmoCount());
return entity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,11 @@
@Repository
public interface WeaponIssueRepository extends JpaRepository<WeaponIssue, Integer> {
List<WeaponIssue> findByWeapon_SerialNumberAndReturnedAtIsNullOrderByIssuedAtDesc(String serialNumber);

Optional<WeaponIssue> findByWeapon_SerialNumberAndReturnedAtIsNull(String serialNumber);

List<WeaponIssue> findByIssuedTo_UserIdOrderByIssuedAtDesc(Integer officerId);

List<WeaponIssue> findByIssuedTo_UserIdAndReturnedAtIsNullOrderByIssuedAtDesc(Integer officerId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import com.crimeLink.analyzer.entity.Weapon;
import com.crimeLink.analyzer.enums.WeaponStatus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
Expand All @@ -11,6 +13,16 @@
@Repository
public interface WeaponRepository extends JpaRepository<Weapon, String> {
boolean existsById(String serialNumber);

List<Weapon> findByStatus(WeaponStatus status);

Optional<Weapon> findBySerialNumber(String serialNumber);

@Query("""
SELECT wi.weapon
FROM WeaponIssue wi
WHERE wi.issuedTo.userId = :userId
AND wi.returnedAt IS NULL
""")
List<Weapon> findActiveWeaponsByOfficer(@Param("officerId") Integer officerId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.crimeLink.analyzer.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.crimeLink.analyzer.entity.WeaponRequest;

@Repository
public interface WeaponRequestRepository extends JpaRepository<WeaponRequest, Integer> {

List<WeaponRequest> findByRequestedBy_UserId(Integer userId);

List<WeaponRequest> findByStatus(String status);
Comment on lines +9 to +15
Comment on lines +9 to +15
Comment on lines +9 to +15
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.crimeLink.analyzer.service;

import java.util.List;

import com.crimeLink.analyzer.dto.WeaponRequestDto;

public interface WeaponRequestService {
WeaponRequestDto createRequest(WeaponRequestDto requestDto);

List<WeaponRequestDto> getAllRequests();

List<WeaponRequestDto> getRequestsByUser(Integer userId);

WeaponRequestDto approvedRequest(Integer requestId);

WeaponRequestDto rejectedRequest(Integer requestId);
Comment on lines +14 to +16
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ public interface WeaponService {
List<Weapon> getAllWeapons();
Weapon getWeaponBySerial(String serialNumber);
List<WeaponResponseDTO> getAllWeaponsWithDetails();
List<Weapon> getWeaponsIssuedToOfficer(Integer officerId);
}
Loading
Loading