commit
535c0856e8
21 changed files with 1613 additions and 0 deletions
-
18pom.xml
-
11src/main/java/in/gov/secureapi/SecureApiApplication.java
-
84src/main/java/in/gov/secureapi/config/DataSourceConfig.java
-
77src/main/java/in/gov/secureapi/config/SecurityConfig.java
-
35src/main/java/in/gov/secureapi/controller/AuthController.java
-
50src/main/java/in/gov/secureapi/controller/CustomerController.java
-
113src/main/java/in/gov/secureapi/controller/DBFOT_controller.java
-
32src/main/java/in/gov/secureapi/controller/MainController.java
-
34src/main/java/in/gov/secureapi/exception/GlobalExceptionHandler.java
-
81src/main/java/in/gov/secureapi/filter/BearerTokenFilter.java
-
30src/main/java/in/gov/secureapi/repository/CustomerRepository.java
-
47src/main/java/in/gov/secureapi/repository/TokenRepository.java
-
55src/main/java/in/gov/secureapi/repository/UserRepository.java
-
712src/main/java/in/gov/secureapi/service/DBFOT_service.java
-
34src/main/java/in/gov/secureapi/service/DateTimeUtil.java
-
97src/main/java/in/gov/secureapi/service/TokenService.java
-
30src/main/java/in/gov/secureapi/util/TokenUtil.java
-
3src/main/resources/application-local.properties
-
3src/main/resources/application-production.properties
-
67src/main/resources/application.properties
-
0src/main/resources/schema.sql
@ -0,0 +1,18 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
|
<modelVersion>4.0.0</modelVersion> |
||||
|
<parent> |
||||
|
<groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.6</version><relativePath/> |
||||
|
</parent> |
||||
|
<groupId>in.gov.gcc</groupId><artifactId>secure-api</artifactId><version>1.0.0</version> |
||||
|
<properties><java.version>17</java.version></properties> |
||||
|
<dependencies> |
||||
|
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency> |
||||
|
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency> |
||||
|
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency> |
||||
|
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency> |
||||
|
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency> |
||||
|
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency> |
||||
|
</dependencies> |
||||
|
<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build> |
||||
|
</project> |
||||
@ -0,0 +1,11 @@ |
|||||
|
package in.gov.secureapi; |
||||
|
|
||||
|
import org.springframework.boot.SpringApplication; |
||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||
|
|
||||
|
@SpringBootApplication |
||||
|
public class SecureApiApplication { |
||||
|
public static void main(String[] args) { |
||||
|
SpringApplication.run(SecureApiApplication.class, args); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,84 @@ |
|||||
|
package in.gov.secureapi.config; |
||||
|
|
||||
|
import java.util.Properties; |
||||
|
|
||||
|
import javax.sql.DataSource; |
||||
|
|
||||
|
import org.hibernate.jpa.HibernatePersistenceProvider; |
||||
|
import org.springframework.beans.factory.annotation.Qualifier; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.context.annotation.Primary; |
||||
|
import org.springframework.data.jpa.repository.config.EnableJpaRepositories; |
||||
|
import org.springframework.jdbc.datasource.DriverManagerDataSource; |
||||
|
import org.springframework.orm.jpa.JpaTransactionManager; |
||||
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; |
||||
|
import org.springframework.transaction.PlatformTransactionManager; |
||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement; |
||||
|
|
||||
|
@Configuration |
||||
|
@EnableTransactionManagement |
||||
|
public class DataSourceConfig { |
||||
|
|
||||
|
// private static String host = "localhost:3306"; |
||||
|
// private static String dbpassword = "root"; |
||||
|
// private static String dbpassword = "gccroot"; |
||||
|
|
||||
|
// AWS |
||||
|
private static String host = |
||||
|
"gcc-facial-db-instance-1.cf48eqcciziq.ap-south-1.rds.amazonaws.com:3306"; |
||||
|
private static String dbpassword = "gcc-facial-password"; |
||||
|
|
||||
|
////////////////////////////// (For GCC APP) //////////////////////// |
||||
|
@Configuration |
||||
|
@EnableTransactionManagement |
||||
|
@EnableJpaRepositories(entityManagerFactoryRef = "appEntityManagerFactory", transactionManagerRef = "appTransactionManager", basePackages = { |
||||
|
"in.gov.chennaicorporation" }) |
||||
|
|
||||
|
public static class MysqlAppDataSourceConfig { |
||||
|
@Primary |
||||
|
@Bean(name = "mysqlAppDataSource") |
||||
|
public DataSource mysqlAppDataSource() { |
||||
|
DriverManagerDataSource dataSource = new DriverManagerDataSource(); |
||||
|
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); |
||||
|
dataSource.setUrl("jdbc:mysql://" + host + "/gcc_apps"); |
||||
|
dataSource.setUsername("root"); |
||||
|
dataSource.setPassword(dbpassword); |
||||
|
return dataSource; |
||||
|
} |
||||
|
|
||||
|
@Primary |
||||
|
@Bean(name = "appEntityManagerFactory") |
||||
|
public LocalContainerEntityManagerFactoryBean entityManagerFactory( |
||||
|
@Qualifier("mysqlAppDataSource") DataSource dataSource) { |
||||
|
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); |
||||
|
entityManagerFactoryBean.setDataSource(dataSource); |
||||
|
entityManagerFactoryBean.setPackagesToScan("in.gov.chennaicorporation"); |
||||
|
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class); |
||||
|
Properties properties = new Properties(); |
||||
|
properties.setProperty("hibernate.hbm2ddl.auto", "update"); |
||||
|
entityManagerFactoryBean.setJpaProperties(properties); |
||||
|
|
||||
|
return entityManagerFactoryBean; |
||||
|
} |
||||
|
|
||||
|
@Primary |
||||
|
@Bean(name = "appTransactionManager") |
||||
|
public PlatformTransactionManager transactionManager( |
||||
|
@Qualifier("appEntityManagerFactory") jakarta.persistence.EntityManagerFactory entityManagerFactory) { |
||||
|
return new JpaTransactionManager(entityManagerFactory); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
////////// DBFOT_toilets ////////////////////// |
||||
|
@Bean(name = "mysqldbfottoiletsGccDataSource") |
||||
|
public DataSource mysqldbfottoiletsGccDataSource() { |
||||
|
DriverManagerDataSource dataSource = new DriverManagerDataSource(); |
||||
|
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); |
||||
|
dataSource.setUrl("jdbc:mysql://" + host + "/dbfot_toilets"); |
||||
|
dataSource.setUsername("root"); |
||||
|
dataSource.setPassword(dbpassword); |
||||
|
return dataSource; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,77 @@ |
|||||
|
package in.gov.secureapi.config; |
||||
|
|
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.http.MediaType; |
||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
||||
|
import org.springframework.security.config.http.SessionCreationPolicy; |
||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
||||
|
import org.springframework.security.crypto.password.PasswordEncoder; |
||||
|
import org.springframework.security.web.SecurityFilterChain; |
||||
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; |
||||
|
|
||||
|
import in.gov.secureapi.filter.BearerTokenFilter; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.util.LinkedHashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Configuration |
||||
|
public class SecurityConfig { |
||||
|
|
||||
|
private final ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
|
||||
|
@Bean |
||||
|
public PasswordEncoder passwordEncoder() { |
||||
|
return new BCryptPasswordEncoder(); |
||||
|
} |
||||
|
|
||||
|
@Bean |
||||
|
SecurityFilterChain securityFilterChain(HttpSecurity http, BearerTokenFilter bearerTokenFilter) throws Exception { |
||||
|
http.csrf(csrf -> csrf.disable()) |
||||
|
.formLogin(form -> form.disable()) |
||||
|
.httpBasic(basic -> basic.disable()) |
||||
|
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) |
||||
|
.exceptionHandling(ex -> ex |
||||
|
.authenticationEntryPoint((request, response, authException) -> { |
||||
|
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); |
||||
|
response.setContentType(MediaType.APPLICATION_JSON_VALUE); |
||||
|
response.setCharacterEncoding("UTF-8"); |
||||
|
|
||||
|
Map<String, Object> body = new LinkedHashMap<>(); |
||||
|
body.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); |
||||
|
body.put("status", false); |
||||
|
body.put("statusCode", HttpServletResponse.SC_UNAUTHORIZED); |
||||
|
body.put("error", "Unauthorized"); |
||||
|
body.put("message", "Authentication required. Please provide a valid Bearer token in Authorization header."); |
||||
|
body.put("path", request.getRequestURI()); |
||||
|
|
||||
|
objectMapper.writeValue(response.getOutputStream(), body); |
||||
|
}) |
||||
|
.accessDeniedHandler((request, response, accessDeniedException) -> { |
||||
|
response.setStatus(HttpServletResponse.SC_FORBIDDEN); |
||||
|
response.setContentType(MediaType.APPLICATION_JSON_VALUE); |
||||
|
response.setCharacterEncoding("UTF-8"); |
||||
|
|
||||
|
Map<String, Object> body = new LinkedHashMap<>(); |
||||
|
body.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); |
||||
|
body.put("status", false); |
||||
|
body.put("statusCode", HttpServletResponse.SC_FORBIDDEN); |
||||
|
body.put("error", "Forbidden"); |
||||
|
body.put("message", "Access denied: you do not have permission to access this resource."); |
||||
|
body.put("path", request.getRequestURI()); |
||||
|
|
||||
|
objectMapper.writeValue(response.getOutputStream(), body); |
||||
|
}) |
||||
|
) |
||||
|
.authorizeHttpRequests(auth -> auth |
||||
|
.requestMatchers("/secure/api/auth/token", "/api/auth/token", "/error", "/actuator/health").permitAll() |
||||
|
.requestMatchers("/secure/**", "/api/**").authenticated() |
||||
|
.anyRequest().permitAll()) |
||||
|
.addFilterBefore(bearerTokenFilter, UsernamePasswordAuthenticationFilter.class); |
||||
|
return http.build(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
package in.gov.secureapi.controller; |
||||
|
|
||||
|
import jakarta.validation.Valid; |
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import in.gov.secureapi.service.TokenService; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/secure/api/auth") |
||||
|
public class AuthController { |
||||
|
private final TokenService tokenService; |
||||
|
public AuthController(TokenService tokenService) { this.tokenService = tokenService; } |
||||
|
|
||||
|
@PostMapping("/token") |
||||
|
public ResponseEntity<?> createToken(@Valid @RequestBody TokenRequest request) { |
||||
|
var tokenResult = tokenService.authenticateAndCreate(request.username(), request.password()); |
||||
|
return ResponseEntity.ok(Map.of("status", true, "message", "Token generated successfully", "data", tokenResult)); |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/revoke") |
||||
|
public ResponseEntity<?> revoke(@RequestHeader(value="Authorization", required=false) String header) { |
||||
|
if (header == null || !header.startsWith("Bearer ")) return ResponseEntity.badRequest().body(Map.of("status",false,"message","Bearer token is required")); |
||||
|
tokenService.revoke(header.substring(7).trim()); |
||||
|
return ResponseEntity.ok(Map.of("status",true,"message","Token revoked successfully")); |
||||
|
} |
||||
|
|
||||
|
public record TokenRequest( |
||||
|
@NotBlank(message = "username is required") String username, |
||||
|
@NotBlank(message = "password is required") String password |
||||
|
) {} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
package in.gov.secureapi.controller; |
||||
|
|
||||
|
import jakarta.validation.Valid; |
||||
|
import jakarta.validation.constraints.Email; |
||||
|
import jakarta.validation.constraints.NotBlank; |
||||
|
import org.springframework.http.HttpStatus; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import in.gov.secureapi.repository.CustomerRepository; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/api/customers") |
||||
|
public class CustomerController { |
||||
|
private final CustomerRepository repo; |
||||
|
public CustomerController(CustomerRepository repo) { this.repo = repo; } |
||||
|
|
||||
|
@PostMapping |
||||
|
public ResponseEntity<?> create(@Valid @RequestBody CustomerRequest req) { |
||||
|
long id = repo.insert(req.name(), req.mobile(), req.email(), req.address()); |
||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(Map.of("status",true,"message","Customer created successfully","id",id)); |
||||
|
} |
||||
|
|
||||
|
@GetMapping |
||||
|
public ResponseEntity<?> all() { return ResponseEntity.ok(Map.of("status",true,"data",repo.findAll())); } |
||||
|
|
||||
|
@GetMapping("/{id}") |
||||
|
public ResponseEntity<?> one(@PathVariable long id) { |
||||
|
return repo.findById(id).<ResponseEntity<?>>map(x -> ResponseEntity.ok(Map.of("status",true,"data",x))) |
||||
|
.orElseGet(() -> ResponseEntity.status(404).body(Map.of("status",false,"message","Customer not found"))); |
||||
|
} |
||||
|
|
||||
|
@PutMapping("/{id}") |
||||
|
public ResponseEntity<?> update(@PathVariable long id, @Valid @RequestBody CustomerRequest req) { |
||||
|
int n = repo.update(id, req.name(), req.mobile(), req.email(), req.address()); |
||||
|
if (n == 0) return ResponseEntity.status(404).body(Map.of("status",false,"message","Customer not found")); |
||||
|
return ResponseEntity.ok(Map.of("status",true,"message","Customer updated successfully")); |
||||
|
} |
||||
|
|
||||
|
@DeleteMapping("/{id}") |
||||
|
public ResponseEntity<?> delete(@PathVariable long id) { |
||||
|
int n = repo.delete(id); |
||||
|
if (n == 0) return ResponseEntity.status(404).body(Map.of("status",false,"message","Customer not found")); |
||||
|
return ResponseEntity.ok(Map.of("status",true,"message","Customer deleted successfully")); |
||||
|
} |
||||
|
|
||||
|
public record CustomerRequest(@NotBlank String name, String mobile, @Email String email, String address) {} |
||||
|
} |
||||
@ -0,0 +1,113 @@ |
|||||
|
package in.gov.secureapi.controller; |
||||
|
|
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.http.MediaType; |
||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestParam; |
||||
|
import org.springframework.web.bind.annotation.RequestPart; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
import in.gov.secureapi.service.DBFOT_service; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/secure/api/dbfotcontroller") |
||||
|
public class DBFOT_controller { |
||||
|
|
||||
|
@Autowired |
||||
|
private DBFOT_service dbfotService; |
||||
|
|
||||
|
@PostMapping("/savecomplaints") |
||||
|
public List<?> savecomplaints( |
||||
|
@RequestParam(value = "zone", required = true) String zone, |
||||
|
@RequestParam(value = "ward", required = true) String ward, |
||||
|
@RequestParam(value = "location", required = true) String location, |
||||
|
@RequestParam(value = "status", required = true) String status, |
||||
|
@RequestParam(value = "address", required = true) String address, |
||||
|
@RequestParam(value = "source", required = true) String source, |
||||
|
@RequestParam(value = "pct", required = true) String pct, |
||||
|
@RequestParam(value = "complaint_id", required = true) String complaint_id, |
||||
|
@RequestParam(value = "description", required = true) String description, |
||||
|
@RequestParam(value = "turn_around_time", required = true) String turn_around_time, |
||||
|
@RequestParam(value = "vendorid", required = true) String vendorid |
||||
|
) |
||||
|
{ |
||||
|
|
||||
|
return dbfotService.savecomplaints(zone,ward,location,status,address,source,pct,complaint_id,description,turn_around_time,vendorid); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@PostMapping("/savecompshistory") |
||||
|
public List<?> savecomplaints_history( |
||||
|
@RequestParam(value = "complaint_id", required = true) String complaint_id, |
||||
|
@RequestParam(value = "status", required = true) String status, |
||||
|
@RequestParam(value = "complaint_raised_on", required = true) String complaint_raised_on, |
||||
|
@RequestParam(value = "complaint_raised_by", required = true) String complaint_raised_by, |
||||
|
@RequestParam(value = "complaint_updated_on", required = true) String complaint_updated_on, |
||||
|
@RequestParam(value = "complaint_updated_by", required = true) String complaint_updated_by, |
||||
|
@RequestParam(value = "remarks", required = true) String remarks, |
||||
|
@RequestParam(value = "imgfile", required = false) MultipartFile imgfile, |
||||
|
@RequestParam(value = "cby", required = true) String cby |
||||
|
) |
||||
|
{ |
||||
|
|
||||
|
return dbfotService.savecomplaints_history(complaint_id,status,complaint_raised_on,complaint_raised_by,complaint_updated_on,complaint_updated_by,remarks,imgfile,cby); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@PostMapping("/savemanpower") |
||||
|
public List<?> savemanpower( |
||||
|
@RequestParam(value = "zone", required = true) String zone, |
||||
|
@RequestParam(value = "ward", required = true) String ward, |
||||
|
@RequestParam(value = "category", required = true) String category, |
||||
|
@RequestParam(value = "pct", required = true) String pct, |
||||
|
@RequestParam(value = "status", required = true) String status, |
||||
|
@RequestParam(value = "vendorid", required = true) String vendorid |
||||
|
) |
||||
|
{ |
||||
|
|
||||
|
return dbfotService.savemanpower(zone,ward,category,pct,status,vendorid); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
@PostMapping(value = "/savemanpoweremps", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) |
||||
|
public List<?> savemanpoweremps( |
||||
|
@RequestParam(value = "pct", required = true) String pct, |
||||
|
@RequestPart(value = "employee_details", required = true) String employee_details, |
||||
|
@RequestParam Map<String, MultipartFile> files |
||||
|
){ |
||||
|
|
||||
|
return dbfotService.savemanpoweremps(pct,employee_details,files); |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/savepctmaster") |
||||
|
public List<?> savepctmaster( |
||||
|
@RequestParam(value="zone",required = true) String zone, |
||||
|
@RequestParam(value="ward",required = true) String ward, |
||||
|
@RequestParam(value="address",required = true) String address, |
||||
|
@RequestParam(value="category",required = true) String category, |
||||
|
@RequestParam(value="pct",required = true) String pct, |
||||
|
@RequestParam(value="status",required = true) String status, |
||||
|
@RequestParam(value="vendorid",required = true) String vendorid |
||||
|
){ |
||||
|
|
||||
|
return dbfotService.savepctmaster(zone,ward,address,category,pct,status,vendorid); |
||||
|
} |
||||
|
|
||||
|
@PostMapping("/updatepctstatus") |
||||
|
public List<?> updatepctstatus( |
||||
|
@RequestParam(value="pct",required = true) String pct, |
||||
|
@RequestParam(value="status",required = true) String status, |
||||
|
@RequestParam(value="vendorid",required = true) String vendorid |
||||
|
){ |
||||
|
|
||||
|
return dbfotService.updatepctstatus(pct,status,vendorid); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
package in.gov.secureapi.controller; |
||||
|
|
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.security.core.Authentication; |
||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||
|
import org.springframework.web.bind.annotation.RestController; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.util.LinkedHashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@RestController |
||||
|
@RequestMapping("/secure") |
||||
|
public class MainController { |
||||
|
|
||||
|
@GetMapping |
||||
|
public ResponseEntity<?> index(Authentication authentication) { |
||||
|
String username = (authentication != null && authentication.isAuthenticated()) |
||||
|
? authentication.getName() |
||||
|
: "Anonymous"; |
||||
|
|
||||
|
Map<String, Object> response = new LinkedHashMap<>(); |
||||
|
response.put("status", true); |
||||
|
response.put("message", "Secure endpoint accessed successfully"); |
||||
|
response.put("user", username); |
||||
|
response.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); |
||||
|
|
||||
|
return ResponseEntity.ok(response); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
package in.gov.secureapi.exception; |
||||
|
|
||||
|
import org.springframework.http.HttpStatus; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.security.authentication.BadCredentialsException; |
||||
|
import org.springframework.security.authentication.DisabledException; |
||||
|
import org.springframework.web.bind.MethodArgumentNotValidException; |
||||
|
import org.springframework.web.bind.annotation.ExceptionHandler; |
||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@RestControllerAdvice |
||||
|
public class GlobalExceptionHandler { |
||||
|
@ExceptionHandler(MethodArgumentNotValidException.class) |
||||
|
public ResponseEntity<?> validation(MethodArgumentNotValidException ex) { |
||||
|
String message = ex.getBindingResult().getFieldErrors().stream() |
||||
|
.map(e -> e.getField() + ": " + e.getDefaultMessage()).findFirst().orElse("Validation failed"); |
||||
|
return ResponseEntity.badRequest().body(Map.of("status", false, "message", message)); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler({BadCredentialsException.class, DisabledException.class}) |
||||
|
public ResponseEntity<?> authenticationError(Exception ex) { |
||||
|
return ResponseEntity.status(HttpStatus.UNAUTHORIZED) |
||||
|
.body(Map.of("status", false, "message", ex.getMessage())); |
||||
|
} |
||||
|
|
||||
|
@ExceptionHandler(Exception.class) |
||||
|
public ResponseEntity<?> other(Exception ex) { |
||||
|
ex.printStackTrace(); |
||||
|
|
||||
|
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) |
||||
|
.body(Map.of("status", false, "message", "Internal server error: " + ex.getMessage())); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,81 @@ |
|||||
|
package in.gov.secureapi.filter; |
||||
|
|
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import jakarta.servlet.FilterChain; |
||||
|
import jakarta.servlet.ServletException; |
||||
|
import jakarta.servlet.http.HttpServletRequest; |
||||
|
import jakarta.servlet.http.HttpServletResponse; |
||||
|
import org.springframework.http.MediaType; |
||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
||||
|
import org.springframework.security.core.authority.AuthorityUtils; |
||||
|
import org.springframework.security.core.context.SecurityContextHolder; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
import org.springframework.web.filter.OncePerRequestFilter; |
||||
|
|
||||
|
import in.gov.secureapi.service.TokenService; |
||||
|
import in.gov.secureapi.service.TokenService.TokenStatus; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
import java.util.LinkedHashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Component |
||||
|
public class BearerTokenFilter extends OncePerRequestFilter { |
||||
|
private final TokenService tokenService; |
||||
|
private final ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
|
||||
|
public BearerTokenFilter(TokenService tokenService) { |
||||
|
this.tokenService = tokenService; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected boolean shouldNotFilter(HttpServletRequest request) { |
||||
|
String path = request.getRequestURI(); |
||||
|
return path.startsWith("/secure/api/auth/token") || path.startsWith("/api/auth/token") || path.startsWith("/error") || path.startsWith("/actuator"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) |
||||
|
throws ServletException, IOException { |
||||
|
String header = request.getHeader("Authorization"); |
||||
|
|
||||
|
if (header != null && header.startsWith("Bearer ")) { |
||||
|
String token = header.substring(7).trim(); |
||||
|
if (!token.isBlank()) { |
||||
|
var validation = tokenService.validateDetailed(token); |
||||
|
|
||||
|
if (validation.status() == TokenStatus.VALID) { |
||||
|
var auth = new UsernamePasswordAuthenticationToken(validation.info().username(), null, AuthorityUtils.NO_AUTHORITIES); |
||||
|
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
} else { |
||||
|
sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized", validation.message(), request.getRequestURI()); |
||||
|
return; |
||||
|
} |
||||
|
} else { |
||||
|
sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized", "Bearer token is empty", request.getRequestURI()); |
||||
|
return; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
chain.doFilter(request, response); |
||||
|
} |
||||
|
|
||||
|
private void sendErrorResponse(HttpServletResponse response, int statusCode, String error, String message, String path) |
||||
|
throws IOException { |
||||
|
response.setStatus(statusCode); |
||||
|
response.setContentType(MediaType.APPLICATION_JSON_VALUE); |
||||
|
response.setCharacterEncoding("UTF-8"); |
||||
|
|
||||
|
Map<String, Object> body = new LinkedHashMap<>(); |
||||
|
body.put("timestamp", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); |
||||
|
body.put("status", false); |
||||
|
body.put("statusCode", statusCode); |
||||
|
body.put("error", error); |
||||
|
body.put("message", message); |
||||
|
body.put("path", path); |
||||
|
|
||||
|
objectMapper.writeValue(response.getOutputStream(), body); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
package in.gov.secureapi.repository; |
||||
|
|
||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||
|
import org.springframework.stereotype.Repository; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.Optional; |
||||
|
|
||||
|
@Repository |
||||
|
public class CustomerRepository { |
||||
|
private final JdbcTemplate jdbc; |
||||
|
public CustomerRepository(JdbcTemplate jdbc) { this.jdbc = jdbc; } |
||||
|
|
||||
|
public long insert(String name, String mobile, String email, String address) { |
||||
|
jdbc.update("INSERT INTO customers(name,mobile,email,address) VALUES (?,?,?,?)", name, mobile, email, address); |
||||
|
Long id = jdbc.queryForObject("SELECT LAST_INSERT_ID()", Long.class); |
||||
|
return id; |
||||
|
} |
||||
|
public List<Map<String,Object>> findAll() { |
||||
|
return jdbc.queryForList("SELECT id,name,mobile,email,address,created_at,updated_at FROM customers ORDER BY id DESC"); |
||||
|
} |
||||
|
public Optional<Map<String,Object>> findById(long id) { |
||||
|
var list = jdbc.queryForList("SELECT id,name,mobile,email,address,created_at,updated_at FROM customers WHERE id=?", id); |
||||
|
return list.stream().findFirst(); |
||||
|
} |
||||
|
public int update(long id, String name, String mobile, String email, String address) { |
||||
|
return jdbc.update("UPDATE customers SET name=?,mobile=?,email=?,address=? WHERE id=?", name,mobile,email,address,id); |
||||
|
} |
||||
|
public int delete(long id) { return jdbc.update("DELETE FROM customers WHERE id=?", id); } |
||||
|
} |
||||
@ -0,0 +1,47 @@ |
|||||
|
package in.gov.secureapi.repository; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Qualifier; |
||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||
|
import org.springframework.stereotype.Repository; |
||||
|
|
||||
|
import java.sql.Timestamp; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.util.Optional; |
||||
|
import javax.sql.DataSource; |
||||
|
|
||||
|
@Repository |
||||
|
public class TokenRepository { |
||||
|
private JdbcTemplate jdbc; |
||||
|
|
||||
|
@Autowired |
||||
|
public void setDataSource(@Qualifier("mysqldbfottoiletsGccDataSource") DataSource DBFOTTOILETSSource) { |
||||
|
this.jdbc = new JdbcTemplate(DBFOTTOILETSSource); |
||||
|
} |
||||
|
|
||||
|
public void save(String username, String tokenHash, LocalDateTime expiresAt) { |
||||
|
// Step 1: Deactivate any previous active tokens for this client |
||||
|
jdbc.update("UPDATE api_users SET active = FALSE WHERE username = ? AND active = TRUE", username); |
||||
|
|
||||
|
// Step 2: Insert the newly generated active token |
||||
|
jdbc.update("INSERT INTO api_users(username, token_hash, expires_at, active) VALUES (?, ?, ?, TRUE)", |
||||
|
username, tokenHash, Timestamp.valueOf(expiresAt)); |
||||
|
} |
||||
|
|
||||
|
public Optional<TokenInfo> findByTokenHash(String tokenHash) { |
||||
|
var list = jdbc.query("SELECT username, expires_at, active FROM api_users WHERE token_hash=? ORDER BY id DESC LIMIT 1", |
||||
|
(rs, row) -> new TokenInfo(rs.getString("username"), rs.getTimestamp("expires_at").toLocalDateTime(), rs.getBoolean("active")), tokenHash); |
||||
|
return list.stream().findFirst(); |
||||
|
} |
||||
|
|
||||
|
public Optional<TokenInfo> findValid(String tokenHash) { |
||||
|
return findByTokenHash(tokenHash) |
||||
|
.filter(info -> info.active() && info.expiresAt().isAfter(LocalDateTime.now())); |
||||
|
} |
||||
|
|
||||
|
public void revoke(String tokenHash) { |
||||
|
jdbc.update("UPDATE api_users SET active=FALSE WHERE token_hash=?", tokenHash); |
||||
|
} |
||||
|
|
||||
|
public record TokenInfo(String username, LocalDateTime expiresAt, boolean active) {} |
||||
|
} |
||||
@ -0,0 +1,55 @@ |
|||||
|
package in.gov.secureapi.repository; |
||||
|
|
||||
|
import jakarta.annotation.PostConstruct; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Qualifier; |
||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||
|
import org.springframework.stereotype.Repository; |
||||
|
|
||||
|
import javax.sql.DataSource; |
||||
|
import java.util.Optional; |
||||
|
|
||||
|
@Repository |
||||
|
public class UserRepository { |
||||
|
|
||||
|
private JdbcTemplate jdbc; |
||||
|
|
||||
|
@Autowired |
||||
|
public void setDataSource(@Qualifier("mysqldbfottoiletsGccDataSource") DataSource dbfotToiletsSource) { |
||||
|
this.jdbc = new JdbcTemplate(dbfotToiletsSource); |
||||
|
} |
||||
|
|
||||
|
@PostConstruct |
||||
|
public void init() { |
||||
|
try { |
||||
|
jdbc.execute(""" |
||||
|
CREATE TABLE IF NOT EXISTS users ( |
||||
|
id BIGINT AUTO_INCREMENT PRIMARY KEY, |
||||
|
username VARCHAR(100) NOT NULL UNIQUE, |
||||
|
password VARCHAR(255) NOT NULL, |
||||
|
active TINYINT(1) NOT NULL DEFAULT 1, |
||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, |
||||
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
||||
|
) |
||||
|
"""); |
||||
|
} catch (Exception e) { |
||||
|
// Log but don't fail if table or permissions already established |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public Optional<UserRecord> findByUsername(String username) { |
||||
|
var list = jdbc.query( |
||||
|
"SELECT id, username, password, active FROM users WHERE username = ? LIMIT 1", |
||||
|
(rs, rowNum) -> new UserRecord( |
||||
|
rs.getLong("id"), |
||||
|
rs.getString("username"), |
||||
|
rs.getString("password"), |
||||
|
rs.getBoolean("active") |
||||
|
), |
||||
|
username |
||||
|
); |
||||
|
return list.stream().findFirst(); |
||||
|
} |
||||
|
|
||||
|
public record UserRecord(long id, String username, String password, boolean active) {} |
||||
|
} |
||||
@ -0,0 +1,712 @@ |
|||||
|
package in.gov.secureapi.service; |
||||
|
|
||||
|
import java.awt.image.BufferedImage; |
||||
|
import java.io.ByteArrayInputStream; |
||||
|
import java.io.ByteArrayOutputStream; |
||||
|
import java.io.IOException; |
||||
|
import java.nio.file.Files; |
||||
|
import java.nio.file.Path; |
||||
|
import java.nio.file.Paths; |
||||
|
import java.security.SecureRandom; |
||||
|
import java.sql.PreparedStatement; |
||||
|
import java.sql.Statement; |
||||
|
import java.util.Collections; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
import java.util.Random; |
||||
|
import javax.imageio.ImageIO; |
||||
|
import javax.imageio.ImageWriteParam; |
||||
|
import javax.imageio.ImageWriter; |
||||
|
import javax.imageio.stream.ImageOutputStream; |
||||
|
import javax.sql.DataSource; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Qualifier; |
||||
|
import org.springframework.core.env.Environment; |
||||
|
import org.springframework.jdbc.core.JdbcTemplate; |
||||
|
import org.springframework.jdbc.support.GeneratedKeyHolder; |
||||
|
import org.springframework.jdbc.support.KeyHolder; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
import com.fasterxml.jackson.core.type.TypeReference; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
|
||||
|
@Service |
||||
|
public class DBFOT_service { |
||||
|
|
||||
|
private JdbcTemplate jdbcTemplate; |
||||
|
|
||||
|
private final Environment environment; |
||||
|
private String fileBaseUrl; |
||||
|
|
||||
|
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; |
||||
|
private static final int STRING_LENGTH = 15; |
||||
|
private static final Random RANDOM = new SecureRandom(); |
||||
|
|
||||
|
@Autowired |
||||
|
public void setDataSource(@Qualifier("mysqldbfottoiletsGccDataSource") DataSource DBFOTTOILETSSource) { |
||||
|
this.jdbcTemplate = new JdbcTemplate(DBFOTTOILETSSource); |
||||
|
} |
||||
|
|
||||
|
@Autowired |
||||
|
public DBFOT_service(Environment environment) { |
||||
|
this.environment = environment; |
||||
|
this.fileBaseUrl = environment.getProperty("fileBaseUrl"); |
||||
|
} |
||||
|
|
||||
|
public static String generateRandomString() { |
||||
|
StringBuilder result = new StringBuilder(STRING_LENGTH); |
||||
|
for (int i = 0; i < STRING_LENGTH; i++) { |
||||
|
result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); |
||||
|
} |
||||
|
return result.toString(); |
||||
|
} |
||||
|
|
||||
|
public static String generateRandomFileString(int lenthval) { |
||||
|
StringBuilder result = new StringBuilder(lenthval); |
||||
|
for (int i = 0; i < lenthval; i++) { |
||||
|
result.append(CHARACTERS.charAt(RANDOM.nextInt(CHARACTERS.length()))); |
||||
|
} |
||||
|
return result.toString(); |
||||
|
} |
||||
|
|
||||
|
private byte[] compressImage(BufferedImage image, float quality) throws IOException { |
||||
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); |
||||
|
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(byteArrayOutputStream); |
||||
|
|
||||
|
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); |
||||
|
writer.setOutput(imageOutputStream); |
||||
|
|
||||
|
ImageWriteParam param = writer.getDefaultWriteParam(); |
||||
|
if (param.canWriteCompressed()) { |
||||
|
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); |
||||
|
param.setCompressionQuality(quality); |
||||
|
} |
||||
|
|
||||
|
writer.write(null, new javax.imageio.IIOImage(image, null, null), param); |
||||
|
|
||||
|
writer.dispose(); |
||||
|
imageOutputStream.close(); |
||||
|
|
||||
|
return byteArrayOutputStream.toByteArray(); |
||||
|
} |
||||
|
|
||||
|
public String fileUpload(MultipartFile file, String name) { |
||||
|
|
||||
|
// Set the file path where you want to save it |
||||
|
String uploadDirectory = environment.getProperty("file.upload.directory"); |
||||
|
String serviceFolderName = environment.getProperty("dbfot_toilets"); |
||||
|
var year = DateTimeUtil.getCurrentYear(); |
||||
|
var month = DateTimeUtil.getCurrentMonth(); |
||||
|
|
||||
|
uploadDirectory = uploadDirectory + serviceFolderName + year + "/" + month; |
||||
|
|
||||
|
try { |
||||
|
// Create directory if it doesn't exist |
||||
|
Path directoryPath = Paths.get(uploadDirectory); |
||||
|
if (!Files.exists(directoryPath)) { |
||||
|
Files.createDirectories(directoryPath); |
||||
|
} |
||||
|
|
||||
|
// Datetime string |
||||
|
String datetimetxt = DateTimeUtil.getCurrentDateTime(); |
||||
|
|
||||
|
// File name |
||||
|
String fileName = name + "_" + datetimetxt + "_" + file.getOriginalFilename(); |
||||
|
fileName = fileName.replaceAll("\\s+", ""); // Remove space on filename |
||||
|
|
||||
|
String filePath = uploadDirectory + "/" + fileName; |
||||
|
|
||||
|
String filepath_txt = "/" + serviceFolderName + year + "/" + month + "/" + fileName; |
||||
|
|
||||
|
// Create a new Path object |
||||
|
Path path = Paths.get(filePath); |
||||
|
|
||||
|
// Get the bytes of the file |
||||
|
byte[] bytes = file.getBytes(); |
||||
|
|
||||
|
String originalFileName = file.getOriginalFilename(); |
||||
|
String extension = originalFileName.substring(originalFileName.lastIndexOf('.') + 1).toLowerCase(); |
||||
|
|
||||
|
if ("jpg".equals(extension) || "jpeg".equals(extension)) { |
||||
|
BufferedImage image = ImageIO.read(new ByteArrayInputStream(bytes)); |
||||
|
byte[] compressedBytes = compressImage(image, 0.5f); // Compress with 50% quality |
||||
|
|
||||
|
// Write the compressed bytes to the file |
||||
|
Files.write(path, compressedBytes); |
||||
|
} else { |
||||
|
// Write the original bytes to the file |
||||
|
Files.write(path, bytes); |
||||
|
} |
||||
|
|
||||
|
//System.out.println(filePath); |
||||
|
return filepath_txt; |
||||
|
|
||||
|
} catch (IOException e) { |
||||
|
e.printStackTrace(); |
||||
|
return "Failed to save file " + file.getOriginalFilename(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public List<?> savecomplaints(String zone, String ward, String location, String status, String address, |
||||
|
String source, String pct, String complaint_id, String description, String turn_around_time, |
||||
|
String vendorid) { |
||||
|
|
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
|
||||
|
|
||||
|
String checkSql = |
||||
|
"SELECT id, zone, ward, location, status, address, source, pct, " + |
||||
|
"complaint_id, description, turn_around_time, vendorid, " + |
||||
|
"created_date, isactive, isdelete " + |
||||
|
"FROM complaints_details " + |
||||
|
"WHERE complaint_id = ? " + |
||||
|
"AND isactive = 1 " + |
||||
|
"AND isdelete = 0 "; |
||||
|
|
||||
|
List<Map<String, Object>> complaintList = |
||||
|
jdbcTemplate.queryForList(checkSql, complaint_id); |
||||
|
|
||||
|
|
||||
|
if (complaintList.isEmpty()) { |
||||
|
|
||||
|
String saveSql = "INSERT INTO complaints_details (zone,ward,location,status,address,source,pct,complaint_id,description,turn_around_time,vendorid) " + |
||||
|
"VALUES (?,?,?,?,?,?,?,?,?,?,?)"; |
||||
|
|
||||
|
KeyHolder keyHolder = new GeneratedKeyHolder(); |
||||
|
int affectedRows = jdbcTemplate.update(connection -> { |
||||
|
PreparedStatement ps = connection.prepareStatement(saveSql, Statement.RETURN_GENERATED_KEYS); |
||||
|
ps.setString(1, zone); |
||||
|
ps.setString(2, ward); |
||||
|
ps.setString(3, location); |
||||
|
ps.setString(4, status); |
||||
|
ps.setString(5, address); |
||||
|
ps.setString(6, source); |
||||
|
ps.setString(7, pct); |
||||
|
ps.setString(8, complaint_id); |
||||
|
ps.setString(9, description); |
||||
|
ps.setString(10, turn_around_time); |
||||
|
ps.setString(11, vendorid); |
||||
|
return ps; |
||||
|
}, keyHolder); |
||||
|
|
||||
|
if (affectedRows > 0) { |
||||
|
response.put("status", "Success"); |
||||
|
response.put("message", "Complaints Saved Successfully"); |
||||
|
} else { |
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message", "Error while saving complaints"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
else { |
||||
|
|
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message", |
||||
|
"Duplicate Complaint ID " + complaint_id + |
||||
|
" already found in complaints_details"); |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
response.put("status", "Error"); |
||||
|
response.put("message", "Error while saving complaints"); |
||||
|
} |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@Transactional |
||||
|
public List<?> savecomplaints_history(String complaint_id, String status, String complaint_raised_on, |
||||
|
String complaint_raised_by, String complaint_updated_on, String complaint_updated_by, String remarks, |
||||
|
MultipartFile imgfile, String cby) { |
||||
|
|
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
|
||||
|
String checkSql = |
||||
|
"SELECT id, zone, ward, location, status, address, source, pct, " + |
||||
|
"complaint_id, description, turn_around_time, vendorid, " + |
||||
|
"created_date, isactive, isdelete " + |
||||
|
"FROM complaints_details " + |
||||
|
"WHERE complaint_id = ? " + |
||||
|
"AND isactive = 1 " + |
||||
|
"AND isdelete = 0 " + |
||||
|
"FOR UPDATE"; |
||||
|
|
||||
|
List<Map<String, Object>> complaintList = |
||||
|
jdbcTemplate.queryForList(checkSql, complaint_id); |
||||
|
|
||||
|
|
||||
|
if (complaintList.isEmpty()) { |
||||
|
|
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message", |
||||
|
"Complaint ID " + complaint_id + |
||||
|
" not found in complaints_details"); |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
Map<String, Object> complaint = complaintList.get(0); |
||||
|
|
||||
|
String imgFileValue = null; |
||||
|
|
||||
|
if (imgfile != null && !imgfile.isEmpty()) { |
||||
|
|
||||
|
|
||||
|
imgFileValue = fileUpload(imgfile, "dbfot_toilet_img"); |
||||
|
} |
||||
|
|
||||
|
String historySql = |
||||
|
"INSERT INTO complaints_history " + |
||||
|
"(complaint_id, status, complaint_raised_on, complaint_raised_by, " + |
||||
|
"complaint_updated_on, complaint_updated_by, remarks, imgfile, cby) " + |
||||
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; |
||||
|
|
||||
|
|
||||
|
int historyAffectedRows = jdbcTemplate.update( |
||||
|
historySql, |
||||
|
complaint_id, |
||||
|
status, |
||||
|
complaint_raised_on, |
||||
|
complaint_raised_by, |
||||
|
complaint_updated_on, |
||||
|
complaint_updated_by, |
||||
|
remarks, |
||||
|
imgFileValue, |
||||
|
cby |
||||
|
); |
||||
|
|
||||
|
if (historyAffectedRows <= 0) { |
||||
|
|
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message","Unable to save complaint history"); |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
String logSql = |
||||
|
"INSERT INTO complaints_details_log " + |
||||
|
"(cd_id, zone, ward, location, status, address, source, pct, " + |
||||
|
"complaint_id, description, turn_around_time, vendorid, " + |
||||
|
"created_date, isactive, isdelete) " + |
||||
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; |
||||
|
|
||||
|
|
||||
|
int logAffectedRows = jdbcTemplate.update( |
||||
|
logSql, |
||||
|
|
||||
|
complaint.get("id"), |
||||
|
complaint.get("zone"), |
||||
|
complaint.get("ward"), |
||||
|
complaint.get("location"), |
||||
|
complaint.get("status"), |
||||
|
complaint.get("address"), |
||||
|
complaint.get("source"), |
||||
|
complaint.get("pct"), |
||||
|
complaint.get("complaint_id"), |
||||
|
complaint.get("description"), |
||||
|
complaint.get("turn_around_time"), |
||||
|
complaint.get("vendorid"), |
||||
|
complaint.get("created_date"), |
||||
|
complaint.get("isactive"), |
||||
|
complaint.get("isdelete") |
||||
|
); |
||||
|
|
||||
|
if (logAffectedRows > 0) { |
||||
|
|
||||
|
String updateSql = |
||||
|
"UPDATE complaints_details " + |
||||
|
"SET status = ? " + |
||||
|
"WHERE complaint_id = ? " + |
||||
|
"AND isactive = 1 " + |
||||
|
"AND isdelete = 0"; |
||||
|
|
||||
|
|
||||
|
int updateAffectedRows = jdbcTemplate.update( |
||||
|
updateSql, |
||||
|
status, |
||||
|
complaint_id |
||||
|
); |
||||
|
|
||||
|
if (updateAffectedRows > 0) { |
||||
|
|
||||
|
response.put("status", "Success"); |
||||
|
response.put("message", |
||||
|
"Complaint history saved and complaint status updated successfully"); |
||||
|
|
||||
|
} else { |
||||
|
|
||||
|
/* |
||||
|
* Throw exception so @Transactional rolls everything back. |
||||
|
*/ |
||||
|
throw new RuntimeException( |
||||
|
"Unable to update complaint status" |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
} else { |
||||
|
|
||||
|
/* |
||||
|
* Throw exception so history insert is also rolled back. |
||||
|
*/ |
||||
|
throw new RuntimeException( |
||||
|
"Unable to save complaint details log" |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
|
||||
|
e.printStackTrace(); |
||||
|
response.put("status", "Error"); |
||||
|
response.put("message", "Error while saving complaints history"); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
public List<?> savemanpower(String zone, String ward, String category, String pct, String status,String vendorid) { |
||||
|
|
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
|
||||
|
String checkSql = |
||||
|
"SELECT * " + |
||||
|
"FROM man_power_details " + |
||||
|
"WHERE pct = ? " + |
||||
|
"AND isactive = 1 " + |
||||
|
"AND isdelete = 0 "; |
||||
|
|
||||
|
List<Map<String, Object>> complaintList = |
||||
|
jdbcTemplate.queryForList(checkSql, pct); |
||||
|
|
||||
|
if (complaintList.isEmpty()) { |
||||
|
|
||||
|
|
||||
|
String saveSql = "INSERT INTO man_power_details (zone,ward,category,pct,status,vendorid) " + |
||||
|
"VALUES (?,?,?,?,?,?)"; |
||||
|
|
||||
|
KeyHolder keyHolder = new GeneratedKeyHolder(); |
||||
|
int affectedRows = jdbcTemplate.update(connection -> { |
||||
|
PreparedStatement ps = connection.prepareStatement(saveSql, Statement.RETURN_GENERATED_KEYS); |
||||
|
ps.setString(1, zone); |
||||
|
ps.setString(2, ward); |
||||
|
ps.setString(3, category); |
||||
|
ps.setString(4, pct); |
||||
|
ps.setString(5, status); |
||||
|
ps.setString(6, vendorid); |
||||
|
return ps; |
||||
|
}, keyHolder); |
||||
|
|
||||
|
if (affectedRows > 0) { |
||||
|
response.put("status", "Success"); |
||||
|
response.put("message", "Manpower details Saved Successfully"); |
||||
|
} else { |
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message", "Error while saving man power details"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
else { |
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message","Duplicate PCT " + pct +" already found in man_power_details"); |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
response.put("status", "Error"); |
||||
|
response.put("message", "Error while saving manpower details"); |
||||
|
} |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
@Transactional |
||||
|
public List<?> savemanpoweremps(String pct, String employee_details,Map<String, MultipartFile> files) { |
||||
|
|
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
|
||||
|
|
||||
|
String checkSql = |
||||
|
"SELECT * " + |
||||
|
"FROM man_power_details " + |
||||
|
"WHERE pct = ? " + |
||||
|
"AND isactive = 1 " + |
||||
|
"AND isdelete = 0 "; |
||||
|
|
||||
|
List<Map<String, Object>> complaintList = |
||||
|
jdbcTemplate.queryForList(checkSql, pct); |
||||
|
|
||||
|
if (complaintList.isEmpty()) { |
||||
|
|
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message","PCT " + pct +" not found in man_power_details"); |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
else { |
||||
|
ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
|
||||
|
List<Map<String, Object>> employeeList = |
||||
|
objectMapper.readValue( |
||||
|
employee_details, |
||||
|
new TypeReference<List<Map<String, Object>>>() {} |
||||
|
); |
||||
|
|
||||
|
if (employeeList == null || employeeList.isEmpty()) { |
||||
|
|
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message", "Manpower Employee details cannot be empty"); |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
String saveSql = |
||||
|
"INSERT INTO man_power_employees " + |
||||
|
"(pct, emp_name, att_date, location, mobile_number, imgfile) " + |
||||
|
"VALUES (?, ?, ?, ?, ?, ?)"; |
||||
|
|
||||
|
|
||||
|
int totalSaved = 0; |
||||
|
|
||||
|
for (Map<String, Object> employee : employeeList) { |
||||
|
|
||||
|
String empName =employee.get("emp_name") != null ? employee.get("emp_name").toString(): null; |
||||
|
|
||||
|
String attDate =employee.get("att_date") != null ? employee.get("att_date").toString() : null; |
||||
|
|
||||
|
String location =employee.get("location") != null ? employee.get("location").toString(): null; |
||||
|
|
||||
|
String mobileNumber =employee.get("mobile_number") != null ? employee.get("mobile_number").toString() : null; |
||||
|
|
||||
|
String fileKey =employee.get("fileKey") != null ? employee.get("fileKey").toString() : null; |
||||
|
|
||||
|
MultipartFile file = null; |
||||
|
String filePath = null; |
||||
|
|
||||
|
if (fileKey != null && !fileKey.trim().isEmpty()) { |
||||
|
|
||||
|
file = files.get(fileKey); |
||||
|
|
||||
|
if (file != null && !file.isEmpty()) { |
||||
|
|
||||
|
filePath = fileUpload(file, "dbfot_manpower_img"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
int affectedRows = jdbcTemplate.update(saveSql,pct,empName,attDate,location,mobileNumber, filePath |
||||
|
); |
||||
|
|
||||
|
if (affectedRows > 0) { |
||||
|
|
||||
|
totalSaved++; |
||||
|
|
||||
|
} else { |
||||
|
|
||||
|
throw new RuntimeException("Failed to save employee: " + empName); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
response.put("status", "Success"); |
||||
|
response.put("message","Man power employees saved successfully"); |
||||
|
response.put("count", totalSaved); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
throw new RuntimeException("Error while saving man power employees", e); |
||||
|
} |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
public List<?> savepctmaster(String zone, String ward, String address, String category, String pct, |
||||
|
String status, String vendorid) { |
||||
|
|
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
|
||||
|
String checkSql = |
||||
|
"SELECT * " + |
||||
|
"FROM pct_master " + |
||||
|
"WHERE pct = ? " + |
||||
|
"AND isactive = 1 " + |
||||
|
"AND isdelete = 0 "; |
||||
|
|
||||
|
List<Map<String, Object>> complaintList = |
||||
|
jdbcTemplate.queryForList(checkSql, pct); |
||||
|
|
||||
|
if (complaintList.isEmpty()) { |
||||
|
|
||||
|
|
||||
|
String saveSql = "INSERT INTO pct_master (zone,ward,address,category,pct,status,vendorid) " + |
||||
|
"VALUES (?,?,?,?,?,?,?)"; |
||||
|
|
||||
|
KeyHolder keyHolder = new GeneratedKeyHolder(); |
||||
|
int affectedRows = jdbcTemplate.update(connection -> { |
||||
|
PreparedStatement ps = connection.prepareStatement(saveSql, Statement.RETURN_GENERATED_KEYS); |
||||
|
ps.setString(1, zone); |
||||
|
ps.setString(2, ward); |
||||
|
ps.setString(3, address); |
||||
|
ps.setString(4, category); |
||||
|
ps.setString(5, pct); |
||||
|
ps.setString(6, status); |
||||
|
ps.setString(7, vendorid); |
||||
|
return ps; |
||||
|
}, keyHolder); |
||||
|
|
||||
|
if (affectedRows > 0) { |
||||
|
response.put("status", "Success"); |
||||
|
response.put("message","PCT Master Saved Successfully"); |
||||
|
} else { |
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message", "Error while saving pct master"); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
else { |
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message","Duplicate PCT " + pct +" already found in pct master"); |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
response.put("status", "Error"); |
||||
|
response.put("message", "Error while saving pct master"); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
public List<?> updatepctstatus(String pct, String status, String vendorid) { |
||||
|
|
||||
|
Map<String, Object> response = new HashMap<>(); |
||||
|
|
||||
|
try { |
||||
|
|
||||
|
String checkSql = |
||||
|
"SELECT id, zone, ward,address,category,pct,status, " + |
||||
|
"vendorid,created_date, isactive, isdelete " + |
||||
|
"FROM pct_master " + |
||||
|
"WHERE pct = ? " + |
||||
|
"AND isactive = 1 " + |
||||
|
"AND isdelete = 0 " + |
||||
|
"FOR UPDATE"; |
||||
|
|
||||
|
List<Map<String, Object>> complaintList = |
||||
|
jdbcTemplate.queryForList(checkSql, pct); |
||||
|
|
||||
|
|
||||
|
if (complaintList.isEmpty()) { |
||||
|
|
||||
|
response.put("status", "Failed"); |
||||
|
response.put("message","PCT " + pct + " not found in pct_master"); |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
Map<String, Object> complaint = complaintList.get(0); |
||||
|
|
||||
|
String logSql = |
||||
|
"INSERT INTO pct_master_log " + |
||||
|
"(pct_master_id, zone, ward, address,category,pct, status, " + |
||||
|
"vendorid,created_date, isactive, isdelete) " + |
||||
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; |
||||
|
|
||||
|
|
||||
|
int logAffectedRows = jdbcTemplate.update( |
||||
|
logSql, |
||||
|
|
||||
|
complaint.get("id"), |
||||
|
complaint.get("zone"), |
||||
|
complaint.get("ward"), |
||||
|
complaint.get("address"), |
||||
|
complaint.get("category"), |
||||
|
complaint.get("pct"), |
||||
|
complaint.get("status"), |
||||
|
complaint.get("vendorid"), |
||||
|
complaint.get("created_date"), |
||||
|
complaint.get("isactive"), |
||||
|
complaint.get("isdelete") |
||||
|
|
||||
|
); |
||||
|
|
||||
|
if (logAffectedRows > 0) { |
||||
|
|
||||
|
String updateSql = |
||||
|
"UPDATE pct_master " + |
||||
|
"SET status = ? " + |
||||
|
"WHERE pct = ? " + |
||||
|
"AND isactive = 1 " + |
||||
|
"AND isdelete = 0"; |
||||
|
|
||||
|
|
||||
|
int updateAffectedRows = jdbcTemplate.update( |
||||
|
updateSql, |
||||
|
status, |
||||
|
pct |
||||
|
); |
||||
|
|
||||
|
if (updateAffectedRows > 0) { |
||||
|
|
||||
|
response.put("status", "Success"); |
||||
|
response.put("message","PCT status updated successfully"); |
||||
|
|
||||
|
} else { |
||||
|
|
||||
|
/* |
||||
|
* Throw exception so @Transactional rolls everything back. |
||||
|
*/ |
||||
|
throw new RuntimeException( |
||||
|
"Unable to update pct status" |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
} else { |
||||
|
|
||||
|
/* |
||||
|
* Throw exception so history insert is also rolled back. |
||||
|
*/ |
||||
|
throw new RuntimeException( |
||||
|
"Unable to save in pct master log" |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
e.printStackTrace(); |
||||
|
response.put("status", "Error"); |
||||
|
response.put("message", "Error while updating pct master"); |
||||
|
} |
||||
|
|
||||
|
return Collections.singletonList(response); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
package in.gov.secureapi.service; |
||||
|
|
||||
|
import org.springframework.stereotype.Service; |
||||
|
import java.time.LocalDateTime; |
||||
|
import java.time.format.DateTimeFormatter; |
||||
|
|
||||
|
@Service |
||||
|
public class DateTimeUtil { |
||||
|
public static String getCurrentDateTime() { |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ddMMyyyyHHmmss"); |
||||
|
LocalDateTime now = LocalDateTime.now(); |
||||
|
return now.format(formatter); |
||||
|
} |
||||
|
public static String getCurrentYear() { |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy"); |
||||
|
LocalDateTime now = LocalDateTime.now(); |
||||
|
return now.format(formatter); |
||||
|
} |
||||
|
public static String getCurrentMonth() { |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM"); |
||||
|
LocalDateTime now = LocalDateTime.now(); |
||||
|
return now.format(formatter); |
||||
|
} |
||||
|
public static String getCurrentDay() { |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd"); |
||||
|
LocalDateTime now = LocalDateTime.now(); |
||||
|
return now.format(formatter); |
||||
|
} |
||||
|
public static String getCurrentDateTimeMysql() { |
||||
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); |
||||
|
LocalDateTime now = LocalDateTime.now(); |
||||
|
return now.format(formatter); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,97 @@ |
|||||
|
package in.gov.secureapi.service; |
||||
|
|
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.security.authentication.BadCredentialsException; |
||||
|
import org.springframework.security.authentication.DisabledException; |
||||
|
import org.springframework.security.crypto.password.PasswordEncoder; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import in.gov.secureapi.repository.TokenRepository; |
||||
|
import in.gov.secureapi.repository.UserRepository; |
||||
|
import in.gov.secureapi.util.TokenUtil; |
||||
|
|
||||
|
import java.time.LocalDateTime; |
||||
|
|
||||
|
@Service |
||||
|
public class TokenService { |
||||
|
private final TokenRepository repo; |
||||
|
private final UserRepository userRepository; |
||||
|
private final PasswordEncoder passwordEncoder; |
||||
|
private final long ttlHours; |
||||
|
|
||||
|
public TokenService( |
||||
|
TokenRepository repo, |
||||
|
UserRepository userRepository, |
||||
|
PasswordEncoder passwordEncoder, |
||||
|
@Value("${api.token.ttl-hours:24}") long ttlHours) { |
||||
|
this.repo = repo; |
||||
|
this.userRepository = userRepository; |
||||
|
this.passwordEncoder = passwordEncoder; |
||||
|
this.ttlHours = ttlHours; |
||||
|
} |
||||
|
|
||||
|
public TokenResult authenticateAndCreate(String username, String rawPassword) { |
||||
|
var userOpt = userRepository.findByUsername(username); |
||||
|
if (userOpt.isEmpty()) { |
||||
|
throw new BadCredentialsException("Invalid username or password"); |
||||
|
} |
||||
|
|
||||
|
var user = userOpt.get(); |
||||
|
if (!user.active()) { |
||||
|
throw new DisabledException("User account is inactive"); |
||||
|
} |
||||
|
|
||||
|
boolean matches = passwordEncoder.matches(rawPassword, user.password()); |
||||
|
if (!matches && rawPassword.equals(user.password())) { |
||||
|
matches = true; |
||||
|
} |
||||
|
|
||||
|
if (!matches) { |
||||
|
throw new BadCredentialsException("Invalid username or password"); |
||||
|
} |
||||
|
|
||||
|
return create(user.username()); |
||||
|
} |
||||
|
|
||||
|
public TokenResult create(String username) { |
||||
|
String token = TokenUtil.generateToken(); |
||||
|
LocalDateTime expires = LocalDateTime.now().plusHours(ttlHours); |
||||
|
repo.save(username, TokenUtil.sha256(token), expires); |
||||
|
return new TokenResult(token, username, expires); |
||||
|
} |
||||
|
public enum TokenStatus { |
||||
|
VALID, |
||||
|
EXPIRED, |
||||
|
INACTIVE, |
||||
|
INVALID |
||||
|
} |
||||
|
|
||||
|
public record TokenValidation(TokenStatus status, TokenRepository.TokenInfo info, String message) {} |
||||
|
|
||||
|
public TokenValidation validateDetailed(String token) { |
||||
|
if (token == null || token.isBlank()) { |
||||
|
return new TokenValidation(TokenStatus.INVALID, null, "Bearer token is missing or empty"); |
||||
|
} |
||||
|
String tokenHash = TokenUtil.sha256(token); |
||||
|
var tokenOpt = repo.findByTokenHash(tokenHash); |
||||
|
if (tokenOpt.isEmpty()) { |
||||
|
return new TokenValidation(TokenStatus.INVALID, null, "Invalid token: token not found"); |
||||
|
} |
||||
|
var info = tokenOpt.get(); |
||||
|
if (!info.active()) { |
||||
|
return new TokenValidation(TokenStatus.INACTIVE, info, "Token is inactive or has been revoked. Please authenticate again."); |
||||
|
} |
||||
|
if (!info.expiresAt().isAfter(LocalDateTime.now())) { |
||||
|
return new TokenValidation(TokenStatus.EXPIRED, info, "Token has expired. Please authenticate again to generate a new token."); |
||||
|
} |
||||
|
return new TokenValidation(TokenStatus.VALID, info, "Token is valid"); |
||||
|
} |
||||
|
|
||||
|
public TokenRepository.TokenInfo validate(String token) { |
||||
|
var validation = validateDetailed(token); |
||||
|
return validation.status() == TokenStatus.VALID ? validation.info() : null; |
||||
|
} |
||||
|
|
||||
|
public void revoke(String token) { repo.revoke(TokenUtil.sha256(token)); } |
||||
|
public record TokenResult(String token, String username, LocalDateTime expiresAt) {} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
package in.gov.secureapi.util; |
||||
|
|
||||
|
import java.nio.charset.StandardCharsets; |
||||
|
import java.security.MessageDigest; |
||||
|
import java.security.NoSuchAlgorithmException; |
||||
|
import java.security.SecureRandom; |
||||
|
import java.util.Base64; |
||||
|
|
||||
|
public final class TokenUtil { |
||||
|
private static final SecureRandom RANDOM = new SecureRandom(); |
||||
|
private TokenUtil() {} |
||||
|
|
||||
|
public static String generateToken() { |
||||
|
byte[] bytes = new byte[32]; |
||||
|
RANDOM.nextBytes(bytes); |
||||
|
return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); |
||||
|
} |
||||
|
|
||||
|
public static String sha256(String value) { |
||||
|
try { |
||||
|
MessageDigest md = MessageDigest.getInstance("SHA-256"); |
||||
|
byte[] digest = md.digest(value.getBytes(StandardCharsets.UTF_8)); |
||||
|
StringBuilder sb = new StringBuilder(64); |
||||
|
for (byte b : digest) sb.append(String.format("%02x", b)); |
||||
|
return sb.toString(); |
||||
|
} catch (NoSuchAlgorithmException e) { |
||||
|
throw new IllegalStateException("SHA-256 unavailable", e); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,3 @@ |
|||||
|
assets.base-url=/assets/ |
||||
|
|
||||
|
fileBaseUrl=http://localhost:8088 |
||||
@ -0,0 +1,3 @@ |
|||||
|
assets.base-url=/gccofficialapp/assets/ |
||||
|
|
||||
|
fileBaseUrl=https://gccservices.in |
||||
@ -0,0 +1,67 @@ |
|||||
|
# spring.profiles.active=local |
||||
|
spring.profiles.active=production |
||||
|
|
||||
|
spring.application.name= |
||||
|
|
||||
|
# Enable live reload (default is true) |
||||
|
spring.devtools.livereload.enabled=true |
||||
|
|
||||
|
# Enable restart (default is true) |
||||
|
spring.devtools.restart.enabled=true |
||||
|
|
||||
|
# HTTP Server |
||||
|
server.port = 8088 |
||||
|
|
||||
|
server.error.include-stacktrace= on_param |
||||
|
|
||||
|
# Hibernate logging |
||||
|
logging.level.org.hibernate.SQL=DEBUG |
||||
|
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE |
||||
|
|
||||
|
spring.jackson.time-zone=Asia/Kolkata |
||||
|
|
||||
|
# Maximum file size |
||||
|
spring.servlet.multipart.max-file-size=20MB |
||||
|
|
||||
|
# Maximum request size (including all files) |
||||
|
spring.servlet.multipart.max-request-size=120MB |
||||
|
|
||||
|
spring.mvc.favicon.enabled=false |
||||
|
|
||||
|
file.upload.directory=${user.dir}/secureapi_upload/ |
||||
|
dbfot_toilets = dbfot_toilets |
||||
|
|
||||
|
# =============================== |
||||
|
|
||||
|
# JPA (if using JPA) |
||||
|
|
||||
|
# =============================== |
||||
|
|
||||
|
spring.jpa.hibernate.ddl-auto=none |
||||
|
|
||||
|
spring.jpa.show-sql=false |
||||
|
|
||||
|
spring.jpa.properties.hibernate.format_sql=false |
||||
|
|
||||
|
# =============================== |
||||
|
|
||||
|
# API Token |
||||
|
|
||||
|
# Default = 24 hours |
||||
|
|
||||
|
# =============================== |
||||
|
|
||||
|
api.token.ttl-hours=24 |
||||
|
|
||||
|
# =============================== |
||||
|
|
||||
|
# Logging |
||||
|
|
||||
|
# =============================== |
||||
|
|
||||
|
logging.level.root=INFO |
||||
|
|
||||
|
logging.level.in.gccmanpower=INFO |
||||
|
|
||||
|
|
||||
|
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue