diff --git a/pom.xml b/pom.xml index a908f28..799cce9 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,13 @@ 1.0.0-M3 + + + io.micrometer + micrometer-core + + + org.springframework.boot spring-boot-starter-web @@ -39,6 +46,17 @@ org.springframework.boot spring-boot-starter-webflux + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.ai spring-ai-openai-spring-boot-starter @@ -55,26 +73,92 @@ org.springframework.ai spring-ai-redis-store-spring-boot-starter - - org.springframework.ai - spring-ai-transformers-spring-boot-starter - + + + + + + redis.clients jedis - 5.2.0 + + + + org.projectlombok + lombok + provided + + + org.springframework.boot - spring-boot-starter-test - test + spring-boot-starter-data-jpa + + - io.projectreactor - reactor-test - test + com.mysql + mysql-connector-j + + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime + + + + + org.mapstruct + mapstruct + 1.5.5.Final + + + org.mapstruct + mapstruct-processor + 1.5.5.Final + provided + + + + + jakarta.annotation + jakarta.annotation-api + + + org.apache.tomcat.embed + tomcat-embed-core + 10.1.25 + + + jakarta.servlet + jakarta.servlet-api + 6.0.0 + provided + + + org.springframework.boot + spring-boot-starter-tomcat + + + + @@ -93,6 +177,15 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-compiler-plugin + 3.10.1 + + 17 + 17 + + diff --git a/src/main/java/com/openAi/ai/OpenAiApi.java b/src/main/java/com/openAi/ai/OpenAiApi.java new file mode 100644 index 0000000..a91238b --- /dev/null +++ b/src/main/java/com/openAi/ai/OpenAiApi.java @@ -0,0 +1,22 @@ +package com.openAi.ai; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +public class OpenAiApi { + @Data public static class EmbeddingList { + @JsonProperty("data") + private List data; + + // Getters and setters + } + + @Data public static class Embedding { + @JsonProperty("embedding") + private List embedding; + + // Getters and setters + } +} \ No newline at end of file diff --git a/src/main/java/com/openAi/ai/RedisConfig.java b/src/main/java/com/openAi/ai/RedisConfig.java deleted file mode 100644 index c92d643..0000000 --- a/src/main/java/com/openAi/ai/RedisConfig.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.openAi.ai; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -@Configuration -public class RedisConfig { - - @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { - RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(connectionFactory); - - // Key serializer - template.setKeySerializer(new StringRedisSerializer()); - // Value serializer - //template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); - - return template; - } -} \ No newline at end of file diff --git a/src/main/java/com/openAi/ai/RedisService.java b/src/main/java/com/openAi/ai/RedisService.java deleted file mode 100644 index 51469a7..0000000 --- a/src/main/java/com/openAi/ai/RedisService.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.openAi.ai; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.connection.DataType; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -@Service -public class RedisService { - - @Autowired - private RedisTemplate redisTemplate; - - @Autowired - private ObjectMapper objectMapper; - - public List getKeysByJsonNodeValue(String nodeName, String nodeValue) { - List matchingKeys = new ArrayList<>(); - Set keys = redisTemplate.keys("*"); - - if (keys != null) { - for (String key : keys) { - System.out.println("key: " + key); - - Object value = redisTemplate.opsForValue().get(key); - if (value != null) { - try { - JsonNode jsonNode = objectMapper.readTree(value.toString()); - if (jsonNode.has(nodeName) && jsonNode.get(nodeName).asText().equals(nodeValue)) { - matchingKeys.add(key); - } - } catch (Exception e) { - System.err.println("Error parsing JSON for key: " + key + " - " + e.getMessage()); - } - } - } - - - } - - - return matchingKeys; - } - /* public List getKeysByJsonNodeValue(String nodeName, String nodeValue) { - return new ArrayList<>(); - }*/ -} \ No newline at end of file diff --git a/src/main/java/com/openAi/application/OpenAiApplication.java b/src/main/java/com/openAi/application/OpenAiApplication.java index 4a008f4..f5e6026 100644 --- a/src/main/java/com/openAi/application/OpenAiApplication.java +++ b/src/main/java/com/openAi/application/OpenAiApplication.java @@ -1,13 +1,43 @@ package com.openAi.application; - +import com.openAi.security.AuthenticationFilter; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.openai.OpenAiChatModel; +import org.springframework.ai.openai.api.OpenAiApi; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -@SpringBootApplication(scanBasePackages = "com.openAi") +@SpringBootApplication(scanBasePackages = "com.openAi", exclude = {SecurityAutoConfiguration.class}) +@EnableJpaRepositories(basePackages = "com.openAi.security.repository") +@EntityScan(basePackages = "com.openAi.security.entity") public class OpenAiApplication { - public static void main(String[] args) { - SpringApplication.run(OpenAiApplication.class, args); - } -} + + public static void main(String[] args) { + SpringApplication.run(OpenAiApplication.class, args); + } + + @Bean + ChatModel chatModel(@Value("${spring.ai.openai.api-key}") String apiKey) { + return new OpenAiChatModel(new OpenAiApi(apiKey)); + } + + @Bean + public FilterRegistrationBean filterRegistrationBean() { + AuthenticationFilter filter = new AuthenticationFilter(); + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(filter); + registrationBean.setEnabled(false); + return registrationBean; + } + + +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/AuthenticationFilter.java b/src/main/java/com/openAi/security/AuthenticationFilter.java new file mode 100644 index 0000000..86362d3 --- /dev/null +++ b/src/main/java/com/openAi/security/AuthenticationFilter.java @@ -0,0 +1,134 @@ +package com.openAi.security; + +import com.openAi.security.exceptions.InvalidAuthenticationException; +import com.openAi.security.model.UserModel; +import com.openAi.security.service.UserService; +import com.openAi.security.utils.JwtUtils; +import io.jsonwebtoken.Claims; +import jakarta.servlet.FilterChain; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.context.support.SpringBeanAutowiringSupport; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.util.Collections; +import java.util.Date; +import java.util.Objects; +import java.util.UUID; + +import static com.openAi.security.enums.EntityStatus.ACTIVE; + +@Slf4j +@Component + +public class AuthenticationFilter extends OncePerRequestFilter { + + @Autowired + private JwtUtils jwtUtils; + @Autowired + private UserService userService; + @Autowired + private HttpServletRequest httpServletRequest; + + @Value("${security.apiKey}") + private String apiKey; + private AuthenticationManager authenticationManager; + + public AuthenticationFilter() { + SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); + } + + @Override + @SneakyThrows + protected void doFilterInternal( + HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) { + + String path = request.getRequestURI(); + log.info( + String.format("Requested path: %s at %s by %s", path, new Date(), request.getRemoteHost())); + if ( + new AntPathMatcher().match("/getToken", path) + || HttpMethod.OPTIONS.name().equalsIgnoreCase(request.getMethod()) + || new AntPathMatcher().match("/", path) + && apiKey.equals(request.getHeader("Api-Key"))) { + filterChain.doFilter(request, response); + return; + } + + String jwt; + try { + jwt = parseJwt(); + jwtUtils.validateJwtToken(jwt); + } catch (Exception e) { + log.error( + String.format( + "%s | AUTHORIZATION Header: %s", + e.getMessage(), request.getHeader(HttpHeaders.AUTHORIZATION))); + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + return; + } + + Claims claims = jwtUtils.getAllClaimsFromToken(jwt); + String email = claims.getSubject(); + UserModel userModel; + try { + userModel = userService.findUserByEmailOrAttendance(email); + } catch (Exception e) { + log.error("User not found for email {}", email); + response.setStatus(HttpStatus.UNAUTHORIZED.value()); + return; + } + + boolean enabled = ACTIVE.equals(userModel.getStatus()); + User user = + new User( + userModel.getEmail(), + UUID.randomUUID().toString(), + enabled, + true, + true, + true, + Collections.singletonList(new SimpleGrantedAuthority(userModel.getRole().name()))); + + final UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); + SecurityContextHolder.getContext().setAuthentication(authentication); + + filterChain.doFilter(request, response); + } + + public String parseJwt() { + + Cookie[] cookieAuth = httpServletRequest.getCookies(); + if (Objects.nonNull(cookieAuth)) { + for (Cookie cookie : cookieAuth) { + if (cookie.getName().equals("auth-token")) { + return cookie.getValue(); + } + } + } + + throw InvalidAuthenticationException.invalidToken("Failed to parse JWT Token"); + } + + public void setAuthenticationManager(AuthenticationManager authenticationManager) { + this.authenticationManager = authenticationManager; + } +} + + diff --git a/src/main/java/com/openAi/security/ConfigController.java b/src/main/java/com/openAi/security/ConfigController.java new file mode 100644 index 0000000..7fbd1d2 --- /dev/null +++ b/src/main/java/com/openAi/security/ConfigController.java @@ -0,0 +1,27 @@ +package com.openAi.security; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.cors.CorsConfiguration; + +@RestController +@RequestMapping("/security-config") +@EnableCaching +@Slf4j +@RequiredArgsConstructor +public class ConfigController { + + private final com.openAi.security.WebSecurityConfig webSecurityConfig; + + @PostMapping("/refresh-cors-config") + public ResponseEntity refreshCorsConfig() { + CorsConfiguration configuration = new CorsConfiguration(); + webSecurityConfig.updateCorsConfiguration(configuration); + return ResponseEntity.ok("CORS configuration updated successfully"); + } +} diff --git a/src/main/java/com/openAi/security/CustomHttpServletRequestFactory.java b/src/main/java/com/openAi/security/CustomHttpServletRequestFactory.java new file mode 100644 index 0000000..c952977 --- /dev/null +++ b/src/main/java/com/openAi/security/CustomHttpServletRequestFactory.java @@ -0,0 +1,14 @@ +package com.openAi.security; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper; +import org.springframework.stereotype.Component; + +@Component +public class CustomHttpServletRequestFactory { + + public SecurityContextHolderAwareRequestWrapper create(HttpServletRequest request, HttpServletResponse response) { + return new SecurityContextHolderAwareRequestWrapper(request, response.toString()); + } +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/CustomSecurityContextHolderAwareRequestFilter.java b/src/main/java/com/openAi/security/CustomSecurityContextHolderAwareRequestFilter.java new file mode 100644 index 0000000..ef7b139 --- /dev/null +++ b/src/main/java/com/openAi/security/CustomSecurityContextHolderAwareRequestFilter.java @@ -0,0 +1,31 @@ +package com.openAi.security; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter; +import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper; +import org.springframework.stereotype.Component; + +@Component +public class CustomSecurityContextHolderAwareRequestFilter extends SecurityContextHolderAwareRequestFilter { + + private final CustomHttpServletRequestFactory customHttpServletRequestFactory; + + public CustomSecurityContextHolderAwareRequestFilter(CustomHttpServletRequestFactory customHttpServletRequestFactory) { + this.customHttpServletRequestFactory = customHttpServletRequestFactory; + } +// @Override + protected SecurityContextHolderAwareRequestWrapper wrapRequest(HttpServletRequest request) { + return customHttpServletRequestFactory.create(request, null); + } + +// @Override + protected SecurityContextHolderAwareRequestWrapper wrapRequest(HttpServletRequest request, HttpServletResponse response) { + return customHttpServletRequestFactory.create(request, response); + } + +// @Override + protected SecurityContextHolderAwareRequestWrapper create(HttpServletRequest request, HttpServletResponse response) { + return customHttpServletRequestFactory.create(request, response); + } +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/PasswordEncryptor.java b/src/main/java/com/openAi/security/PasswordEncryptor.java new file mode 100644 index 0000000..000b9f9 --- /dev/null +++ b/src/main/java/com/openAi/security/PasswordEncryptor.java @@ -0,0 +1,15 @@ +package com.openAi.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordEncryptor { + + @Bean + public PasswordEncoder passwordEncoder(){ + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/com/openAi/security/WebSecurityConfig.java b/src/main/java/com/openAi/security/WebSecurityConfig.java new file mode 100644 index 0000000..ef459b1 --- /dev/null +++ b/src/main/java/com/openAi/security/WebSecurityConfig.java @@ -0,0 +1,141 @@ +//package com.openAi.security; +// +//import com.openAi.security.entity.AllowedDomain; +//import com.openAi.security.repository.AllowedDomainRepository; +//import lombok.RequiredArgsConstructor; +// +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.context.annotation.Profile; +//import org.springframework.http.HttpStatus; +//import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +//import org.springframework.security.config.annotation.web.builders.HttpSecurity; +//import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +//import org.springframework.security.config.http.SessionCreationPolicy; +//import org.springframework.security.web.authentication.HttpStatusEntryPoint; +//import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +//import org.springframework.web.cors.CorsConfiguration; +//import org.springframework.web.cors.CorsConfigurationSource; +//import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +// +//import java.util.Arrays; +//import java.util.List; +// +//@Configuration +//@EnableWebSecurity +//@EnableGlobalMethodSecurity(prePostEnabled = true) +//@RequiredArgsConstructor +//public class WebSecurityConfig { +// +// private final AuthenticationFilter filter; +// +// private final AllowedDomainRepository allowedDomainRepository; +// +// private CorsConfiguration configuration = new CorsConfiguration(); +// +// +//// @Override +// protected void configure(HttpSecurity http) throws Exception { +// http.cors(cors -> cors.configurationSource(corsConfigurationSource())) +// .csrf(csrf -> csrf.disable()) +// .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) +// .authorizeHttpRequests(authorize -> authorize +// .requestMatchers( +// "/getToken", +// "/cicero/cicero-compliance-data", +// "/cicero/importCiceroData", +// "/technology/getTechDigest/label", +// "/valueAdd/valueAddsByTag", +// "/tech/categories", +// "/tech/categories/*", +// "/tech/category/*/value-adds", +// "/tech/category/*/blogs", +// "/tech/category/*/teams", +// "/tech/category/**", +// "/tech/**", +// "/getTokenUserAuth", +// "/user/generatePassword", +// "/resetPassword", +// "/getTokenGoogleAuth" +// ).permitAll() +// .anyRequest().authenticated() +// ) +// .exceptionHandling(exception -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) +// .addFilterBefore(filter, AuthenticationFilter.class); +// } +// @Bean +// @Profile({"dev","staging","prod"}) +// public CorsConfigurationSource corsConfigurationSource() { +// updateCorsConfiguration(); +// configuration.addExposedHeader("Set-Cookie"); +// configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); +// // setAllowCredentials(true) is important, otherwise: +// // The value of the 'Access-Control-Allow-Origin' header in the response must not be the +// // wildcard '*' when the request's credentials mode is 'include'. +// // setAllowedHeaders is important! Without it, OPTIONS preflight request +// // will fail with 403 Invalid CORS request +// configuration.setAllowedHeaders( +// List.of( +// "Api-Key", +// "Authorization", +// "Cache-Control", +// "Content-Type", +// "Access-Control-Allow-Origin", +// "Access-Control-Allow-Credentials")); +// configuration.setAllowCredentials(true); +// +// final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); +// source.registerCorsConfiguration("/**", configuration); +// return source; +// } +// +// @Bean +// @Profile("test") +// public CorsConfigurationSource corsConfigurationSourceTest() { +// final CorsConfiguration corsConfiguration = new CorsConfiguration(); +// corsConfiguration.setAllowedOrigins( +// List.of( +// "https://playbook.talentica.com/", +// "https://orion.talentica.com/", +// "https://prod-orion.talentica.com/", +// "http://localhost:3000/", +// "http://localhost/", +// "https://stagingplaybook.talentica.com", +// "https://dev-orion.talentica.com/", +// "https://stagingorion.talentica.com", +// "https://staging-orion.talentica.com/", +// "http://localhost:3001/", +// "https://stagingknowledgebase.talentica.com/", +// "https://stagingknowledgebase-sales.talentica.com/", +// "https://staging.kb.talentica.com/", +// "https://stagingknowledgebase.talentica.com/", +// "https://nexus.talentica.com/", +// "https://kb.talentica.com/")); +// corsConfiguration.addExposedHeader("Set-Cookie"); +// corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "PUT", "DELETE")); +// // setAllowCredentials(true) is important, otherwise: +// // The value of the 'Access-Control-Allow-Origin' header in the response must not be the +// // wildcard '*' when the request's credentials mode is 'include'. +// // setAllowedHeaders is important! Without it, OPTIONS preflight request +// // will fail with 403 Invalid CORS request +// corsConfiguration.setAllowedHeaders( +// List.of( +// "Api-Key", +// "Authorization", +// "Cache-Control", +// "Content-Type", +// "Access-Control-Allow-Origin", +// "Access-Control-Allow-Credentials")); +// corsConfiguration.setAllowCredentials(true); +// +// final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); +// source.registerCorsConfiguration("/**", corsConfiguration); +// return source; +// } +// +// public void updateCorsConfiguration() { +// List origins = allowedDomainRepository.findAll() +// .stream().map(AllowedDomain::getDomainName).toList(); +// configuration.setAllowedOrigins(origins); +// } +//} diff --git a/src/main/java/com/openAi/security/controller/AuthController.java b/src/main/java/com/openAi/security/controller/AuthController.java new file mode 100644 index 0000000..fe07fe9 --- /dev/null +++ b/src/main/java/com/openAi/security/controller/AuthController.java @@ -0,0 +1,242 @@ +package com.openAi.security.controller; + +import com.fasterxml.jackson.databind.JsonNode; +import com.openAi.security.exceptions.CustomRuntimeException; +import com.openAi.security.model.JwtRequest; +import com.openAi.security.model.UserRequest; +import com.openAi.security.model.WebClientResponse; +import com.openAi.security.repository.CustomerCredentialRepository; +import com.openAi.security.entity.CustomerCredentials; +import com.openAi.security.service.UserService; +import com.openAi.security.utils.JwtUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseCookie; +import org.springframework.http.ResponseEntity; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.reactive.function.client.WebClient; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +@Slf4j +@RestController +@RequiredArgsConstructor +public class AuthController { + + private static final String ERROR_DUE_TO_INVALID_EMAIL = "Bad/Unauthorised Request error due to Invalid email"; + private static final String COOKIE = "Set-Cookie"; + private static final String BEARER = "Bearer "; + private final JwtUtils jwtUtils; + private final HttpServletResponse httpServletResponse; + private final HttpServletRequest httpServletRequest; + private final UserService userService; + private final CustomerCredentialRepository customerCredentialRepository; + + @Value("${security.jwtExpirationMs}") + private Long jwtExpirationMs; + private final PasswordEncoder passwordEncoder; + + @PostMapping("/getTokenUserAuth") + public ResponseEntity authenticateCustomer(@RequestBody UserRequest userRequest){ + String user = userRequest.getUser(); + List credentialsList = customerCredentialRepository.findAllByUserNameOrUserEmail(user,user); + if(credentialsList.isEmpty()){ + log.error(ERROR_DUE_TO_INVALID_EMAIL); + return ResponseEntity.status(HttpStatus.NON_AUTHORITATIVE_INFORMATION).body(WebClientResponse.builder() + .reason("Incorrect Username") + .build()); + } + CustomerCredentials customerCredentials = credentialsList.get(0); + if(!passwordEncoder.matches(userRequest.getPassword(),customerCredentials.getPassword())){ + return ResponseEntity.status(HttpStatus.NON_AUTHORITATIVE_INFORMATION).body(WebClientResponse.builder() + .reason("Incorrect Password") + .build()); + } + + else{ + String jwt = jwtUtils.getJWTToken(customerCredentials.getUserEmail()); + userService.saveUserLog(customerCredentials.getUserEmail()); + + + var cookie = getAuthCookie(jwt); + httpServletResponse.addHeader(COOKIE, cookie.toString()); + + customerCredentials.setLoginCount(Optional.ofNullable(customerCredentials.getLoginCount()).orElse(0) + 1); + customerCredentialRepository.save(customerCredentials); + + return ResponseEntity.ok(WebClientResponse.builder() + .givenName(customerCredentials.getUserName()) + .displayName(customerCredentials.getUserName()) + .mail(customerCredentials.getUserEmail()) + .isResetRequired(!customerCredentials.getIsReset()) + .token(BEARER + jwt).build()); + } + } + + @PostMapping("/resetPassword") + public ResponseEntity resetPassword(@RequestBody UserRequest userRequest){ + String user = userRequest.getUser(); + List credentialsList = customerCredentialRepository.findAllByUserNameOrUserEmail(user,user); + if(credentialsList.isEmpty()){ + log.error(ERROR_DUE_TO_INVALID_EMAIL); + return ResponseEntity.status(HttpStatus.NON_AUTHORITATIVE_INFORMATION).body(WebClientResponse.builder() + .reason("Incorrect Username") + .build()); + } + String actualPwd = credentialsList.get(0).getPassword(); + String password = userRequest.getOldPassword(); + + if(!passwordEncoder.matches(password,actualPwd)){ + return ResponseEntity.status(HttpStatus.NON_AUTHORITATIVE_INFORMATION).body(WebClientResponse.builder() + .reason("Incorrect Password") + .build()); + } + + if(userRequest.getPassword().isBlank()){ + return ResponseEntity.status(HttpStatus.NON_AUTHORITATIVE_INFORMATION).body(WebClientResponse.builder() + .reason("Enter New Password") + .build()); + } + + credentialsList.get(0).setPassword(passwordEncoder.encode(userRequest.getPassword())); + credentialsList.get(0).setPwdGeneratedDate(new Date()); + credentialsList.get(0).setIsReset(true); + + customerCredentialRepository.save(credentialsList.get(0)); + + String jwt = jwtUtils.getJWTToken(credentialsList.get(0).getUserEmail()); + userService.saveUserLog(credentialsList.get(0).getUserEmail()); + + if(Boolean.TRUE.equals(credentialsList.get(0).getIsReset())) { + var cookie = getAuthCookie(jwt); + httpServletResponse.addHeader(COOKIE, cookie.toString()); + } + + return ResponseEntity.ok(WebClientResponse.builder() + .givenName(credentialsList.get(0).getUserName()) + .displayName(credentialsList.get(0).getUserName()) + .mail(credentialsList.get(0).getUserEmail()) + .isResetRequired(!credentialsList.get(0).getIsReset()) + .token(BEARER + jwt).build()); + } + + @GetMapping("/initialLogin") + public ResponseEntity ifInitialLogin(@RequestParam String email) { + List credentialsList = customerCredentialRepository.findAllByUserEmail(email); + if(credentialsList.isEmpty()){ + throw new IllegalArgumentException(ERROR_DUE_TO_INVALID_EMAIL); + } + return ResponseEntity.ok(credentialsList.get(0).getLoginCount() == 1); + } + + @PostMapping("/getTokenGoogleAuth") + public ResponseEntity authenticateGoogleUser(@RequestBody JwtRequest jwtRequest) { + WebClient client = WebClient.create(); + JsonNode response = client.get() + .uri("https://www.googleapis.com/oauth2/v3/userinfo") + .headers(headers -> { + headers.setBearerAuth(jwtRequest.getToken()); + headers.setContentType(MediaType.APPLICATION_JSON); + }) + .retrieve() + .bodyToMono(JsonNode.class) + .block(); + + log.info( + "Profile successfully validated from google against user {}", + Objects.requireNonNull(response).get("email").asText()); + + String mail = response.get("email").asText(); + if (mail == null) { + log.error(ERROR_DUE_TO_INVALID_EMAIL); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + + String jwt = jwtUtils.getJWTToken(mail); + + log.info("JWT token fetched successfully for valid email: {}", mail); + + userService.saveUserLog(mail); + + var cookie = getAuthCookie(jwt); + httpServletResponse.addHeader(COOKIE, cookie.toString()); + + return ResponseEntity.ok(WebClientResponse.builder() + .id(response.get("sub").asText()) + .givenName(response.get("given_name").asText()) + .displayName(response.get("name").asText()) + .mail(mail) + .token(BEARER + jwt).build()); + } + + @PostMapping("/getToken") + public ResponseEntity authenticateUser(@RequestBody JwtRequest jwtRequest) { + WebClient client = WebClient.create(); + WebClientResponse response = + client + .get() + .uri("https://graph.microsoft.com/v1.0/me") + .headers( + headers -> { + headers.setBearerAuth(jwtRequest.getToken()); + headers.setContentType(MediaType.APPLICATION_JSON); + }) + .retrieve() + .bodyToMono(WebClientResponse.class) + .block(); + log.info( + "Me profile successfully validated from microsoft against user {}", + Objects.requireNonNull(response).getMail()); + + String mail = response.getMail(); + if (StringUtils.isEmpty(response.getMail())) { + log.error(ERROR_DUE_TO_INVALID_EMAIL); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + + String jwt = jwtUtils.getJWTToken(mail); + response.setToken(BEARER + jwt); + log.info("JWT token fetched successfully for valid email: {}", response.getMail()); + + userService.saveUserLog(mail); + + + var cookie = getAuthCookie(jwt); + httpServletResponse.addHeader(COOKIE, cookie.toString()); + + return ResponseEntity.ok(response); + } + + private ResponseCookie getAuthCookie(String authToken) { + URL url = null; + try { + url = new URL(httpServletRequest.getRequestURL().toString()); + } catch (MalformedURLException e) { + throw new CustomRuntimeException(e.getMessage()); + } + final String cookieName = "auth-token"; + final int expiryTime = Math.toIntExact(jwtExpirationMs / 1000); // millis in seconds + return ResponseCookie + .from(cookieName,authToken) + .secure(true) + .httpOnly(false) + .path("/") + .maxAge(expiryTime) + .domain(url.getHost().equalsIgnoreCase("localhost")?"localhost":".talentica.com") + .sameSite("None") + .build(); + + } +} diff --git a/src/main/java/com/openAi/security/controller/UserController.java b/src/main/java/com/openAi/security/controller/UserController.java new file mode 100644 index 0000000..913fcf0 --- /dev/null +++ b/src/main/java/com/openAi/security/controller/UserController.java @@ -0,0 +1,121 @@ +package com.openAi.security.controller; + +import com.openAi.security.entity.Roles; +import com.openAi.security.entity.User; +import com.openAi.security.enums.AppConstant; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.UserRole; +import com.openAi.security.mapper.UserMapper; +import com.openAi.security.mapper.UserTeamRolesMapper; +import com.openAi.security.model.UserListViewResponse; +import com.openAi.security.model.UserModel; +import com.openAi.security.service.UserService; +import com.openAi.security.service.UserTeamRoleService; +import com.openAi.security.utils.SessionUtils; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.mapstruct.factory.Mappers; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +@Slf4j +@RestController +@RequestMapping("/user") +@RequiredArgsConstructor +public class UserController { + + UserMapper userMapper = Mappers.getMapper(UserMapper.class); + UserTeamRolesMapper userTeamRolesMapper = Mappers.getMapper(UserTeamRolesMapper.class); + private final UserService userService; + private final SessionUtils sessionUtils; + private final UserTeamRoleService userTeamRoleService; + + @GetMapping("/loggedInUser") + public ResponseEntity getLoggedInUser() { + return ResponseEntity.status(HttpStatus.OK).body(sessionUtils.getLoggedInUser()); + } + + @GetMapping + public ResponseEntity getUser(@RequestParam String email) { + if (StringUtils.isEmpty(email)) { + log.error("Invalid email address."); + throw new IllegalArgumentException("Invalid email address"); + } + UserModel userModel = userService.findUserByEmailOrAttendance(email); + return ResponseEntity.status(HttpStatus.OK).body(userModel); + } + + @GetMapping("/roles") + public ResponseEntity> getRoles() { + List roles = userService.getRoles(); + return ResponseEntity.status(HttpStatus.OK).body(roles); + } + + @GetMapping("all") + public ResponseEntity getAllUser( + @RequestParam(value = "role", required = false) UserRole role, + @RequestParam(value = "status", required = false) EntityStatus status, + @RequestParam(value = "name", required = false) String name, + @RequestParam(value = "email", required = false) String email, + @RequestParam(value = "teamName", required = false) String teamName, + @RequestParam(value = "isTeg", required = false) Boolean isTeg, + @RequestParam(value = "orderBy", defaultValue = "id", required = false) String orderBy, + @RequestParam(value = "direction", defaultValue = "DESC", required = false) + Sort.Direction direction, + @RequestParam(value = "page", defaultValue = AppConstant.DEFAULT_PAGE, required = false) + int page, + @RequestParam(value = "size", defaultValue = AppConstant.DEFAULT_PAGE_SIZE, required = false) + int size, + @RequestParam(value = "searchField", required = false) String searchField) { + Sort sort = + orderBy.equalsIgnoreCase("id") + ? Sort.by(direction, orderBy) + : Sort.by(direction, orderBy).and(Sort.by(Sort.Direction.ASC, "id")); + Pageable paging = PageRequest.of(page, size, sort); + Specification userSpecification = Specification.where(null); + + if (Arrays.asList(UserRole.values()).contains(role)) { + userSpecification = userSpecification.and(User.roleSpec(role)); + } + if (Objects.nonNull(status)) { + userSpecification = userSpecification.and(User.statusSpec(status)); + } + if (Objects.nonNull(name)) { + userSpecification = userSpecification.and(User.nameSpec(name)); + } + if (Objects.nonNull(email)) { + userSpecification = userSpecification.and(User.emailSpec(email)); + } + if (Objects.nonNull(teamName)) { + userSpecification = userSpecification.and(User.teamSpec(teamName)); + } + if (Objects.nonNull(isTeg)) { + userSpecification = userSpecification.and(User.isTegSpec(isTeg)); + } + if (StringUtils.isNotBlank(searchField)) { + userSpecification = userSpecification.and(User.userSearchFieldSpec(searchField)); + } + userSpecification = userSpecification.and(User.distinct()); + UserListViewResponse userListViewResponse = userService.findAllUsers(userSpecification, paging); + return ResponseEntity.status(HttpStatus.OK).body(userListViewResponse); + } + + @GetMapping("/manager-list") + public ResponseEntity> getSeniorManagers(@RequestParam(required = true) String role) { + UserRole userRole = UserRole.valueOf(role); + return ResponseEntity.ok(userTeamRoleService.getUsersByRole(userRole)); + } +} diff --git a/src/main/java/com/openAi/security/entity/AllowedDomain.java b/src/main/java/com/openAi/security/entity/AllowedDomain.java new file mode 100644 index 0000000..1c8be4e --- /dev/null +++ b/src/main/java/com/openAi/security/entity/AllowedDomain.java @@ -0,0 +1,41 @@ +package com.openAi.security.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import jakarta.persistence.*; +import java.time.LocalDate; + +@Entity +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "allowed_domain") +public class AllowedDomain { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(columnDefinition = "INT(11) UNSIGNED") + private Integer id; + + @Column(name = "domain_name") + private String domainName; + + @Column(name = "customer_id") + private Integer customerId; + + @Column(name = "team_ids") + private String teamIds; + + @Column(name = "is_on_boarded") + private Boolean isOnBoarded; + + @Column(name = "on_boarded_date") + private LocalDate onBoardedDate; + + @Column(name = "data_from") + private LocalDate dataFrom; +} diff --git a/src/main/java/com/openAi/security/entity/Attendance.java b/src/main/java/com/openAi/security/entity/Attendance.java new file mode 100644 index 0000000..01bbe4c --- /dev/null +++ b/src/main/java/com/openAi/security/entity/Attendance.java @@ -0,0 +1,79 @@ +package com.openAi.security.entity; + +import lombok.*; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.util.Date; + +@Entity +@Data +@Table(name = "attendance") +public class Attendance { + + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + private String employeeCode; + + private String employeeName; + + private String firstName; + + private String lastName; + + private String projectName; + + private String employeeGrade; + + private String reportingManager; + + private String emailId; + + private Integer presentDays; + + private Integer year; + + private Integer month; + + private Date assignmentStartDate; + + private Date assignmentEndDate; + + private Date dateOfJoining; + + private String employeeFunction; + + private Integer billingPercentage; + + private String businessUnit; + + public Attendance(Attendance att) { + this.id = att.id; + this.employeeCode = att.employeeCode; + this.employeeName = att.employeeName; + this.firstName = att.firstName; + this.lastName = att.lastName; + this.projectName = att.projectName; + this.employeeGrade = att.employeeGrade; + this.reportingManager = att.reportingManager; + this.emailId = att.emailId; + this.presentDays = att.presentDays; + this.year = att.year; + this.month = att.month; + this.assignmentStartDate = att.assignmentStartDate; + this.assignmentEndDate = att.assignmentEndDate; + this.employeeFunction = att.employeeFunction; + this.billingPercentage = att.billingPercentage; + this.businessUnit = att.businessUnit; + this.dateOfJoining = att.dateOfJoining; + + } + +} diff --git a/src/main/java/com/openAi/security/entity/Customer.java b/src/main/java/com/openAi/security/entity/Customer.java new file mode 100644 index 0000000..add4481 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/Customer.java @@ -0,0 +1,54 @@ +package com.openAi.security.entity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.enums.EntityStatus; +import lombok.*; +import lombok.experimental.Accessors; + +import jakarta.persistence.*; +import java.time.LocalDate; +import java.util.List; + +@Entity +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +@Table(name = "customers") +public class Customer { + + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + private String customerName; + private String projectName; + + @Enumerated(EnumType.STRING) + private EntityStatus status = EntityStatus.ACTIVE; + + private String currentStage; + + private String engagementType; + + @OneToMany(mappedBy = "customer", cascade = CascadeType.MERGE, fetch = FetchType.LAZY) + @JsonIgnoreProperties("teamLeads") + private List teams; + + + @Column(columnDefinition = "DATE") + private LocalDate startDate; + + @Column(columnDefinition = "DATE") + private LocalDate endDate; + + private Boolean isCicero; + + private Boolean isTeg; + + private String link; + +} diff --git a/src/main/java/com/openAi/security/entity/CustomerCredentials.java b/src/main/java/com/openAi/security/entity/CustomerCredentials.java new file mode 100644 index 0000000..88e107f --- /dev/null +++ b/src/main/java/com/openAi/security/entity/CustomerCredentials.java @@ -0,0 +1,28 @@ +package com.openAi.security.entity; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import jakarta.persistence.*; +import java.util.Date; + +@Entity +@Getter +@Setter +@Accessors(chain = true) +@Table(name = "customer_credentials") +public class CustomerCredentials { + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + private String userName; + private String userEmail; + private String password; + private Boolean isReset; + private Date pwdGeneratedDate; + private Integer loginCount; + private Boolean tourClosed; +} diff --git a/src/main/java/com/openAi/security/entity/Roles.java b/src/main/java/com/openAi/security/entity/Roles.java new file mode 100644 index 0000000..e303a13 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/Roles.java @@ -0,0 +1,24 @@ +package com.openAi.security.entity; + +import com.openAi.security.enums.UserRole; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import jakarta.persistence.*; + +@Entity +@Getter +@Setter +@Accessors(chain = true) +public class Roles { + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @Enumerated(EnumType.STRING) + private UserRole role = UserRole.LEAD; + + private float priority; +} diff --git a/src/main/java/com/openAi/security/entity/Team.java b/src/main/java/com/openAi/security/entity/Team.java new file mode 100644 index 0000000..85a0910 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/Team.java @@ -0,0 +1,144 @@ +package com.openAi.security.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.TeamType; +import lombok.*; +import lombok.experimental.Accessors; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.jpa.domain.Specification; + +import jakarta.persistence.*; +import jakarta.persistence.criteria.JoinType; +import java.time.LocalDate; +import java.util.List; + +/** + * Team Entity. + */ +@Entity +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +public class Team { + + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer id; + + private String teamName; + + private String teamShortName; + + private String teamJiraName; + + private String teamJiraLink; + + @Enumerated(EnumType.STRING) + private TeamType teamType; + + private Double noOfHoursPerSP; + + @ManyToMany(fetch = FetchType.LAZY) + @JsonIgnoreProperties("teams") + @JoinTable( + name = "user_teams", + joinColumns = @JoinColumn(name = "teams_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id")) + private List teamLeads; + + @Column(columnDefinition = "DATE") + private LocalDate activeSince; + + @Column(columnDefinition = "DATE") + private LocalDate endDate; + + @Enumerated(EnumType.STRING) + private EntityStatus status = EntityStatus.ACTIVE; + + private Boolean isTeg; + private Boolean excludeCompliance; + + private Boolean complianceByStory; + + @JsonIgnore + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "customer_id") + @JsonIgnoreProperties("teams") + private Customer customer; + + private String doneStatuses; + + private String onTimeIssueTypes; +/* + public static Specification idSpec(int id) { + return (team, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(team.get("id"), id); + } + + public static Specification statusSpec(EntityStatus status) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.equal((team.get("status")), status); + } + + public static Specification teamTypeSpec(TeamType teamType) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.equal((team.get("teamType")), teamType); + } + + public static Specification teamNameSpec(String teamName) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like(team.get("teamName"), "%" + teamName + "%"); + } + + public static Specification teamLeadNameSpec(String teamLeadName) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like( + team.join("teamLeads", JoinType.LEFT).get("name"), "%" + teamLeadName + "%"); + } + + public static Specification teamLeadEmailSpec(String teamLeadEmail) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like( + team.join("teamLeads", JoinType.LEFT).get("email"), "%" + teamLeadEmail + "%"); + } + + public static Specification isTegSpec(Boolean isTeg) { + return (team, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.equal((team.get("isTeg")), isTeg); + } + + public static Specification distinct() { + return (root, query, cb) -> { + query.distinct(true); + return null; + }; + } + + public static Specification teamSearchFieldSpec(String searchField) { + Specification teamSpecification = Specification.where(null); + if (StringUtils.isNumeric(searchField)) { + int id = Integer.parseInt(searchField); + teamSpecification = teamSpecification.or(Team.idSpec(id)); + } + try { + var entityStatus = EntityStatus.valueOf(searchField.toUpperCase()); + teamSpecification = teamSpecification.or(Team.statusSpec(entityStatus)); + } catch (IllegalArgumentException e) { + // Not Entity Status + } + try { + var teamType = TeamType.valueOf(searchField.toUpperCase()); + teamSpecification = teamSpecification.or(Team.teamTypeSpec(teamType)); + } catch (IllegalArgumentException e) { + // Not Team Type + } + teamSpecification = + teamSpecification.or(Team.teamLeadNameSpec(searchField)).or(Team.teamNameSpec(searchField)); + return teamSpecification; + }*/ +} diff --git a/src/main/java/com/openAi/security/entity/User.java b/src/main/java/com/openAi/security/entity/User.java new file mode 100644 index 0000000..c3a1b3b --- /dev/null +++ b/src/main/java/com/openAi/security/entity/User.java @@ -0,0 +1,121 @@ +package com.openAi.security.entity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.entity.Team; +import com.openAi.security.entity.UserTeamRoles; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.UserRole; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.jpa.domain.Specification; + +import jakarta.persistence.*; +import jakarta.persistence.criteria.JoinType; +import java.util.List; + +/** + * User Entity. + */ +@Entity +@Getter +@Setter +@Accessors(chain = true) +public class User { + + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + private String name; + + @Enumerated(EnumType.STRING) + private UserRole role = UserRole.LEAD; + + @JsonIgnoreProperties("user") + @OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL) + private List userTeamRoles; + + private String email; + private Boolean isTeg; + + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "user_teams", + joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "teams_id", referencedColumnName = "id")) + @JsonIgnoreProperties("teamLeads") + private List teams; + + @Enumerated(EnumType.STRING) + private EntityStatus status = EntityStatus.ACTIVE; + + + public static Specification idSpec(int id) { + return (user, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(user.get("id"), id); + } + + public static Specification nameSpec(String name) { + return (user, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like(user.get("name"), "%" + name + "%"); + } + + public static Specification emailSpec(String email) { + return (user, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like(user.get("email"), "%" + email + "%"); + } + + public static Specification roleSpec(UserRole role) { + return (user, criteriaQuery, criteriaBuilder) -> criteriaBuilder.equal(user.get("role"), role); + } + + public static Specification teamSpec(String teamName) { + return (user, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.like( + user.join("teams", JoinType.LEFT).get("teamName"), "%" + teamName + "%"); + } + + public static Specification statusSpec(EntityStatus status) { + return (user, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.equal(user.get("status"), status); + } + + public static Specification isTegSpec(Boolean isTeg) { + return (user, criteriaQuery, criteriaBuilder) -> + criteriaBuilder.equal((user.get("isTeg")), isTeg); + } + + public static Specification distinct() { + return (root, query, cb) -> { + query.distinct(true); + return null; + }; + } + + public static Specification userSearchFieldSpec(String searchField) { + Specification userSpecification = Specification.where(null); + if (StringUtils.isNumeric(searchField)) { + int id = Integer.parseInt(searchField); + userSpecification = userSpecification.or(User.idSpec(id)); + } + try { + var entityStatus = EntityStatus.valueOf(searchField.toUpperCase()); + userSpecification = userSpecification.or(User.statusSpec(entityStatus)); + } catch (IllegalArgumentException e) { + // Not Entity Status + } + try { + var userRole = UserRole.valueOf(searchField.toUpperCase()); + userSpecification = userSpecification.or(User.roleSpec(userRole)); + } catch (IllegalArgumentException e) { + // Not User Role + } + userSpecification = + userSpecification + .or(User.nameSpec(searchField).or(User.emailSpec(searchField))) + .or(User.teamSpec(searchField)); + return userSpecification; + } +} diff --git a/src/main/java/com/openAi/security/entity/UserLog.java b/src/main/java/com/openAi/security/entity/UserLog.java new file mode 100644 index 0000000..5ad917c --- /dev/null +++ b/src/main/java/com/openAi/security/entity/UserLog.java @@ -0,0 +1,26 @@ +package com.openAi.security.entity; + +import lombok.*; +import lombok.experimental.Accessors; + +import jakarta.persistence.*; +import java.util.Date; + +@Entity +@Getter +@Setter +@Builder +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "user_log") +public class UserLog { + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + private Integer userId; + + private Date logInDate; +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/entity/UserTeamRoles.java b/src/main/java/com/openAi/security/entity/UserTeamRoles.java new file mode 100644 index 0000000..acbf950 --- /dev/null +++ b/src/main/java/com/openAi/security/entity/UserTeamRoles.java @@ -0,0 +1,36 @@ +package com.openAi.security.entity; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.*; +import lombok.experimental.Accessors; + +import jakarta.persistence.*; + +@Entity +@Getter +@Setter +@Accessors(chain = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "user_team_roles") +public class UserTeamRoles{ + + @Id + @Column(columnDefinition = "INT(11) UNSIGNED") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private int id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "user_id", referencedColumnName = "id") + private User user; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "role_id") + private Roles userRole; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "team_id") + @JsonIgnoreProperties(value = {"teamLeads"}, allowSetters = true) + private Team team; +} diff --git a/src/main/java/com/openAi/security/enums/AppConstant.java b/src/main/java/com/openAi/security/enums/AppConstant.java new file mode 100644 index 0000000..fc6193c --- /dev/null +++ b/src/main/java/com/openAi/security/enums/AppConstant.java @@ -0,0 +1,8 @@ +package com.openAi.security.enums; + +public class AppConstant { + private AppConstant(){} + public static final String DEFAULT_PAGE = "0"; + public static final String DEFAULT_PAGE_SIZE = "10"; + public static final String DEFAULT_PAGE_SIZE_PRODUCT_ROADMAP = "50"; +} diff --git a/src/main/java/com/openAi/security/enums/EntityStatus.java b/src/main/java/com/openAi/security/enums/EntityStatus.java new file mode 100644 index 0000000..7d8ae22 --- /dev/null +++ b/src/main/java/com/openAi/security/enums/EntityStatus.java @@ -0,0 +1,14 @@ +package com.openAi.security.enums; + +import lombok.Getter; + +public enum EntityStatus { + INACTIVE(0), + ACTIVE(1); + + @Getter private final int value; + + EntityStatus(int value) { + this.value = value; + } +} diff --git a/src/main/java/com/openAi/security/enums/TeamType.java b/src/main/java/com/openAi/security/enums/TeamType.java new file mode 100644 index 0000000..31acc17 --- /dev/null +++ b/src/main/java/com/openAi/security/enums/TeamType.java @@ -0,0 +1,27 @@ +package com.openAi.security.enums; + +import java.util.EnumMap; +import java.util.List; + +/** TeamType consisting multiple team types. */ +public enum TeamType { + BIG_TECH, + EARLY, + GROWTH, + PROFITABLE; + private static final EnumMap> CORRESPONDING_TYPES = + new EnumMap<>(TeamType.class); + + static { + CORRESPONDING_TYPES.put(BIG_TECH, List.of(BIG_TECH)); + CORRESPONDING_TYPES.put(EARLY, List.of(EARLY)); + CORRESPONDING_TYPES.put(GROWTH, List.of(GROWTH)); + CORRESPONDING_TYPES.put(PROFITABLE, List.of(PROFITABLE)); + } + + public static List getCorrespondingTypeList(TeamType teamType) { + return CORRESPONDING_TYPES.get(teamType); + } + + +} diff --git a/src/main/java/com/openAi/security/enums/UserRole.java b/src/main/java/com/openAi/security/enums/UserRole.java new file mode 100644 index 0000000..a24cb91 --- /dev/null +++ b/src/main/java/com/openAi/security/enums/UserRole.java @@ -0,0 +1,35 @@ +package com.openAi.security.enums; + +import lombok.Getter; + +public enum UserRole { + ADMIN(0), + MANAGER(1), + LEAD(2), + M4(3), + CSO(4), + RO(5), + TO(6), + I3(7), + I2(8), + I1(9), + WATCHER(10), + PEOPLE_GROUP(11), + M1(12), + M2(13), + I4(14), + A1(15), + A2(16), + A3(17), + M3(18), + CUSTOMER(19), + E1(20), + E2(21); + + @Getter + private final int value; + + UserRole(int value) { + this.value = value; + } +} diff --git a/src/main/java/com/openAi/security/exceptions/CustomRuntimeException.java b/src/main/java/com/openAi/security/exceptions/CustomRuntimeException.java new file mode 100644 index 0000000..69221dc --- /dev/null +++ b/src/main/java/com/openAi/security/exceptions/CustomRuntimeException.java @@ -0,0 +1,12 @@ +package com.openAi.security.exceptions; + +public class CustomRuntimeException extends RuntimeException { + public CustomRuntimeException(String message) { + super(message); + } + + public CustomRuntimeException(String message,Exception e) { + super(message+ "::" +e.getMessage()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/exceptions/EntityNotFoundException.java b/src/main/java/com/openAi/security/exceptions/EntityNotFoundException.java new file mode 100644 index 0000000..105d56a --- /dev/null +++ b/src/main/java/com/openAi/security/exceptions/EntityNotFoundException.java @@ -0,0 +1,51 @@ +package com.openAi.security.exceptions; + + +import static com.openAi.security.exceptions.ErrorCode.*; + +/** + * EntityNotFoundException. + */ +public class EntityNotFoundException extends RAGException { + + private EntityNotFoundException(String message, Integer code) { + super(message); + setCode(code); + } + + public static EntityNotFoundException user(String message) { + return new EntityNotFoundException(message, USER_NOT_FOUND); + } + + public static EntityNotFoundException team(String message) { + return new EntityNotFoundException(message, TEAM_NOT_FOUND); + } + + public static EntityNotFoundException cycleConfig(String message) { + return new EntityNotFoundException(message, CYCLE_CONFIG_NOT_FOUND); + } + + public static EntityNotFoundException survey(String message) { + return new EntityNotFoundException(message, SURVEY_NOT_FOUND); + } + + public static EntityNotFoundException customer(String message) { + return new EntityNotFoundException(message, CUSTOMER_NOT_FOUND); + } + + public static EntityNotFoundException section(String message) { + return new EntityNotFoundException(message, SECTION_NOT_FOUND); + } + + public static EntityNotFoundException employee(String message) { + return new EntityNotFoundException(message, EMPLOYEE_NOT_FOUND); + } + + public static EntityNotFoundException dataForEmployee(String message) { + return new EntityNotFoundException(message, NO_DATA_FOUND_FOR_EMPLOYEE); + } + + public static RuntimeException techDigest(String s) { + return new EntityNotFoundException(s,TECH_DIGEST_NOT_FOUND); + } +} diff --git a/src/main/java/com/openAi/security/exceptions/ErrorCode.java b/src/main/java/com/openAi/security/exceptions/ErrorCode.java new file mode 100644 index 0000000..96b852a --- /dev/null +++ b/src/main/java/com/openAi/security/exceptions/ErrorCode.java @@ -0,0 +1,65 @@ +package com.openAi.security.exceptions; + +public class ErrorCode { + + public static final Integer INTERNAL_SERVER_ERROR = 500; + public static final Integer NULL_POINTER_EXCEPTION = 500; + public static final Integer INVALID_ACCESS = 401; + + // Authentication and Authorization + public static final Integer INVALID_TOKEN = 1; + public static final Integer UNAUTHORISED_USER = 2; + + // User + public static final Integer USER_NOT_FOUND = 11; + + // Team + public static final Integer TEAM_NOT_FOUND = 21; + + // ConfigCycle + public static final Integer CYCLE_EXPIRED = 31; + public static final Integer CYCLE_CONFIG_NOT_FOUND = 32; + + // Survey + public static final Integer SURVEY_NOT_FOUND = 41; + public static final Integer NOT_ENOUGH_SURVEY = 42; + + // File + public static final Integer INVALID_FILE_EXTENSION = 51; + public static final Integer INVALID_FILE_FORMAT = 52; + + // Csat + public static final Integer NOT_ENOUGH_SURVEYS = 61; + public static final Integer CATEGORY_NOT_FOUND = 62; + public static final Integer QUESTION_NOT_FOUND = 63; + public static final Integer SUB_QUESTION_NOT_FOUND = 64; + public static final Integer SURVEY_ALREADY_EXISTS = 65; + public static final Integer PLACEHOLDER_NOT_FOUND = 66; + + // Customer + public static final Integer CUSTOMER_NOT_FOUND = 71; + + // Product Roadmap + public static final Integer EMPTY_STORY_NAME = 81; + public static final Integer INVALID_END_DATE = 82; + public static final Integer EMPTY_START_DATE = 83; + public static final Integer INCORRECT_DATA = 84; + public static final Integer NO_DATA_FOUND = 85; + + // Http Connection + public static final Integer HTTP_CONNECTION_FAILED = 91; + + // Section + public static final Integer SECTION_NOT_FOUND = 101; + + // TouchPoint + public static final Integer INVALID_FILE = 1101; + + // Teams + public static final Integer EMPLOYEE_NOT_FOUND = 1201; + public static final Integer NO_DATA_FOUND_FOR_EMPLOYEE = 1202; + + public static final Integer TECH_DIGEST_NOT_FOUND = 1301; + private ErrorCode() { + } +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/exceptions/InvalidAuthenticationException.java b/src/main/java/com/openAi/security/exceptions/InvalidAuthenticationException.java new file mode 100644 index 0000000..b8ab3ef --- /dev/null +++ b/src/main/java/com/openAi/security/exceptions/InvalidAuthenticationException.java @@ -0,0 +1,20 @@ +package com.openAi.security.exceptions; + +import static com.openAi.security.exceptions.ErrorCode.INVALID_TOKEN; +import static com.openAi.security.exceptions.ErrorCode.UNAUTHORISED_USER; + +public class InvalidAuthenticationException extends RAGException { + + private InvalidAuthenticationException(String message, Integer code) { + super(message); + setCode(code); + } + + public static InvalidAuthenticationException invalidToken(String message) { + return new InvalidAuthenticationException(message, INVALID_TOKEN); + } + + public static InvalidAuthenticationException unauthorisedUser(String message) { + return new InvalidAuthenticationException(message, UNAUTHORISED_USER); + } +} diff --git a/src/main/java/com/openAi/security/exceptions/RAGException.java b/src/main/java/com/openAi/security/exceptions/RAGException.java new file mode 100644 index 0000000..744ddc6 --- /dev/null +++ b/src/main/java/com/openAi/security/exceptions/RAGException.java @@ -0,0 +1,28 @@ +package com.openAi.security.exceptions; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + + + +@Setter +@Getter +public abstract class RAGException extends RuntimeException { + + private Integer code = ErrorCode.INTERNAL_SERVER_ERROR; + + protected RAGException(String message) { + super(message); + } + + protected RAGException(String message, Throwable cause) { + super(message, cause); + } + + protected RAGException(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/openAi/security/mapper/UserMapper.java b/src/main/java/com/openAi/security/mapper/UserMapper.java new file mode 100644 index 0000000..d7289b6 --- /dev/null +++ b/src/main/java/com/openAi/security/mapper/UserMapper.java @@ -0,0 +1,16 @@ +package com.openAi.security.mapper; + + +import com.openAi.security.entity.User; +import com.openAi.security.model.UserModel; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +/** Entity-Model mapper for User. */ +@Mapper +public interface UserMapper { + @Mapping(source = "userTeamRoles", target = "teamRoles") + UserModel entityToModel(User user); + + User modelToEntity(UserModel user); +} diff --git a/src/main/java/com/openAi/security/mapper/UserTeamRolesMapper.java b/src/main/java/com/openAi/security/mapper/UserTeamRolesMapper.java new file mode 100644 index 0000000..604f41b --- /dev/null +++ b/src/main/java/com/openAi/security/mapper/UserTeamRolesMapper.java @@ -0,0 +1,12 @@ +package com.openAi.security.mapper; + +import com.openAi.security.entity.UserTeamRoles; +import com.openAi.security.model.UserTeamRolesModel; +import org.mapstruct.Mapper; + +@Mapper +public interface UserTeamRolesMapper { + UserTeamRolesModel entityToModel(UserTeamRoles userTeamRoles); + + UserTeamRoles modelToEntity(UserTeamRolesModel userTeamRolesModel); +} diff --git a/src/main/java/com/openAi/security/model/JwtRequest.java b/src/main/java/com/openAi/security/model/JwtRequest.java new file mode 100644 index 0000000..3d277be --- /dev/null +++ b/src/main/java/com/openAi/security/model/JwtRequest.java @@ -0,0 +1,10 @@ +package com.openAi.security.model; + +import lombok.Data; + +@Data +public class JwtRequest { + + private String token; + private String email; +} \ No newline at end of file diff --git a/src/main/java/com/openAi/security/model/MonthValue.java b/src/main/java/com/openAi/security/model/MonthValue.java new file mode 100644 index 0000000..aae7072 --- /dev/null +++ b/src/main/java/com/openAi/security/model/MonthValue.java @@ -0,0 +1,10 @@ +package com.openAi.security.model; + +import lombok.Getter; + +public interface MonthValue { + String getMonth(); + String getYear(); + String getValue(); + +} diff --git a/src/main/java/com/openAi/security/model/TeamModel.java b/src/main/java/com/openAi/security/model/TeamModel.java new file mode 100644 index 0000000..e3c50da --- /dev/null +++ b/src/main/java/com/openAi/security/model/TeamModel.java @@ -0,0 +1,43 @@ +package com.openAi.security.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.entity.Customer; +import com.openAi.security.entity.User; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.TeamType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; +import java.util.List; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class TeamModel { + + private Integer id; + private String teamName; + private TeamType teamType; + private LocalDate activeSince; + private LocalDate endDate; + private String teamShortName; + private String teamJiraName; + private Boolean isTeg; + private Boolean excludeCompliance; + private Boolean complianceByStory; + + @JsonIgnoreProperties("teams") + private List teamLeads; + + @JsonIgnoreProperties("team") + private List userRoles; + + private EntityStatus status; + + @JsonIgnoreProperties(value = {"epics", "customerUserRoles"}, allowSetters = true) + private Customer customer; +} diff --git a/src/main/java/com/openAi/security/model/UserListViewResponse.java b/src/main/java/com/openAi/security/model/UserListViewResponse.java new file mode 100644 index 0000000..e68c288 --- /dev/null +++ b/src/main/java/com/openAi/security/model/UserListViewResponse.java @@ -0,0 +1,23 @@ +package com.openAi.security.model; + +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +import java.util.ArrayList; +import java.util.List; + +/** UserListViewResponse. */ +@Getter +@Setter +@Accessors(chain = true) +public class UserListViewResponse { + + private List userListViews = new ArrayList<>(); + private Long totalRecords; + private Integer totalPages; + private boolean hasNext = false; + private boolean hasPrevious = false; + private Integer page; + private Integer size; +} diff --git a/src/main/java/com/openAi/security/model/UserModel.java b/src/main/java/com/openAi/security/model/UserModel.java new file mode 100644 index 0000000..43542bb --- /dev/null +++ b/src/main/java/com/openAi/security/model/UserModel.java @@ -0,0 +1,32 @@ +package com.openAi.security.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.entity.Customer; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.UserRole; +import lombok.*; + +import java.util.List; + +/** + * User Model. + */ +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class UserModel { + + private Integer id; + private String name; + private UserRole role; + private String email; + @JsonIgnoreProperties(value = {"teamLeads", "userTeamRoles"}, allowSetters = true) + private List teams; + private List teamRoles; + private boolean isCustomerRole; + private EntityStatus status; + private List customers; + private boolean isTeg; +} diff --git a/src/main/java/com/openAi/security/model/UserRequest.java b/src/main/java/com/openAi/security/model/UserRequest.java new file mode 100644 index 0000000..e1433ef --- /dev/null +++ b/src/main/java/com/openAi/security/model/UserRequest.java @@ -0,0 +1,10 @@ +package com.openAi.security.model; + +import lombok.Data; + +@Data +public class UserRequest { + private String user; + private String password; + private String oldPassword; +} diff --git a/src/main/java/com/openAi/security/model/UserRole.java b/src/main/java/com/openAi/security/model/UserRole.java new file mode 100644 index 0000000..38fac0b --- /dev/null +++ b/src/main/java/com/openAi/security/model/UserRole.java @@ -0,0 +1,35 @@ +package com.openAi.security.model; + +import lombok.Getter; + +public enum UserRole { + ADMIN(0), + MANAGER(1), + LEAD(2), + M4(3), + CSO(4), + RO(5), + TO(6), + I3(7), + I2(8), + I1(9), + WATCHER(10), + PEOPLE_GROUP(11), + M1(12), + M2(13), + I4(14), + A1(15), + A2(16), + A3(17), + M3(18), + CUSTOMER(19), + E1(20), + E2(21); + + @Getter + private final int value; + + UserRole(int value) { + this.value = value; + } +} diff --git a/src/main/java/com/openAi/security/model/UserTeamRolesModel.java b/src/main/java/com/openAi/security/model/UserTeamRolesModel.java new file mode 100644 index 0000000..dcfea87 --- /dev/null +++ b/src/main/java/com/openAi/security/model/UserTeamRolesModel.java @@ -0,0 +1,23 @@ +package com.openAi.security.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.openAi.security.entity.Roles; +import com.openAi.security.entity.Team; +import com.openAi.security.entity.User; +import lombok.*; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UserTeamRolesModel { + private int id; + private User user; + private Roles userRole; + + @JsonIgnoreProperties( + value = {"teamLeads"}, + allowSetters = true) + private Team team; +} diff --git a/src/main/java/com/openAi/security/model/WebClientResponse.java b/src/main/java/com/openAi/security/model/WebClientResponse.java new file mode 100644 index 0000000..15e2316 --- /dev/null +++ b/src/main/java/com/openAi/security/model/WebClientResponse.java @@ -0,0 +1,23 @@ +package com.openAi.security.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class WebClientResponse { + private String displayName; + private String givenName; + private String mail; + private String mobilePhone; + private String id; + private String userPrincipalName; + private String type = "Bearer"; + private String token; + private Boolean isResetRequired; + private String reason; +} diff --git a/src/main/java/com/openAi/security/repository/AllowedDomainRepository.java b/src/main/java/com/openAi/security/repository/AllowedDomainRepository.java new file mode 100644 index 0000000..1c7b2e6 --- /dev/null +++ b/src/main/java/com/openAi/security/repository/AllowedDomainRepository.java @@ -0,0 +1,17 @@ +package com.openAi.security.repository; + +import com.drew.lang.annotations.NotNull; +import com.openAi.security.entity.AllowedDomain; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface AllowedDomainRepository extends JpaRepository { + + @NotNull + List findAll(); + @NotNull List findAllByDomainName(String domainName); + List findByTeamIdsContains(String teamId); +} diff --git a/src/main/java/com/openAi/security/repository/AttendanceRepository.java b/src/main/java/com/openAi/security/repository/AttendanceRepository.java new file mode 100644 index 0000000..5fc7d09 --- /dev/null +++ b/src/main/java/com/openAi/security/repository/AttendanceRepository.java @@ -0,0 +1,394 @@ +package com.openAi.security.repository; + + +import com.openAi.security.entity.Attendance; +import com.openAi.security.model.MonthValue; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +public interface AttendanceRepository extends JpaRepository { + + @Query(value = """ + select distinct concat(a.year,"-",a.month) from playbook.attendance a + order by a.year desc,a.month desc limit 1 + """, nativeQuery = true) + String getLatestMonthAndYear(); + + @Query(value = """ + SELECT * FROM attendance where + month in :month AND year=:year AND + (project_name like %:projectName% or project_name = :customerName) + AND employee_grade != 'Contract' """, nativeQuery = true) + List findAllByProjectName(Integer year, List month, String projectName, String customerName); + + @Query(value = """ + SELECT * FROM attendance a where + STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <=:endDate + and (a.project_name like %:projectName% or a.project_name = :customerName) + AND a.employee_grade != 'Contract' """, nativeQuery = true) + List findAllByProjectNameAndDate(LocalDate startDate,LocalDate endDate, String projectName, String customerName); + + + @Query(value = """ + select distinct a.* FROM playbook.attendance a + where a.month = :month and a.year = :year + and a.employee_function not in ('IT','Administration','Account','Accounts','Account Management') + AND a.email_id NOT IN (SELECT user_email_id FROM playbook.kra_user_survey WHERE kra_cycle_id= :configId) + """, nativeQuery = true) + List findAllAttendanceSurvey(Integer year, Integer month,Integer configId); + @Query(value = """ + SELECT * FROM attendance where + month in :month AND year=:year + AND employee_grade != 'Contract' """, nativeQuery = true) + List findAllByYearAndMonth(Integer year, List month); + + + @Query(value = """ + SELECT * FROM attendance where + (project_name like %:projectName% or project_name = :customerName) + AND employee_grade != 'Contract' """, nativeQuery = true) + List findAllByProjectName(String projectName, String customerName); + + + @Query(value = """ + SELECT * FROM attendance where + month in :month AND year=:year AND + (employee_function like %:function%) + AND employee_grade != 'Contract' """, nativeQuery = true) + List findAllByEmployeeFunction(Integer year, List month, String function); + + @Query(value = """ + select a2.* FROM attendance a1 join attendance a2 + on a1.employee_name = a2.reporting_manager and a1.month = a2.month and a1.year = a2.year + join (select * from attendance where employee_grade = 'M2' and employee_function like %:function% and month in (:month) and year=:year) as a3 + on a1.reporting_manager = a3.employee_name and a1.month = a3.month and a1.year = a3.year + where a1.month in (:month) AND a1.year=:year + union + select a1.* FROM attendance a1 + join (select * from attendance where employee_grade = 'M2' and employee_function like %:function% and month in (:month) and year=:year) a2 + on a1.reporting_manager = a2.employee_name and a1.month = a2.month and a1.year = a2.year + where a1.month in (:month) AND a1.year=:year + """, nativeQuery = true) + List findAllByReportingManager(Integer year, List month, String function); + + + @Query(value= """ + select( + (select sum(story_points) from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <=:endDate and at.team_id in :teamId) + / + (select sum(story_points) from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <=:endDate and at.team_id in :teamId and a.employee_function + in (select a.employee_function from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id=:email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <=:endDate )))*100 as Result + """,nativeQuery = true) + Double getOwnerShipByEffort(List teamId, String email, LocalDate startDate, LocalDate endDate); + + + @Query(value = """ + select sum(present_days) from attendance a + where STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <=:endDate\s + and a.email_id =:email + """,nativeQuery = true) + Double getDevelopmentDays(String email, LocalDate startDate, LocalDate endDate); + + @Query(value= """ + select sum(logged_hours)/avg(working_hours)*100 from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')<=:endDate and at.team_id in (:teamId) + group by a.month,a.year + """,nativeQuery = true) + List getProductivity(List teamId,String email, LocalDate startDate,LocalDate endDate); + + + @Query(value= """ + select sum(logged_hours)/(8) from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')<=:endDate and at.team_id in (:teamId) + group by a.month,a.year + """,nativeQuery = true) + List getProductivityInDays(List teamId,String email, LocalDate startDate,LocalDate endDate); + + @Query(value= """ + select sum(logged_hours)/avg(working_hours)*100 as value,a.month,a.year from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')<=:endDate and at.team_id in (:teamId) + group by a.month,a.year + """,nativeQuery = true) + List getProductivityValues(List teamId, String email, LocalDate startDate, LocalDate endDate); + + + @Query(value= """ + select sum(story_points) * 22 /sum(a.present_days) from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')<=:endDate and at.team_id in (:teamId) + group by a.month,a.year + """,nativeQuery = true) + List getStoryPoints(List teamId,String email, LocalDate startDate,LocalDate endDate); + + + @Query(value= """ + select sum(story_points) from playbook.attendance_team at join playbook.attendance a + on at.attendance_id = a.id and a.email_id= :email + and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')>=:startDate and STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d')<=:endDate and at.team_id in (:teamId) + group by a.month,a.year + """,nativeQuery = true) + List getTotalStoryPoints(List teamId,String email, LocalDate startDate,LocalDate endDate); + + @Query(value= """ + select (sum(COALESCE(bug_fixes_story_points, 0) + COALESCE(enhancements_story_points, 0) + COALESCE(new_features_story_points, 0))/(sum(at.working_hours)/8))*22 sp + from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + and a.month = :month and a.year = :year and at.team_id = :teamId + """,nativeQuery = true) + Double getVelocityByTeamAndMonthAndYear(Integer teamId, Integer month, Integer year); + + @Query(value = """ + SELECT * FROM attendance where + month in :month AND year=:year AND + (employee_grade like 'A%') + AND employee_grade != 'Contract' """, nativeQuery = true) + List findAllByEmployeeGrade(Integer year, List month); + + @Query(value = "SELECT at FROM Attendance at where at.month=:month AND at.year=:year AND at.employeeName IN :employeeNames") + List getByMonthAndYearAndEmployeeNameIn(Integer month, Integer year, List employeeNames); + + @Query(value = "select * from attendance where email_id= :emailId and ((month >= :startMonth and year= :startYear) or (month <= :endMonth and year= :endYear)) order by year,month desc", nativeQuery = true) + List findByEmployeeEmailAndYearMonth(String emailId, Integer startMonth, Integer startYear, Integer endMonth, Integer endYear); + + @Query(value = "select * from attendance where email_id= :emailId and month >= :startMonth and month <= :endMonth and year= :year order by year,month desc", nativeQuery = true) + List findByEmployeeEmailAndYearMonth(String emailId, Integer startMonth, Integer endMonth, Integer year); + + List findByMonthAndYearAndFirstNameAndLastName(Integer month, Integer year, String firstName, String lastName); + + @Query(value = """ + SELECT * FROM attendance where + (project_name like %:projectName% or project_name = :customerName) + AND first_name = :firstName + AND last_name = :lastName + AND employee_grade != 'Contract' + """, nativeQuery = true) + List findByProjectNameAndFirstNameAndLastName(String projectName, String customerName, String firstName, String lastName); + + List findByMonthAndYearAndLastName(Integer month, Integer year, String lastName); + + List findByMonthAndYearAndLastNameAndProjectName(Integer month, Integer year, String lastName,String projectName); + + List findByMonthAndYearAndFirstNameAndProjectName(Integer month, Integer year, String firstName,String projectName); + + + List findByEmailIdOrderByYearDescMonthDesc(String email); + + @Query(value = "select * from attendance where reporting_manager= :name and month = :month and year= :year", nativeQuery = true) + List findByReportingManagerOrderByYearDescMonthDesc(String name,Integer year,Integer month); + + @Query(value = "select * from attendance where email_id= :email and month = :month and year= :year Limit 1", nativeQuery = true) + Attendance findByEmailAndYearAndMonth(String email, Integer year, Integer month); + + @Query(value = "select * from attendance where month = :month and year= :year Limit 5", nativeQuery = true) + List findByYearAndMonth(Integer year, Integer month); + + @Modifying + @Transactional + @Query(value = "delete FROM attendance where month = :month and year = :year", nativeQuery = true) + void deleteByMonthAndYear(Integer month, Integer year); + + @Modifying + @Transactional + @Query(value = "delete FROM attendance_team where attendance_id in (select id from attendance where month = :month and year = :year)", nativeQuery = true) + void deleteByMonthAndYearAttendanceTeam(Integer month, Integer year); + + @Query(value = "SELECT DISTINCT a.* FROM attendance AS a JOIN customers AS c ON a.project_name LIKE CONCAT('%', SUBSTRING(c.project_name, 1, LENGTH(a.project_name)), '%') WHERE c.id = :customerId AND ((a.year = :startYear AND a.month >= :startMonth) AND (a.year = :endYear AND a.month <= :endMonth));", nativeQuery = true) + List findByCustomerIdAndDateRanges(Long customerId, int startYear, int startMonth, int endYear, + int endMonth); + + @Query(value = "SELECT DISTINCT a.* FROM attendance AS a WHERE a.id IN( SELECT attendance_id FROM attendance_team WHERE team_id in :teamId ) AND ((month >= :startMonth and year= :startYear) or (month <= :endMonth and year= :endYear));", nativeQuery = true) + List findByTeamIdAndDateRanges(List teamId, int startYear, int startMonth, int endYear, int endMonth); + + @Query(value = "SELECT DISTINCT a.* FROM attendance AS a WHERE a.id IN( SELECT attendance_id FROM attendance_team WHERE team_id in :teamId ) AND (month >= :startMonth and year= :startYear and month <= :endMonth);", nativeQuery = true) + List findByTeamIdAndDateRanges(List teamId, int startYear, int startMonth, int endMonth); + + @Query(value = "SELECT DISTINCT a.employee_code,a.employee_name, a.employee_grade, a.employee_function ,at.team_id FROM attendance a join attendance_team at on a.id = at.attendance_id join team t on at.team_id = t.id WHERE ((month >= :startMonth and year= :startYear) or (month <= :endMonth and year= :endYear));", nativeQuery = true) + List> findByDateRanges(int startYear, int startMonth, int endYear, int endMonth); + + @Query(value = "SELECT DISTINCT a.employee_code,a.employee_name, a.employee_grade, a.employee_function ,at.team_id FROM attendance a join attendance_team at on a.id = at.attendance_id join team t on at.team_id = t.id WHERE (month >= :startMonth and year= :startYear and month <= :endMonth);", nativeQuery = true) + List> findByDateRanges(int startYear, int startMonth, int endMonth); + + @Query(value = "SELECT COALESCE(SUM(new_features),0) FROM attendance_team at JOIN attendance a ON at.attendance_id = a.id WHERE at.team_id = :teamId AND ((a.year = :year AND a.month = :month))", nativeQuery = true) + Integer findNewsFeaturesCountForDate(Long teamId, int year, int month); + + @Query(value = "SELECT COALESCE(SUM(enhancements),0) FROM attendance_team at JOIN attendance a ON at.attendance_id = a.id WHERE at.team_id = :teamId and ((a.year = :year AND a.month = :month))", nativeQuery = true) + Integer findEnhancementCountForDate(Long teamId, int year, int month); + + @Query(value = "SELECT COALESCE(SUM(bug_fixes),0) FROM attendance_team at JOIN attendance a ON at.attendance_id = a.id WHERE at.team_id = :teamId AND ((a.year = :year AND a.month = :month))", nativeQuery = true) + Integer findBugsFixesCountForDate(Long teamId, int year, int month); + + @Query(value = """ + select + (select sum(bug_fixes+enhancements+new_features) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year)/ + ((select count(distinct(a.month)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year)* + (select count(distinct(at.team_id)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year) + ) as talenticaAvg + """, nativeQuery = true) + Double findAverageTrendCount(int year, int startMonth, int endMonth); + + @Query(value = """ + select + (select avg(story_points) from (select sum(bug_fixes_story_points + enhancements_story_points + new_features_story_points) as story_points from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear))) as storyPoints)/ + ((select count(distinct(a.month)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear)) + )*(select count(distinct(at.team_id)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear)))) as teamAvg + """, nativeQuery = true) + Double findAverageTrendCount(int startYear, int endYear, int startMonth, int endMonth); + + @Query(value = """ + select + (select avg(story_points) from (select sum(bug_fixes_story_points + enhancements_story_points + new_features_story_points) as story_points from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year and at.team_id in :teamIds + ) as storyPoints )/ + ((select count(distinct(a.month)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year and at.team_id in :teamIds + )*(select count(distinct(a.email_id)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where a.month >= :startMonth and a.month < :endMonth and year = :year and at.team_id in :teamIds)) as teamAvg + """, nativeQuery = true) + Double findAverageTrendCountByTeam(int year, int startMonth, int endMonth, List teamIds); + + @Query(value = """ + select + (select sum(bug_fixes_story_points+enhancements_story_points+new_features_story_points) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear)) and at.team_id in :teamIds + )/ + ((select count(distinct(a.month)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear)) and at.team_id in :teamIds + )*(select count(distinct(a.email_id)) from playbook.attendance_team at + join playbook.attendance a on at.attendance_id = a.id + where ((a.month >= :startMonth and year= :startYear) or (a.month < :endMonth and year = :endYear)) and at.team_id in :teamIds)) as teamAvg + """, nativeQuery = true) + Double findAverageTrendCountByTeam(int startYear, int endYear, int startMonth, int endMonth, List teamIds); + + @Query(value = """ + SELECT DISTINCT a.* FROM attendance AS a + where a.project_name = :projectName and month >= :startMonth and month<= :endMonth and year = :year + and employee_name in :employee + """, nativeQuery = true) + List findByProjectNameAndDateRangesAndEmployee(String projectName, Integer startMonth, Integer endMonth, Integer year, List employee); + + @Query(value = """ + SELECT DISTINCT a.* FROM attendance AS a + where month >= :startMonth and month<= :endMonth and year = :year + and email_id in :email and (employee_grade in ('M1','M2','M3') or employee_grade like 'A%') + """, nativeQuery = true) + List findByProjectNameAndDateRangesAndEmail(Integer startMonth, Integer endMonth, Integer year, List email); + + List findByMonthAndYearAndEmailIdIn(Integer month, Integer year, List emailIds); + + @Query(value = """ + SELECT a.year, a.month, COALESCE(SUM(new_features_story_points), 0) AS new_features, + COALESCE(SUM(enhancements_story_points), 0) AS enhancements, + COALESCE(SUM(bug_fixes_story_points), 0) AS bug_fixes, + Avg(new_features_story_points+enhancements_story_points+bug_fixes_story_points) as normalizedCount + FROM attendance_team at JOIN attendance a + ON at.attendance_id = a.id WHERE at.team_id in (:teamId) + AND STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') >= STR_TO_DATE(CONCAT(:startYear,'-',:startMonth,'-',1), '%Y-%m-%d')\s + AND STR_TO_DATE(CONCAT(a.year,'-',a.month,'-',1), '%Y-%m-%d') <= STR_TO_DATE(CONCAT(:endYear,'-',:endMonth,'-',1), '%Y-%m-%d') + GROUP BY a.year, a.month + """ + , nativeQuery = true) + List findCountsForDateRange(List teamId, int startYear, int startMonth, int endYear, int endMonth); + + + @Query(value = """ + SELECT a.year, a.month, COALESCE(SUM(new_features_story_points), 0) AS new_features, + COALESCE(SUM(enhancements_story_points), 0) AS enhancements, + COALESCE(SUM(bug_fixes_story_points), 0) AS bug_fixes, + Avg(new_features_story_points+enhancements_story_points+bug_fixes_story_points) as normalizedCount + FROM attendance_team at JOIN attendance a + ON at.attendance_id = a.id WHERE a.employee_function like %:customerName% + AND (((:startYear = :endYear) AND ((a.month >= :startMonth AND a.month <= :endMonth) + AND a.year = :startYear)) OR ((:startYear != :endYear) AND ((a.year >= :startYear AND a.month >= :startMonth) OR (a.year <= :endYear AND a.month <= :endMonth)))) GROUP BY a.year, a.month;""" + , nativeQuery = true) + List findCountsForDateRangeTegCustomer(String customerName, int startYear, int startMonth, int endYear, int endMonth); + @Query(value = """ + SELECT a.year, a.month, COALESCE(SUM(new_features_story_points), 0) AS new_features, + COALESCE(SUM(enhancements_story_points), 0) AS enhancements, + COALESCE(SUM(bug_fixes_story_points), 0) AS bug_fixes FROM attendance_team at\s + JOIN + (select a2.* FROM attendance a1 join attendance a2 + on a1.employee_name = a2.reporting_manager + and a1.reporting_manager in (select distinct employee_name from attendance where employee_grade = 'M2' and employee_function like %:customerName%) + where STR_TO_DATE(CONCAT('01-', a1.month,'-',a1.year), '%d-%m-%Y') >= STR_TO_DATE(CONCAT('01-', :startMonth,'-',:startYear), '%d-%m-%Y') + AND STR_TO_DATE(CONCAT('01-', a1.month,'-',a1.year), '%d-%m-%Y') <= STR_TO_DATE(CONCAT('01-', :endMonth,'-',:endYear), '%d-%m-%Y') + AND STR_TO_DATE(CONCAT('01-', a2.month,'-',a2.year), '%d-%m-%Y') >= STR_TO_DATE(CONCAT('01-', :startMonth,'-',:startYear), '%d-%m-%Y') + AND STR_TO_DATE(CONCAT('01-', a2.month,'-',a2.year), '%d-%m-%Y') <= STR_TO_DATE(CONCAT('01-', :endMonth,'-',:endYear), '%d-%m-%Y') \s + union + select a1.* FROM attendance a1 + where STR_TO_DATE(CONCAT('01-', a1.month,'-',a1.year), '%d-%m-%Y') >= STR_TO_DATE(CONCAT('01-', :startMonth,'-',:startYear), '%d-%m-%Y') + AND STR_TO_DATE(CONCAT('01-', a1.month,'-',a1.year), '%d-%m-%Y') <= STR_TO_DATE(CONCAT('01-', :endMonth,'-',:endYear), '%d-%m-%Y') + AND a1.reporting_manager in (select distinct employee_name from attendance where employee_grade = 'M2' and employee_function like %:customerName%))as a \s + ON at.attendance_id = a.id + GROUP BY a.year, a.month ; + """ + , nativeQuery = true) + List findCountsForDateRangeTegOpsCustomer(String customerName, int startYear, int startMonth, int endYear, int endMonth); + + @Query(value = """ + SELECT a.year, a.month, COALESCE(SUM(new_features_story_points), 0) AS new_features, + COALESCE(SUM(enhancements_story_points), 0) AS enhancements, + COALESCE(SUM(bug_fixes_story_points), 0) AS bug_fixes, + Avg(new_features_story_points+enhancements_story_points+bug_fixes_story_points) as normalizedCount + FROM attendance_team at JOIN attendance a + ON at.attendance_id = a.id WHERE a.employee_grade like 'A%' + AND (((:startYear = :endYear) AND ((a.month >= :startMonth AND a.month <= :endMonth) + AND a.year = :startYear)) OR ((:startYear != :endYear) AND ((a.year >= :startYear AND a.month >= :startMonth) OR (a.year <= :endYear AND a.month <= :endMonth)))) GROUP BY a.year, a.month;""" + , nativeQuery = true) + List findCountsForDateRangeTegCustomerArchitects(int startYear, int startMonth, int endYear, int endMonth); + + @Query(value = "select a.year, a.month, at.team_id from attendance a join attendance_team at on at.attendance_id = a.id", nativeQuery = true) + List> getRecentRecord(); + + + @Query(value = """ + SELECT SUM(bug_fixes_story_points+enhancements_story_points+new_features_story_points) + FROM attendance_team atm JOIN attendance a + ON atm.attendance_id = a.id + WHERE atm.team_id in :teamId AND month = :month AND year = :year + GROUP BY a.month, a.year + """ + , nativeQuery = true) + Double getAvgStoryPoints(List teamId, int month, int year); + + @Query(value = """ + SELECT distinct t.team_name + FROM attendance_team atm JOIN attendance a + ON atm.attendance_id = a.id + JOIN team t on atm.team_id = t.id + WHERE a.email_id = :email and (year, month) >= (:startYear, :startMonth) + and (year, month) <= (:endYear, :endMonth) + """ + , nativeQuery = true) + List getTeamHistory(String email, int startMonth, int startYear, int endMonth, int endYear); +} diff --git a/src/main/java/com/openAi/security/repository/CustomerCredentialRepository.java b/src/main/java/com/openAi/security/repository/CustomerCredentialRepository.java new file mode 100644 index 0000000..d58dfe1 --- /dev/null +++ b/src/main/java/com/openAi/security/repository/CustomerCredentialRepository.java @@ -0,0 +1,15 @@ +package com.openAi.security.repository; + +import com.openAi.security.entity.CustomerCredentials; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface CustomerCredentialRepository extends JpaRepository, JpaSpecificationExecutor { + List findAllByUserNameOrUserEmail(String userName,String userEmail); + List findAllByUserEmail(String userEmail); + +} diff --git a/src/main/java/com/openAi/security/repository/RolesRepository.java b/src/main/java/com/openAi/security/repository/RolesRepository.java new file mode 100644 index 0000000..1bbed2e --- /dev/null +++ b/src/main/java/com/openAi/security/repository/RolesRepository.java @@ -0,0 +1,9 @@ +package com.openAi.security.repository; + +import com.openAi.security.entity.Roles; +import com.openAi.security.enums.UserRole; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RolesRepository extends JpaRepository { + Roles findByRole(UserRole userRole); +} diff --git a/src/main/java/com/openAi/security/repository/UserLogRepository.java b/src/main/java/com/openAi/security/repository/UserLogRepository.java new file mode 100644 index 0000000..371408b --- /dev/null +++ b/src/main/java/com/openAi/security/repository/UserLogRepository.java @@ -0,0 +1,11 @@ +package com.openAi.security.repository; + +import com.openAi.security.entity.UserLog; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Date; +import java.util.List; + +public interface UserLogRepository extends JpaRepository { + List findAllByUserIdAndLogInDate(Integer userId, Date logInDate); +} diff --git a/src/main/java/com/openAi/security/repository/UserRepository.java b/src/main/java/com/openAi/security/repository/UserRepository.java new file mode 100644 index 0000000..de04346 --- /dev/null +++ b/src/main/java/com/openAi/security/repository/UserRepository.java @@ -0,0 +1,36 @@ +package com.openAi.security.repository; + +import com.openAi.security.entity.User; +import com.openAi.security.enums.EntityStatus; +import com.openAi.security.enums.UserRole; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +/** User Repository. */ +@Repository +public interface UserRepository + extends JpaRepository, JpaSpecificationExecutor { + + Optional findByEmailIgnoreCaseAndStatus(String email, EntityStatus status); + + Optional findByEmailIgnoreCase(String email); + + Page findByStatusInAndRoleIn( + List statusList, + List role, + Specification specification, + Pageable paging); + + Optional findUserByEmail(String email); + + Optional findByNameIgnoreCase(String name); + + List findByStatusAndRoleNotIn(EntityStatus status, List roles); +} diff --git a/src/main/java/com/openAi/security/repository/UserTeamRoleRepository.java b/src/main/java/com/openAi/security/repository/UserTeamRoleRepository.java new file mode 100644 index 0000000..b9bceca --- /dev/null +++ b/src/main/java/com/openAi/security/repository/UserTeamRoleRepository.java @@ -0,0 +1,31 @@ +package com.openAi.security.repository; + +import com.openAi.security.entity.Roles; +import com.openAi.security.entity.UserTeamRoles; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; + + +import java.util.List; + +@Repository +public interface UserTeamRoleRepository extends JpaRepository { + List findByUserRole(Roles userRoles); + + UserTeamRoles findByUserIdAndTeamId(Integer user, Integer team); + + List findAllByTeam_Id(Integer team); + + @Modifying + @Transactional + @Query(value = "delete from playbook.user_team_roles where team_id = :team", nativeQuery = true) + void deleteByTeam_Id(Integer team); + + @Modifying + @Transactional + @Query(value = "delete from playbook.user_team_roles where user_id = :user", nativeQuery = true) + void deleteByUser_Id(Integer user); +} diff --git a/src/main/java/com/openAi/security/service/UserService.java b/src/main/java/com/openAi/security/service/UserService.java new file mode 100644 index 0000000..238caf5 --- /dev/null +++ b/src/main/java/com/openAi/security/service/UserService.java @@ -0,0 +1,30 @@ +package com.openAi.security.service; + +import com.openAi.security.entity.Roles; +import com.openAi.security.entity.User; +import com.openAi.security.model.UserListViewResponse; +import com.openAi.security.model.UserModel; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; +import java.util.Map; + +/** + * UserService. + */ +public interface UserService { + + + UserModel findUserByEmailOrAttendance(String email); + + UserModel findUserByEmail(String email); + + void saveUserLog(String userEmail); + + UserListViewResponse findAllUsers(Specification userSpecification, Pageable paging); + + List getRoles(); + +} diff --git a/src/main/java/com/openAi/security/service/UserServiceImpl.java b/src/main/java/com/openAi/security/service/UserServiceImpl.java new file mode 100644 index 0000000..4d0afa6 --- /dev/null +++ b/src/main/java/com/openAi/security/service/UserServiceImpl.java @@ -0,0 +1,176 @@ +package com.openAi.security.service; + +import com.openAi.security.entity.*; +import com.openAi.security.enums.UserRole; +import com.openAi.security.exceptions.EntityNotFoundException; +import com.openAi.security.mapper.UserMapper; +import com.openAi.security.mapper.UserTeamRolesMapper; +import com.openAi.security.model.UserListViewResponse; +import com.openAi.security.model.UserModel; +import com.openAi.security.repository.*; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.mapstruct.factory.Mappers; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.ZoneId; +import java.util.*; + +import static com.openAi.security.enums.EntityStatus.ACTIVE; + +/** + * UserService Implementation. + */ +@Slf4j +@Service +public class UserServiceImpl implements UserService { + + private final UserMapper userMapper = Mappers.getMapper(UserMapper.class); + private final String LOGIN = "login"; + + @Autowired + UserTeamRoleRepository userTeamRoleRepository; + @Autowired + AttendanceRepository attendanceRepository; + @Autowired + CustomerCredentialRepository customerCredentialRepository; + @Autowired + PasswordEncoder passwordEncoder; + @Autowired + UserRepository userRepository; + @Value("${customer-login.site-url}") + private String siteURL; + + @Value("${customer-login.login-endpoint}") + private String loginEndPoint; + @Autowired + private UserLogRepository userLogRepository; + + private final UserTeamRolesMapper userTeamRolesMapper = Mappers.getMapper(UserTeamRolesMapper.class); + + @Override + public UserModel findUserByEmailOrAttendance(String email) { + UserModel userModel = null; + try { + userModel = findUserByEmail(email); + } catch (Exception e) { + List attendanceList = attendanceRepository.findByEmailIdOrderByYearDescMonthDesc(email); + if (attendanceList == null || attendanceList.isEmpty()) { + throw new jakarta.persistence.EntityNotFoundException("User not found with email " + email); + } + UserRole role = UserRole.valueOf("People Group".equals(attendanceList.get(0).getEmployeeFunction()) + ? "PEOPLE_GROUP" : attendanceList.get(0).getEmployeeGrade()); + userModel = new UserModel( + null, attendanceList.get(0).getEmployeeName(), role, email, new ArrayList<>(), new ArrayList<>(), false, ACTIVE, new ArrayList<>(), false + ); + } + return userModel; + } + + @Override + public UserModel findUserByEmail(String email) { + log.debug("Finding user with email: {}", email); + User user = + userRepository + .findByEmailIgnoreCaseAndStatus(email, ACTIVE) + .orElseThrow(() -> EntityNotFoundException.user("User not found with email " + email)); + UserModel userModel = userMapper.entityToModel(user); + userModel.setCustomers(user.getTeams().stream().map(Team::getCustomer).toList()); + return userModel; + } + + @Override + public void saveUserLog(String email) { + + try { + Optional optionalUser = userRepository.findUserByEmail(email); + if (optionalUser.isPresent()) { + User user = optionalUser.get(); + Date date = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant()); + List logs = userLogRepository.findAllByUserIdAndLogInDate(user.getId(), date); + var userLogBuilder = UserLog.builder(); + if (!logs.isEmpty()) { + userLogBuilder.id(logs.get(0).getId()); + } + + UserLog log = userLogBuilder + .userId(user.getId()) + .logInDate(date) + .build(); + userLogRepository.save(log); + } + } catch (Exception e) { + log.error(e.getMessage()); + } + + + } + + @Override + public UserListViewResponse findAllUsers(Specification userSpecification, Pageable paging) { + Page pagedResult = userRepository.findAll(userSpecification, paging); + + UserListViewResponse userListViewResponse; + if (pagedResult.hasContent()) { + userListViewResponse = populateUserListViewResponse(pagedResult); + } else { + userListViewResponse = new UserListViewResponse(); + userListViewResponse.setTotalPages(pagedResult.getTotalPages()); + userListViewResponse.setTotalRecords(pagedResult.getTotalElements()); + userListViewResponse.setPage(pagedResult.getNumber()); + userListViewResponse.setSize(pagedResult.getSize()); + userListViewResponse.setHasNext(pagedResult.hasNext()); + userListViewResponse.setHasPrevious(pagedResult.hasPrevious()); + log.warn("No User(s) found"); + } + return userListViewResponse; + } + + private UserListViewResponse populateUserListViewResponse(Page pagedResult) { + UserListViewResponse userListViewResponse = + new UserListViewResponse() + .setTotalPages(pagedResult.getTotalPages()) + .setTotalRecords(pagedResult.getTotalElements()) + .setPage(pagedResult.getNumber()) + .setSize(pagedResult.getSize()) + .setHasNext(pagedResult.hasNext()) + .setHasPrevious(pagedResult.hasPrevious()); + + List userEntityList = pagedResult.getContent(); + List userList = + userEntityList.stream() + .map( + user -> { + var userModel = userMapper.entityToModel(user); + userModel.setTeams(new HashSet<>(userModel.getTeams()).stream().toList()); + userModel.setTeamRoles( + user.getUserTeamRoles().stream() + .map(userTeamRoles -> userTeamRolesMapper.entityToModel(userTeamRoles)) + .toList()); +// userModel.setIsCustomerRole( +// userModel.getTeamRoles().stream() +// .anyMatch( +// userTeamRolesModel -> +// userTeamRolesModel.getUserRole().getRole().equals(UserRole.CUSTOMER))); + return userModel; + }) + .toList(); + + userListViewResponse.setUserListViews(userList); + return userListViewResponse; + } + + + @Override + public List getRoles() { + return List.of(); + } + +} diff --git a/src/main/java/com/openAi/security/service/UserTeamRoleService.java b/src/main/java/com/openAi/security/service/UserTeamRoleService.java new file mode 100644 index 0000000..4e692c8 --- /dev/null +++ b/src/main/java/com/openAi/security/service/UserTeamRoleService.java @@ -0,0 +1,10 @@ +package com.openAi.security.service; + +import com.openAi.security.enums.UserRole; + +import java.util.Set; + +public interface UserTeamRoleService { + + Set getUsersByRole(UserRole role); +} diff --git a/src/main/java/com/openAi/security/service/UserTeamRoleServiceImpl.java b/src/main/java/com/openAi/security/service/UserTeamRoleServiceImpl.java new file mode 100644 index 0000000..28692d6 --- /dev/null +++ b/src/main/java/com/openAi/security/service/UserTeamRoleServiceImpl.java @@ -0,0 +1,36 @@ +package com.openAi.security.service; + + +import com.openAi.security.entity.Roles; +import com.openAi.security.entity.User; +import com.openAi.security.entity.UserTeamRoles; +import com.openAi.security.enums.UserRole; +import com.openAi.security.repository.RolesRepository; +import com.openAi.security.repository.UserTeamRoleRepository; +import lombok.RequiredArgsConstructor; + +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class UserTeamRoleServiceImpl implements UserTeamRoleService { + + private final UserTeamRoleRepository userTeamRoleRepository; + private final RolesRepository rolesRepository; + + @Override + public Set getUsersByRole(UserRole userRole) { + + Roles role = rolesRepository.findByRole(userRole); + + List userTeamRoles = userTeamRoleRepository.findByUserRole(role); + return userTeamRoles.stream() + .map(UserTeamRoles::getUser) + .map(User::getName) + .collect(Collectors.toSet()); + } +} diff --git a/src/main/java/com/openAi/security/utils/JwtKeyGenerator.java b/src/main/java/com/openAi/security/utils/JwtKeyGenerator.java new file mode 100644 index 0000000..a6f8c53 --- /dev/null +++ b/src/main/java/com/openAi/security/utils/JwtKeyGenerator.java @@ -0,0 +1,15 @@ +package com.openAi.security.utils; + +import io.jsonwebtoken.security.Keys; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Encoders; + +import java.security.Key; + +public class JwtKeyGenerator { + public static void main(String[] args) { + Key key = Keys.secretKeyFor(SignatureAlgorithm.HS512); // Generates a secure random key + String base64Key = Encoders.BASE64.encode(key.getEncoded()); // Encode key to Base64 + System.out.println("Generated Key: " + base64Key); + } +} diff --git a/src/main/java/com/openAi/security/utils/JwtUtils.java b/src/main/java/com/openAi/security/utils/JwtUtils.java new file mode 100644 index 0000000..7baac6e --- /dev/null +++ b/src/main/java/com/openAi/security/utils/JwtUtils.java @@ -0,0 +1,73 @@ +package com.openAi.security.utils; + +import com.openAi.security.exceptions.InvalidAuthenticationException; +import io.jsonwebtoken.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + +@Component +public class JwtUtils { + + private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class); + + @Value("${security.jwtSecret}") + private String jwtSecret; + + @Value("${security.jwtExpirationMs}") + private int jwtExpirationMs; + + public String getJWTToken(String username) { + List grantedAuthorities = + AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"); + + String token = + Jwts.builder() + .setId("softtekJWT") + .setSubject(username) + .claim( + "authorities", + grantedAuthorities.stream() + .map(GrantedAuthority::getAuthority) + .toList()) + .setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + jwtExpirationMs)) + .signWith(SignatureAlgorithm.HS512, jwtSecret) + .compact(); + logger.info("Token successfully generated for user: {}", username); + return token; + } + + public void validateJwtToken(String authToken) { + try { + Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken).getBody(); + } + catch (SignatureException|MalformedJwtException|UnsupportedJwtException|IllegalArgumentException e) { + throw e; + } catch (ExpiredJwtException e) { + final String errorMessage = String.format("JWT token is expired | %s", e.getMessage()); + throw InvalidAuthenticationException.invalidToken(errorMessage); + } + } + + public String getSubject(String jwt) { + return getAllClaimsFromToken(jwt).getSubject(); + } + + public Claims getAllClaimsFromToken(String token) { + Claims claims; + try { + claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody(); + } catch (Exception e) { + logger.error("Could not get all claims Token from passed token"); + claims = null; + } + return claims; + } +} diff --git a/src/main/java/com/openAi/security/utils/SessionUtils.java b/src/main/java/com/openAi/security/utils/SessionUtils.java new file mode 100644 index 0000000..cd4bd48 --- /dev/null +++ b/src/main/java/com/openAi/security/utils/SessionUtils.java @@ -0,0 +1,35 @@ +package com.openAi.security.utils; + +import com.openAi.security.model.UserModel; +import com.openAi.security.service.UserService; +import com.openAi.security.utils.JwtUtils; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Objects; + +@Service +@RequiredArgsConstructor +public class SessionUtils { + + private final HttpServletRequest request; + private final UserService userService; + private final JwtUtils jwtUtils; + + public UserModel getLoggedInUser() { + Cookie[] cookieAuth = request.getCookies(); + String jwt = ""; + if (Objects.nonNull(cookieAuth)) { + for (Cookie cookie : cookieAuth) { + if (cookie.getName().equals("auth-token")) { + jwt = cookie.getValue(); + } + } + } + + String email = jwtUtils.getSubject(jwt); + return userService.findUserByEmail(email); + } +} diff --git a/src/main/java/com/openAi/security/utils/WebSecurityConfig.java b/src/main/java/com/openAi/security/utils/WebSecurityConfig.java new file mode 100644 index 0000000..2a0fd11 --- /dev/null +++ b/src/main/java/com/openAi/security/utils/WebSecurityConfig.java @@ -0,0 +1,126 @@ +package com.openAi.security; + +import com.openAi.security.entity.AllowedDomain; +import com.openAi.security.repository.AllowedDomainRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.http.HttpStatus; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.HttpStatusEntryPoint; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.List; +import java.util.stream.Collectors; + +@Configuration +@EnableMethodSecurity(prePostEnabled = true) +@RequiredArgsConstructor +@EnableWebSecurity +public class WebSecurityConfig { + + private final AllowedDomainRepository allowedDomainRepository; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception { + http.cors(cors -> cors.configurationSource(corsConfigurationSource())) + .csrf(csrf -> csrf.disable()) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(authorize -> authorize + .requestMatchers( + "/getToken", + "/getTokenUserAuth", + "/user/generatePassword", + "/resetPassword", + "/getTokenGoogleAuth" + ).permitAll() + .anyRequest().authenticated() + ) + .exceptionHandling(exception -> exception.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))) + .addFilterBefore(authenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class); + return http.build(); + } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { + return authenticationConfiguration.getAuthenticationManager(); + } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + updateCorsConfiguration(configuration); + applyCommonCorsSettings(configuration); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + + @Bean + @Profile("test") + public CorsConfigurationSource corsConfigurationSourceTest() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins(List.of( + "https://playbook.talentica.com/", + "https://orion.talentica.com/", + "https://prod-orion.talentica.com/", + "http://localhost:3000/", + "http://localhost/", + "https://stagingplaybook.talentica.com", + "https://dev-orion.talentica.com/", + "https://stagingorion.talentica.com", + "https://staging-orion.talentica.com/", + "http://localhost:3001/", + "https://stagingknowledgebase.talentica.com/", + "https://stagingknowledgebase-sales.talentica.com/", + "https://staging.kb.talentica.com/", + "https://nexus.talentica.com/", + "https://kb.talentica.com/" + )); + applyCommonCorsSettings(configuration); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + + public void updateCorsConfiguration(CorsConfiguration configuration) { + List allowedOrigins = allowedDomainRepository.findAll() + .stream() + .map(AllowedDomain::getDomainName) + .collect(Collectors.toList()); + configuration.setAllowedOrigins(allowedOrigins); + } + + private void applyCommonCorsSettings(CorsConfiguration configuration) { + configuration.addExposedHeader("Set-Cookie"); + configuration.setAllowedMethods(List.of("GET", "POST", "OPTIONS", "PUT", "DELETE")); + configuration.setAllowedHeaders(List.of( + "Api-Key", + "Authorization", + "Cache-Control", + "Content-Type", + "Access-Control-Allow-Origin", + "Access-Control-Allow-Credentials" + )); + configuration.setAllowCredentials(true); + } + + @Bean + public AuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) { + AuthenticationFilter filter = new AuthenticationFilter(); + filter.setAuthenticationManager(authenticationManager); + return filter; + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1fd37ae..9c4f1ed 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,17 +1,43 @@ spring: application: name: demo + jpa: + properties: + hibernate: + jdbc: + time_zone: Asia/Kolkata + enable_lazy_load_no_trans: true + hibernate: + ddl-auto: update + datasource: + hikari: + minimumIdle: 2 + maximumPoolSize: 10 + url: jdbc:mysql://localhost:3306/playbook + username: root + password: password + driver-class-name: com.mysql.cj.jdbc.Driver + ddl-auto: update ai: vectorstore: - redis: - host: localhost - port: 6379 - database: 0 - index: faqs - prefix: "faq:" - initialize-schema: true +# redis: +# host: localhost +# port: 6379 +# database: 0 +# index: faqs +# prefix: "faq:" +# initialize-schema: true openai: temperature: 0.3 api-key: ${OPEN-AI-KEY} model: gpt-3.5-turbo +security: + jwtSecret: eQUxnnSq6Ypz7FvcVBFh8AzvRwInfXokdCPCgY8G3ZTVsWCcpDE0Xun3HlgWd9OqRxxkKghUTAuZLJrt4grpPQ== + + jwtExpirationMs: 604800000 + apiKey: 53e72eed-6f0b-4d5b-9cc5-088487d969b9 + +customer-login: + site-url: https://dev-orion.talentica.com + login-endpoint: /login \ No newline at end of file