diff --git a/.gitignore b/.gitignore
index 524f0963..219512a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,24 +1,42 @@
-# Compiled class file
-*.class
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+### DS_Store ###
+.DS_Store
+/bin/
+
-# Log file
-*.log
-# BlueJ files
-*.ctxt
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-# Package Files #
-*.jar
-*.war
-*.nar
-*.ear
-*.zip
-*.tar.gz
-*.rar
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
-replay_pid*
diff --git a/pom.xml b/pom.xml
index 6142921d..1b55d803 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,6 +1,5 @@
-
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
org.springframework.boot
@@ -13,42 +12,148 @@
0.0.1-SNAPSHOT
tendermanagement
Tender Management project
-
-
-
-
-
-
-
-
-
-
-
-
-
17
+ 1.5.5.Final
+
org.springframework.boot
spring-boot-starter-web
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+ com.h2database
+ h2
+
+
+
+
+ org.postgresql
+ postgresql
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ 2.2.0
+
+
+
+
+ org.mapstruct
+ mapstruct
+ ${mapstruct.version}
+
+
+ org.mapstruct
+ mapstruct-processor
+ ${mapstruct.version}
+ provided
+
+
+
+ org.liquibase
+ liquibase-core
+
+
+
org.springframework.boot
spring-boot-starter-test
test
+
+
+ com.amazonaws
+ aws-java-sdk-s3
+ 1.12.312
+
+
+
+ com.amazonaws
+ aws-java-sdk-core
+ 1.12.341
+
+
+
+ commons-io
+ commons-io
+ 2.11.0
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.11.5
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ jakarta.validation
+ jakarta.validation-api
+
+
+ org.hibernate.validator
+ hibernate-validator
+
+
+
+ com.google.code.gson
+ gson
+ 2.10.1
+
+
+
+
+
org.springframework.boot
spring-boot-maven-plugin
+
+ org.liquibase
+ liquibase-maven-plugin
+ 4.20.0
+
+ src/main/resources/application.properties
+
+
-
diff --git a/src/main/java/net/gepafin/tendermanagement/TendermanagementApplication.java b/src/main/java/net/gepafin/tendermanagement/TendermanagementApplication.java
index f63a972f..07a51505 100644
--- a/src/main/java/net/gepafin/tendermanagement/TendermanagementApplication.java
+++ b/src/main/java/net/gepafin/tendermanagement/TendermanagementApplication.java
@@ -2,12 +2,21 @@ package net.gepafin.tendermanagement;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.scheduling.annotation.EnableScheduling;
+@EnableScheduling
+@ComponentScan(basePackages = {"net.gepafin.tendermanagement"})
+@EnableJpaRepositories(basePackages = {"net.gepafin.tendermanagement"})
+@EntityScan(basePackages = {"net.gepafin.tendermanagement"})
@SpringBootApplication
public class TendermanagementApplication {
public static void main(String[] args) {
SpringApplication.run(TendermanagementApplication.class, args);
+ System.out.println("Spring Boot started");
}
}
diff --git a/src/main/java/net/gepafin/tendermanagement/config/AmazonConfig.java b/src/main/java/net/gepafin/tendermanagement/config/AmazonConfig.java
new file mode 100644
index 00000000..878cd12f
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/config/AmazonConfig.java
@@ -0,0 +1,34 @@
+package net.gepafin.tendermanagement.config;
+
+import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.auth.AWSStaticCredentialsProvider;
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.AmazonS3ClientBuilder;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class AmazonConfig {
+
+ @Value("${aws.access.key.id}")
+ private String accessKey;
+
+ @Value("${aws.secret.access.key}")
+ private String secretKey;
+
+ @Value("${aws.s3.region}")
+ private String region;
+
+ @Bean
+ public AmazonS3 mementoBucket() {
+ AWSCredentials awsCredentials =
+ new BasicAWSCredentials(accessKey, secretKey);
+ return AmazonS3ClientBuilder
+ .standard()
+ .withRegion(region)
+ .withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/gepafin/tendermanagement/config/MessageSourceConfig.java b/src/main/java/net/gepafin/tendermanagement/config/MessageSourceConfig.java
new file mode 100644
index 00000000..6f9767c6
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/config/MessageSourceConfig.java
@@ -0,0 +1,17 @@
+package net.gepafin.tendermanagement.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.support.ResourceBundleMessageSource;
+
+@Configuration
+public class MessageSourceConfig {
+ @Bean(name = "defaultMessageSource")
+ public ResourceBundleMessageSource messageSource() {
+ ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
+ messageSource.setBasenames("message");
+ messageSource.setDefaultEncoding("UTF-8");
+ messageSource.setUseCodeAsDefaultMessage(true);
+ return messageSource;
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/config/SchemaInit.java b/src/main/java/net/gepafin/tendermanagement/config/SchemaInit.java
new file mode 100644
index 00000000..6d57f81f
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/config/SchemaInit.java
@@ -0,0 +1,70 @@
+package net.gepafin.tendermanagement.config;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AbstractDependsOnBeanFactoryPostProcessor;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.stereotype.Component;
+
+import liquibase.change.DatabaseChange;
+import liquibase.integration.spring.SpringLiquibase;
+import org.springframework.beans.factory.annotation.Value;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Configuration
+@ConditionalOnClass({ SpringLiquibase.class, DatabaseChange.class })
+@ConditionalOnProperty(prefix = "spring.liquibase", name = "enabled", matchIfMissing = true)
+@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
+@Import({SchemaInit.SpringLiquibaseDependsOnPostProcessor.class})
+public class SchemaInit {
+
+ @Component
+ @ConditionalOnProperty(prefix = "spring.liquibase", name = "enabled", matchIfMissing = true)
+ public static class SchemaInitBean implements InitializingBean {
+
+ private final DataSource dataSource;
+ private final String schemaName;
+
+ @Autowired
+ public SchemaInitBean(DataSource dataSource, @Value("${spring.liquibase.default-schema}") String schemaName) {
+ this.dataSource = dataSource;
+ this.schemaName = schemaName;
+ }
+
+ @Override
+ public void afterPropertiesSet() {
+ try (Connection conn = dataSource.getConnection();
+ Statement statement = conn.createStatement()) {
+ log.info("Going to create DB schema '{}' if not exists.", schemaName);
+ String query = "create schema if not exists " + schemaName;
+ statement.execute(query);
+ } catch (SQLException e) {
+ throw new RuntimeException("Failed to create schema '" + schemaName + "'", e);
+ }
+ }
+ }
+
+
+ @ConditionalOnBean(SchemaInitBean.class)
+ static class SpringLiquibaseDependsOnPostProcessor extends AbstractDependsOnBeanFactoryPostProcessor {
+
+ SpringLiquibaseDependsOnPostProcessor() {
+ // Configure the 3rd party SpringLiquibase bean to depend on our SchemaInitBean
+ super(SpringLiquibase.class, SchemaInitBean.class);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java
new file mode 100644
index 00000000..1c97a2de
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java
@@ -0,0 +1,111 @@
+package net.gepafin.tendermanagement.config;
+
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import io.swagger.v3.oas.models.servers.Server;
+import net.gepafin.tendermanagement.config.jwt.JWTConfigurer;
+import net.gepafin.tendermanagement.config.jwt.JWTFilter;
+import net.gepafin.tendermanagement.config.jwt.TokenProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
+
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig {
+
+ private final TokenProvider tokenProvider;
+
+ @Autowired
+ public SecurityConfig(TokenProvider tokenProvider) {
+ this.tokenProvider = tokenProvider;
+ }
+
+ @Bean
+ public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
+ return config.getAuthenticationManager();
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Bean
+ MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
+ return new MvcRequestMatcher.Builder(introspector);
+ }
+
+ @Bean
+ public WebSecurityCustomizer webSecurityCustomizer(MvcRequestMatcher.Builder mvc) {
+ return (web) -> web.ignoring()
+ .requestMatchers(mvc.pattern(HttpMethod.OPTIONS, "/**"))
+ .requestMatchers(new AntPathRequestMatcher("/i18n/**"))
+ .requestMatchers(new AntPathRequestMatcher("/content/**"))
+ .requestMatchers(new AntPathRequestMatcher("/swagger-ui/index.html"))
+ .requestMatchers(new AntPathRequestMatcher("/swagger-ui/**"));
+ }
+
+ @Bean
+ public CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ CorsConfiguration config = new CorsConfiguration();
+ config.setAllowCredentials(true);
+ config.addAllowedOrigin("*");
+ config.addAllowedHeader("*");
+ config.addAllowedMethod("*");
+ source.registerCorsConfiguration("/**", config);
+ return new CorsFilter(source);
+ }
+
+ @Bean
+ public SecurityFilterChain securityFilterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
+ http
+ .csrf(AbstractHttpConfigurer::disable)
+ .authorizeHttpRequests(auth -> auth
+ .requestMatchers(mvc.pattern(HttpMethod.POST, "/v1/user/login")).permitAll()
+ .requestMatchers(mvc.pattern(HttpMethod.POST, "/v1/user")).permitAll()
+ .requestMatchers("/swagger-ui/**").permitAll()
+ .requestMatchers("/v1/api-docs/**").permitAll()
+ .anyRequest().authenticated()
+ )
+ .sessionManagement(session -> session
+ .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ )
+ .apply(new JWTConfigurer(tokenProvider))
+ .and()
+ .addFilterBefore(new JWTFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class);
+
+ return http.build();
+ }
+
+ @Bean
+ public OpenAPI customOpenAPI() {
+ return new OpenAPI()
+ .addServersItem(new Server().url("/"))
+ .addSecurityItem(new SecurityRequirement().addList("bearer-key"))
+ .components(new Components().addSecuritySchemes("bearer-key",
+ new SecurityScheme().type(SecurityScheme.Type.HTTP)
+ .scheme("bearer").bearerFormat("JWT")));
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/config/Translator.java b/src/main/java/net/gepafin/tendermanagement/config/Translator.java
new file mode 100644
index 00000000..b3c02401
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/config/Translator.java
@@ -0,0 +1,25 @@
+package net.gepafin.tendermanagement.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.i18n.LocaleContextHolder;
+import org.springframework.context.support.ResourceBundleMessageSource;
+import org.springframework.stereotype.Component;
+
+import java.util.Locale;
+
+@Component
+public class Translator {
+
+ private static ResourceBundleMessageSource messageSource;
+
+ @Autowired
+ Translator(ResourceBundleMessageSource messageSource) {
+ Translator.messageSource = messageSource;
+ }
+
+ public static String toLocale(String msgCode) {
+// LocaleContextHolder.setDefaultLocale(Locale.ITALIAN);
+ Locale locale = LocaleContextHolder.getLocale();
+ return messageSource.getMessage(msgCode, null, locale);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/net/gepafin/tendermanagement/config/jwt/JWTConfigurer.java b/src/main/java/net/gepafin/tendermanagement/config/jwt/JWTConfigurer.java
new file mode 100644
index 00000000..1ee7efe6
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/config/jwt/JWTConfigurer.java
@@ -0,0 +1,23 @@
+package net.gepafin.tendermanagement.config.jwt;
+
+import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+public class JWTConfigurer extends SecurityConfigurerAdapter {
+
+ public static final String AUTHORIZATION_HEADER = "Authorization";
+
+ private TokenProvider tokenProvider;
+
+ public JWTConfigurer(TokenProvider tokenProvider) {
+ this.tokenProvider = tokenProvider;
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ JWTFilter customFilter = new JWTFilter(tokenProvider);
+ http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/config/jwt/JWTFilter.java b/src/main/java/net/gepafin/tendermanagement/config/jwt/JWTFilter.java
new file mode 100644
index 00000000..4d8d5948
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/config/jwt/JWTFilter.java
@@ -0,0 +1,43 @@
+package net.gepafin.tendermanagement.config.jwt;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.GenericFilterBean;
+
+import java.io.IOException;
+
+public class JWTFilter extends GenericFilterBean {
+
+ private final TokenProvider tokenProvider;
+
+ public JWTFilter(TokenProvider tokenProvider) {
+ this.tokenProvider = tokenProvider;
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
+ throws IOException, ServletException {
+ HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+ String token = resolveToken(httpServletRequest);
+
+ if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
+ Authentication authentication = tokenProvider.getAuthentication(token);
+ if (authentication != null) {
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
+ }
+
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+
+ private String resolveToken(HttpServletRequest request) {
+ String bearerToken = request.getHeader("Authorization");
+ return StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ") ? bearerToken.substring(7) : null;
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/config/jwt/TokenProvider.java b/src/main/java/net/gepafin/tendermanagement/config/jwt/TokenProvider.java
new file mode 100644
index 00000000..c3c54d99
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/config/jwt/TokenProvider.java
@@ -0,0 +1,199 @@
+package net.gepafin.tendermanagement.config.jwt;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.Keys;
+import jakarta.annotation.PostConstruct;
+import jakarta.servlet.http.HttpServletRequest;
+import net.gepafin.tendermanagement.entities.UserEntity;
+import net.gepafin.tendermanagement.util.Utils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.time.DateUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import javax.crypto.SecretKey;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.stream.Collectors;
+import com.google.gson.Gson;
+
+import static io.micrometer.common.util.StringUtils.isEmpty;
+
+
+@Component
+public class TokenProvider {
+ private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
+
+ @Value("${security.authentication.jwt.secret}")
+ private String secretKey;
+
+ @Value("${security.authentication.jwt.token-validity-in-seconds}")
+ private long tokenValidityInSeconds;
+
+ private SecretKey key;
+
+ private static final String AUTHORITIES_KEY = "auth";
+ private static final String MERCHANTID="merchantId";
+
+ public static final String INVALID_USER = "invalid_user";
+ static final String AUTH_SECRET = "X-Api-Secret";
+
+ @PostConstruct
+ public void init() {
+ this.key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));
+ log.info("JWT Secret Key initialized.");
+ }
+
+ public String createToken(Authentication authentication, Boolean rememberMe, UserEntity user) {
+ String authorities = authentication.getAuthorities().stream()
+ .map(GrantedAuthority::getAuthority)
+ .collect(Collectors.joining(","));
+ Long now;
+ Date validity;
+
+ if (Boolean.TRUE.equals(rememberMe)) {
+ now = DateUtils.addMonths(new Date(), 2).getTime();
+ validity = new Date(now);
+ log.info("Creating token with extended validity for 2 months.");
+ } else {
+ now = (new Date()).getTime();
+ validity = new Date(now + (this.tokenValidityInSeconds * 1000));
+ log.info("Creating token with standard validity of {} seconds.", this.tokenValidityInSeconds);
+ }
+
+ String payload = authentication.getName();
+ if(user != null) {
+ payload += ":"+user.getId();
+ }
+
+ String token = Jwts.builder()
+ .setSubject(payload)
+ .claim("auth", authorities)
+ .signWith(key, SignatureAlgorithm.HS512)
+ .setExpiration(validity)
+ .compact();
+
+ log.debug("Generated token: {}", token);
+ return token;
+ }
+
+ public Authentication getAuthentication(String token) {
+ Claims claims = Jwts.parserBuilder()
+ .setSigningKey(key)
+ .build()
+ .parseClaimsJws(token)
+ .getBody();
+
+ UserDetails principal = new User(claims.getSubject(), "", Collections.emptyList());
+ log.info("Authenticated user: {}", claims.getSubject());
+
+ return new UsernamePasswordAuthenticationToken(principal, token, ClaimsToAuthorities(claims.get("auth")));
+ }
+
+ private Collection extends GrantedAuthority> ClaimsToAuthorities(Object authClaim) {
+ Collection extends GrantedAuthority> authorities = authClaim == null || ((String) authClaim).isEmpty() ?
+ Collections.emptyList() :
+ Arrays.stream(((String) authClaim).split(","))
+ .map(SimpleGrantedAuthority::new)
+ .collect(Collectors.toList());
+ log.debug("Converted authorities from claims: {}", authorities);
+ return authorities;
+ }
+
+ public boolean validateToken(String authToken) {
+ try {
+ Jwts.parserBuilder()
+ .setSigningKey(key)
+ .build()
+ .parseClaimsJws(authToken);
+ log.info("Token is valid.");
+ return true;
+ } catch (Exception e) {
+ log.error("Token validation failed: {}", e.getMessage());
+ return false;
+ }
+ }
+ public Map getUserInfoAndUserIdFromToken(HttpServletRequest request) {
+ Map userInfo = new HashMap<>();
+ String authSecretHeader=request.getHeader(AUTH_SECRET);
+// userInfo.put(MERCHANTID, null);
+ String bearerToken = request.getHeader("Authorization");
+ String token = "";
+ if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
+ token = bearerToken.substring(7, bearerToken.length());
+ }
+ extractDetailsFromTheToken(userInfo, authSecretHeader, token);
+ return userInfo;
+ }
+ public Map extractDetailsFromTheToken(Map userInfo, String authSecretHeader,
+ String token) {
+ String payload = null;
+ Boolean isSuperAdmin = false;
+// if (StringUtils.hasText(token) && token.endsWith("_superKey" + getSuperUserToken())) {
+// Map payloadMap = getUserDetailsForSuperUser(token);
+// payload = payloadMap.get("sub").toString();
+// isSuperAdmin = true;
+//
+// } else
+ if (!isEmpty(authSecretHeader)) {
+ String secret = Utils.decodeBase64String(authSecretHeader);
+ String[] tokenArr = secret.split("\\.", 2);
+ String[] merchant = tokenArr[0].split("-");
+ if (ArrayUtils.isNotEmpty(merchant) && 2 <= merchant.length) {
+ userInfo.put(MERCHANTID, merchant[1]);
+ return userInfo;
+ }
+
+ } else {
+ payload = getUserDetails(token);
+ }
+ if (payload != null && !isSuperAdmin) {
+ String[] payloadString = payload.split(":");{
+
+ if (payloadString.length > 1) {
+// userInfo.put(MERCHANTID, payloadString[1]);
+// userInfo.put("associatedTags", payloadString[2]);
+ userInfo.put("userId", payloadString[1]);
+ }
+ }
+
+ if (payloadString.length > 1) {
+// userInfo.put(MERCHANTID, payloadString[1]);
+// userInfo.put("associatedTags", payloadString[2]);
+ userInfo.put("userId", payloadString[1]);
+ }
+ } else {
+ String[] payloadString = payload.split(":");
+
+ if (payloadString.length > 1) {
+ userInfo.put("userId", payloadString[1]);
+ }
+ }
+
+ return userInfo;
+ }
+ public Map getUserDetailsForSuperUser(String token) {
+ Base64.Decoder decoder = Base64.getUrlDecoder();
+ String[] parts = token.split("\\."); // Splitting header, payload and signature
+ Gson g = new Gson();
+ return g.fromJson(new String(decoder.decode(parts[1])), Map.class);
+ }
+// public String getSuperUserToken() {
+// return superUserToken;
+// }
+ public String getUserDetails(String token) {
+ Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody();
+ return claims.getSubject();
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java
new file mode 100644
index 00000000..add54e21
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java
@@ -0,0 +1,44 @@
+package net.gepafin.tendermanagement.constants;
+
+public class GepafinConstant {
+
+ public static final String USER_CREATED_SUCCESS_MSG = "user.created.success";
+ public static final String USER_UPDATED_SUCCESS_MSG = "user.updated.success";
+ public static final String USER_DELETED_SUCCESS_MSG = "user.deleted.success";
+ public static final String USER_NOT_FOUND_MSG = "user.not.found";
+ public static final String CREATE_USER_ERROR_MSG = "create_user_error_msg";
+ public static final String UPDATE_USER_ERROR_MSG = "update_user_error_msg";
+ public static final String DELETE_USER_ERROR_MSG = "delete_user_error_msg";
+ public static final String GET_USER_SUCCESS_MSG = "get_user_success_msg";
+
+ public static final String ROLE_CREATED_SUCCESS_MSG = "role.created.success";
+ public static final String ROLE_UPDATED_SUCCESS_MSG = "role.updated.success";
+ public static final String ROLE_DELETED_SUCCESS_MSG = "role.deleted.success";
+ public static final String ROLE_FETCH_SUCCESS_MSG = "role.fetch.success";
+ public static final String ROLE_NOT_FOUND = "role.not.found";
+
+
+ public static final String REGION_CREATED_SUCCESS_MSG = "region.created.success";
+ public static final String REGION_UPDATED_SUCCESS_MSG = "region.updated.success";
+ public static final String GET_REGION_SUCCESS_MSG = "get.region.success";
+ public static final String DELETE_REGION_SUCCESS_MSG = "delete.region.success";
+ public static final String REGION_NOT_FOUND_MSG = "user.region.not.found";
+ public static final String PASSWORD_DOESNT_MATCH ="password.doesnt.match";
+ public static final String USER_NOT_EXIST_MSG = "user.not.exist";
+ public static final String REGION_NOT_FOUND = "region.not.found";
+ public static final String USER_ID_NOT_NULL_MSG = "user.id.not.null";
+ public static final String QUESTION_NOT_EMPTY_MSG = "question.not.empty";
+ public static final String NAME_NOT_EMPTY_MSG = "name.not.empty";
+ public static final String TYPE_NOT_EMPTY_MSG = "type.not.empty";
+ public static final String REGION_NOT_NULL_MSG = "region.not.null";
+ public static final String AMOUNT_GREATER_THAN_ZERO_MSG = "amount.greater.than.zero";
+ public static final String LOOK_UP_DATA_NOT_VALID_MSG = "look.up.data.not.valid";
+ public static final String FILES_UPLOADED_MSG = "files.uploaded";
+ public static final String CALL_CREATED_SUCCESSFULLY_MSG = "call.created.successfully";
+ public static final String FILE_DELETED_SUCCESSFULLY_MSG="file.deleted.successfully";
+ public static final String DOCUMENT_NOT_FOUND="document.not.found";
+ public static final String LOGIN_SUCCESS_MSG="login.successfully";
+ public static final String PASSWORD_MIN_LEN ="pass.min.len.msg";
+ public static final String EMAIL_ALREADY_EXISTS = "email.already.exists";
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java
new file mode 100644
index 00000000..d034f8a7
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java
@@ -0,0 +1,325 @@
+package net.gepafin.tendermanagement.dao;
+
+import net.gepafin.tendermanagement.config.Translator;
+import net.gepafin.tendermanagement.constants.GepafinConstant;
+import net.gepafin.tendermanagement.entities.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import net.gepafin.tendermanagement.enums.CallTypeEnum;
+import net.gepafin.tendermanagement.model.request.*;
+import net.gepafin.tendermanagement.model.response.*;
+import net.gepafin.tendermanagement.repositories.*;
+import net.gepafin.tendermanagement.util.DateTimeUtil;
+import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException;
+import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException;
+import net.gepafin.tendermanagement.web.rest.api.errors.Status;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import net.gepafin.tendermanagement.entities.LookUpDataEntity.LookUpDataTypeEnum;
+
+@Component
+public class CallDao {
+
+ @Autowired
+ private CallRepository callRepository;
+
+ @Autowired
+ private DocumentRepository documentRepository;
+
+ @Autowired
+ private EvaluationCriteriaRepository evaluationCriteriaRepository;
+
+ @Autowired
+ private FaqRepository faqRepository;
+
+ @Autowired
+ private RegionRepository regionRepository;
+
+ @Autowired
+ private LookUpDataRepository lookUpDataRepository;
+
+ @Autowired
+ private CallTargetAudienceChecklistRepository callTargetAudienceChecklistRepository;
+
+ @Autowired
+ private UserRepository userRepository;
+
+ public CreateCallResponseBean createCall(CreateCallRequest createCallRequest, Long userId) {
+ try {
+ CreateCallResponseBean createCallResponseBean=null;
+ CallEntity callEntity = convertToCallEntity(createCallRequest);
+ List evaluationCriteriaEntities = convertToEvaluationCriteriaEntities(createCallRequest.getCriteria(), callEntity);
+ List documentEntities = convertToDocumentEntities(createCallRequest.getDocs(), callEntity);
+ List imageEntities=convertToDocumentEntities(createCallRequest.getImages(),callEntity);
+ List faqEntities = convertToFaqEntities(createCallRequest.getFaq(), callEntity, userId);
+ List amiedTo=convertLookUpDataEntities(createCallRequest.getAimedTo(),callEntity,LookUpDataTypeEnum.AIMED_TO);
+ List checkList=convertLookUpDataEntities(createCallRequest.getAimedTo(),callEntity,LookUpDataTypeEnum.CHECKLIST);
+ createCallResponseBean= assembleCreateCallResponseBean(callEntity, evaluationCriteriaEntities, documentEntities, faqEntities,imageEntities);
+ createCallResponseBean.setAimedTo(amiedTo);
+ createCallResponseBean.setCheckList(checkList);
+ return createCallResponseBean;
+ } catch (Exception e) {
+ throw new RuntimeException("Error processing create call request", e);
+ }
+ }
+
+
+ public CallEntity convertToCallEntity(CreateCallRequest createCallRequest) {
+ CallEntity callEntity = new CallEntity();
+ validateCallEntity(createCallRequest.getRegionId(), createCallRequest.getAmount());
+ RegionEntity region = regionRepository.findById(createCallRequest.getRegionId())
+ .orElseThrow(() -> new ResourceNotFoundException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.REGION_NOT_FOUND)));
+ callEntity.setRegion(region);
+ callEntity.setName(createCallRequest.getName());
+ callEntity.setDescriptionShort(createCallRequest.getDescriptionShort());
+ callEntity.setDescriptionLong(createCallRequest.getDescriptionLong());
+ callEntity.setStartDate(createCallRequest.getStartDate());
+ callEntity.setEndDate(createCallRequest.getEndDate());
+ callEntity.setStatus(String.valueOf(createCallRequest.getStatus()));
+ callEntity.setAmountMax(createCallRequest.getAmountMax());
+ callEntity.setAmount(createCallRequest.getAmountMax());
+ callEntity.setThreshold(createCallRequest.getThreshold());
+ callEntity.setConfidi(false);
+ if(createCallRequest.getConfidi()!=null){
+ callEntity.setConfidi(createCallRequest.getConfidi());
+ }
+ callEntity.setDocumentation_requested(createCallRequest.getDocumentationRequested());
+ callEntity = callRepository.save(callEntity);
+ return callEntity;
+ }
+
+ public List convertToEvaluationCriteriaEntities(List criteriaReqList, CallEntity callEntity) {
+ List evaluationCriteriaEntities = criteriaReqList.stream().map(req -> convertToEvaluationCriteriaEntity(req, callEntity)).collect(Collectors.toList());
+ evaluationCriteriaRepository.saveAll(evaluationCriteriaEntities);
+ return evaluationCriteriaEntities;
+ }
+
+ private EvaluationCriteriaEntity convertToEvaluationCriteriaEntity(EvaluationCriteriaReq criteriaReq, CallEntity callEntity) {
+ EvaluationCriteriaEntity criteriaEntity = new EvaluationCriteriaEntity();
+ validateEvolutionCrieteriaEntity(criteriaReq.getName());
+ criteriaEntity.setName(criteriaReq.getName());
+ criteriaEntity.setDescription(criteriaReq.getValue());
+ criteriaEntity.setScore(criteriaReq.getScore());
+ criteriaEntity.setCall(callEntity);
+ return criteriaEntity;
+ }
+
+
+ public List convertToDocumentEntities(List documentReqList, CallEntity callEntity) {
+ List documentEntities = documentReqList.stream().map(req -> convertToDocumentEntity(req, callEntity)).collect(Collectors.toList());
+ documentRepository.saveAll(documentEntities);
+ return documentEntities;
+ }
+
+ private DocumentEntity convertToDocumentEntity(DocumentReq documentReq, CallEntity callEntity) {
+ DocumentEntity documentEntity = new DocumentEntity();
+ validateDocumentEntity(documentReq.getFileName());
+ documentEntity.setFileName(documentReq.getFileName());
+ documentEntity.setFilePath(documentReq.getUrl());
+ documentEntity.setCall(callEntity);
+ return documentEntity;
+ }
+
+
+ public List convertToFaqEntities(List faqReqList, CallEntity callEntity, Long userId) {
+ List faqEntities = faqReqList.stream().map(req -> convertToFaqEntity(req, callEntity, userId)).collect(Collectors.toList());
+ faqRepository.saveAll(faqEntities);
+ return faqEntities;
+ }
+
+ private FaqEntity convertToFaqEntity(FaqReq faqReq, CallEntity callEntity, Long userId) {
+ FaqEntity faqEntity = new FaqEntity();
+ validateFaqEntity(faqReq.getQuestion());
+ UserEntity userEntity= userRepository.findById(userId)
+ .orElseThrow(() -> new ResourceNotFoundException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.LOOK_UP_DATA_NOT_VALID_MSG)));
+ faqEntity.setUser(userEntity);
+ faqEntity.setIsVisible(true);
+ if(faqReq.getIsVisible()!=null){
+ faqEntity.setIsVisible(faqReq.getIsVisible());
+ }
+ faqEntity.setQuestionShort(faqReq.getQuestionShort());
+ faqEntity.setQuestion(faqReq.getQuestion());
+ if(faqReq.getResponse()!=null ||faqReq.getResponseShort()!=null){
+ faqEntity.setResponseDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
+ }
+ faqEntity.setResponseShort(faqReq.getResponseShort());
+ faqEntity.setResponse(faqReq.getResponse());
+ faqEntity.setCall(callEntity);
+ return faqEntity;
+ }
+
+ public void validateFaqEntity( String question) {
+ if (!StringUtils.hasText(question)) {
+ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.QUESTION_NOT_EMPTY_MSG));
+ }
+ }
+
+ public void validateDocumentEntity(String name) {
+ if (!StringUtils.hasText(name)) {
+ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.NAME_NOT_EMPTY_MSG));
+ }
+ }
+
+ public void validateEvolutionCrieteriaEntity(String name) {
+ if (!StringUtils.hasText(name)) {
+ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.NAME_NOT_EMPTY_MSG));
+ }
+ }
+
+ public void validateCallEntity(Long regionId, BigDecimal fundingAmount) {
+ if (regionId == null) {
+ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.REGION_NOT_FOUND_MSG));
+ }
+
+ if (fundingAmount == null || fundingAmount.compareTo(BigDecimal.ZERO) <= 0) {
+ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.AMOUNT_GREATER_THAN_ZERO_MSG));
+ }
+ }
+ public CreateCallResponseBean convertToCallResponseBean(CallEntity callEntity) {
+ CreateCallResponseBean createCallResponseBean = new CreateCallResponseBean();
+ createCallResponseBean.setId(callEntity.getId());
+ createCallResponseBean.setName(callEntity.getName());
+ createCallResponseBean.setDates(List.of(callEntity.getStartDate(), callEntity.getEndDate()));
+ createCallResponseBean.setDescriptionShort(callEntity.getDescriptionShort());
+ createCallResponseBean.setDescriptionLong(callEntity.getDescriptionLong());
+ createCallResponseBean.setStatus(CallTypeEnum.valueOf(callEntity.getStatus()));
+ createCallResponseBean.setRegionId(callEntity.getRegion().getId());
+ createCallResponseBean.setAmount(callEntity.getAmount());
+ createCallResponseBean.setAmountMax(callEntity.getAmountMax());
+ createCallResponseBean.setContactInfo(callEntity.getContactInfo());
+ createCallResponseBean.setSubmissionMethod(callEntity.getSubmissionMethod());
+ createCallResponseBean.setThreshold(callEntity.getThreshold());
+ createCallResponseBean.setDocumentationReqested(callEntity.getDocumentation_requested());
+ createCallResponseBean.setPriorityArea(callEntity.getPriorityArea());
+ createCallResponseBean.setCreatedDate(callEntity.getCreatedDate());
+ createCallResponseBean.setUpdatedDate(callEntity.getUpdatedDate());
+ return createCallResponseBean;
+ }
+ public EvaluationCriteriaResponseBean convertToEvaluationCriteriaResponseBean(EvaluationCriteriaEntity entity) {
+ EvaluationCriteriaResponseBean responseBean = new EvaluationCriteriaResponseBean();
+ responseBean.setId(entity.getId());
+ responseBean.setName(entity.getName());
+ responseBean.setDescription(entity.getDescription());
+ responseBean.setScore(entity.getScore());
+ responseBean.setCreatedDate(entity.getCreatedDate());
+ responseBean.setUpdatedDate(entity.getUpdatedDate());
+ return responseBean;
+ }
+ public DocumentResponseBean convertToDocumentResponseBean(DocumentEntity entity) {
+ DocumentResponseBean responseBean = new DocumentResponseBean();
+ responseBean.setId(entity.getId());
+ responseBean.setName(entity.getFileName());
+ responseBean.setDescription(entity.getDescription());
+ responseBean.setFilePath(entity.getFilePath());
+ responseBean.setCreatedDate(entity.getCreatedDate());
+ responseBean.setUpdatedDate(entity.getUpdatedDate());
+ return responseBean;
+ }
+ public FaqResponseBean convertToFaqResponseBean(FaqEntity entity) {
+ FaqResponseBean responseBean = new FaqResponseBean();
+ responseBean.setId(entity.getId());
+ responseBean.setQuestionShort(entity.getQuestionShort());
+ responseBean.setResponseShort(entity.getResponseShort());
+ responseBean.setResponse(entity.getResponse());
+ responseBean.setQuestion(entity.getQuestion());
+ responseBean.setUserId(entity.getUser().getId());
+ responseBean.setIsVisible(entity.getIsVisible());
+ responseBean.setCreatedDate(entity.getCreatedDate());
+ responseBean.setUpdatedDate(entity.getUpdatedDate());
+ return responseBean;
+ }
+ public CreateCallResponseBean assembleCreateCallResponseBean(
+ CallEntity callEntity,
+ List evaluationCriteriaEntities,
+ List documentEntities,
+ List faqEntities,List images) {
+
+ CreateCallResponseBean callResponseBean = convertToCallResponseBean(callEntity);
+
+ List evaluationCriteriaResponseBeans = evaluationCriteriaEntities.stream()
+ .map(this::convertToEvaluationCriteriaResponseBean)
+ .collect(Collectors.toList());
+
+ List documentResponseBeans = documentEntities.stream()
+ .map(this::convertToDocumentResponseBean)
+ .collect(Collectors.toList());
+
+ List faqResponseBeans = faqEntities.stream()
+ .map(this::convertToFaqResponseBean)
+ .collect(Collectors.toList());
+
+ List imagesResponseBean = images.stream()
+ .map(this::convertToDocumentResponseBean)
+ .collect(Collectors.toList());
+ CreateCallResponseBean createCallResponseBean =callResponseBean;
+ createCallResponseBean.setCriteria(evaluationCriteriaResponseBeans);
+ createCallResponseBean.setDocs(documentResponseBeans);
+ createCallResponseBean.setFaq(faqResponseBeans);
+ createCallResponseBean.setImages(imagesResponseBean);
+ return createCallResponseBean;
+ }
+ public List convertLookUpDataEntities(List lookUpData, CallEntity callEntity, LookUpDataEntity.LookUpDataTypeEnum type) {
+ List lookUpDataEntities = lookUpData.stream()
+ .map(req -> convertLookUpDataRequestIntoLookUpDataEntity(req, type))
+ .collect(Collectors.toList());
+
+ lookUpDataRepository.saveAll(lookUpDataEntities);
+
+ return createCallTargetAudienceCheckList(callEntity, lookUpDataEntities);
+ }
+
+ private List createCallTargetAudienceCheckList(CallEntity callEntity, List lookUpDataEntities) {
+ List lookUpDataResponses=new ArrayList<>();
+ List callTargetAudienceChecklistEntities=new ArrayList<>();
+ for(LookUpDataEntity lookUpDataEntity:lookUpDataEntities){
+ CallTargetAudienceChecklistEntity callTargetAudienceChecklistEntity=new CallTargetAudienceChecklistEntity();
+ callTargetAudienceChecklistEntity.setIsValidated(false);
+ callTargetAudienceChecklistEntity.setLookupData(lookUpDataEntity);
+ callTargetAudienceChecklistEntity.setCall(callEntity);
+ callTargetAudienceChecklistEntities.add(callTargetAudienceChecklistEntity);
+ lookUpDataResponses.add(convertToLookUpDataResponseBean(lookUpDataEntity,callTargetAudienceChecklistEntity));
+ }
+ callTargetAudienceChecklistRepository.saveAll(callTargetAudienceChecklistEntities);
+ return lookUpDataResponses;
+ }
+
+ private LookUpDataEntity convertLookUpDataRequestIntoLookUpDataEntity(LookUpDataReq req, LookUpDataEntity.LookUpDataTypeEnum type) {
+ if (req.getLookUpDataId() == null || req.getLookUpDataId().equals(BigDecimal.ZERO)) {
+ LookUpDataEntity newEntity = new LookUpDataEntity();
+ newEntity.setValue(req.getValue());
+ newEntity.setType(type.getValue());
+ return newEntity;
+ }
+
+ return lookUpDataRepository.findById(req.getLookUpDataId())
+ .orElseThrow(() -> new ResourceNotFoundException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.LOOK_UP_DATA_NOT_VALID_MSG)));
+ }
+
+ private CallTargetAudienceChecklistEntity createChecklistEntity(CallEntity callEntity, LookUpDataEntity lookUpDataEntity) {
+ CallTargetAudienceChecklistEntity checklistEntity = new CallTargetAudienceChecklistEntity();
+ checklistEntity.setCall(callEntity);
+ checklistEntity.setLookupData(lookUpDataEntity);
+ checklistEntity.setIsValidated(false);
+ return checklistEntity;
+ }
+
+ public LookUpDataResponse convertToLookUpDataResponseBean(LookUpDataEntity lookUpDataEntity,CallTargetAudienceChecklistEntity callTargetAudienceChecklistEntity) {
+ LookUpDataResponse lookUpDataResponse = new LookUpDataResponse();
+ lookUpDataResponse.setId(callTargetAudienceChecklistEntity.getId());
+ lookUpDataResponse.setLookUpDataId(lookUpDataEntity.getId());
+ lookUpDataResponse.setValue(lookUpDataEntity.getValue());
+ lookUpDataResponse.setTitle(lookUpDataEntity.getTitle());
+ lookUpDataResponse.setCreatedDate(lookUpDataEntity.getCreatedDate());
+ lookUpDataResponse.setUpdatedDate(lookUpDataEntity.getUpdatedDate());
+ return lookUpDataResponse;
+ }
+}
+
+
+
diff --git a/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java b/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java
new file mode 100644
index 00000000..3c5cd708
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/dao/DocumentDao.java
@@ -0,0 +1,80 @@
+package net.gepafin.tendermanagement.dao;
+
+import net.gepafin.tendermanagement.config.Translator;
+import net.gepafin.tendermanagement.constants.GepafinConstant;
+import net.gepafin.tendermanagement.entities.DocumentEntity;
+import net.gepafin.tendermanagement.enums.DocumentTypeEnum;
+import net.gepafin.tendermanagement.model.response.DocumentResponseBean;
+import net.gepafin.tendermanagement.repositories.DocumentRepository;
+import net.gepafin.tendermanagement.service.AmazonS3Service;
+import net.gepafin.tendermanagement.util.Utils;
+import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException;
+import net.gepafin.tendermanagement.web.rest.api.errors.Status;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Component
+public class DocumentDao {
+
+ @Autowired
+ private AmazonS3Service amazonS3Service;
+
+ @Autowired
+ private DocumentRepository documentRepository;
+
+ @Autowired
+ private CallDao callDao;
+
+ @Value("${aws.s3.bucket.name}")
+ private String bucketName;
+
+ @Value("${aws.s3.url.folder}")
+ private String s3Folder;
+
+ @Value("${aws.s3.url}")
+ private String s3Url;
+
+ public List uploadFiles(List files, DocumentTypeEnum fileType) {
+ List documentEntities = new ArrayList<>();
+
+ for (MultipartFile file : files) {
+ try {
+ String extension = FilenameUtils.getExtension(file.getOriginalFilename());
+ String fileName = StringUtils.cleanPath(file.getOriginalFilename());
+ String firstNameContain = fileName.substring(0, fileName.lastIndexOf('.'));
+ fileName = (firstNameContain + "." + extension);
+ String filepath = amazonS3Service.upload(fileName,file);
+ DocumentEntity documentEntity = new DocumentEntity();
+ documentEntity.setFileName(fileName);
+ documentEntity.setType(fileType.getValue());
+ documentEntity.setFilePath(filepath);
+ documentEntities.add(documentEntity);
+ } catch (IOException e) {}
+ }
+ documentRepository.saveAll(documentEntities);
+ return documentEntities.stream()
+ .map(callDao::convertToDocumentResponseBean)
+ .collect(Collectors.toList());
+ }
+ public Void deleteFile(Long documentId){
+ DocumentEntity documentEntity= documentRepository.findById(documentId);
+ if(documentEntity==null){
+ new ResourceNotFoundException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND));
+ }
+ String fileName= Utils.extractFileName(documentEntity.getFilePath());
+ try {
+ amazonS3Service.delete(bucketName, fileName);
+ documentRepository.delete(documentEntity);
+ }catch (Exception e){}
+ return null;
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/dao/RegionDao.java b/src/main/java/net/gepafin/tendermanagement/dao/RegionDao.java
new file mode 100644
index 00000000..9277b167
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/dao/RegionDao.java
@@ -0,0 +1,127 @@
+package net.gepafin.tendermanagement.dao;
+
+import net.gepafin.tendermanagement.config.Translator;
+import net.gepafin.tendermanagement.constants.GepafinConstant;
+import net.gepafin.tendermanagement.entities.RegionEntity;
+import net.gepafin.tendermanagement.model.request.RegionReq;
+import net.gepafin.tendermanagement.model.response.RegionResponseBean;
+import net.gepafin.tendermanagement.repositories.RegionRepository;
+import net.gepafin.tendermanagement.util.Utils;
+import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException;
+import net.gepafin.tendermanagement.web.rest.api.errors.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static net.gepafin.tendermanagement.util.ObjectUtils.setIfUpdated;
+
+@Repository
+public class RegionDao {
+ private final Logger log = LoggerFactory.getLogger(RegionDao.class);
+
+ @Autowired
+ private RegionRepository regionRepository;
+
+ public RegionResponseBean createRegion(RegionReq regionReq) {
+ log.info("Creating new region with details: {}", regionReq);
+ RegionEntity regionEntity = convertRegionRequestToRegionEntity(regionReq);
+ regionEntity = regionRepository.save(regionEntity);
+ log.info("Region created with ID: {}", regionEntity.getId());
+ return convertRegionEntityToRegionResponse(regionEntity);
+ }
+
+ private RegionEntity convertRegionRequestToRegionEntity(RegionReq regionReq) {
+ RegionEntity regionEntity = new RegionEntity();
+ regionEntity.setCountry(regionReq.getCountry());
+ regionEntity.setDescription(regionReq.getDescription());
+ regionEntity.setGdp(regionReq.getGdp());
+ regionEntity.setRegionName(regionReq.getRegionName());
+ regionEntity.setAreaSize(regionReq.getAreaSize());
+ regionEntity.setPopulation(regionReq.getPopulation());
+ regionEntity.setEnvironmentalScore(regionReq.getEnvironmentalScore());
+ regionEntity.setStatus(regionReq.getStatus());
+ regionEntity.setHealthcareAccess(regionReq.getHealthcareAccess());
+ regionEntity.setInfrastructureScore(regionReq.getInfrastructureScore());
+ regionEntity.setPriorityArea(regionReq.getPriorityArea());
+ regionEntity.setUnemploymentRate(regionReq.getUnemploymentRate());
+ regionEntity.setEducationLevel(regionReq.getEducationLevel());
+ return regionEntity;
+ }
+
+ public RegionResponseBean convertRegionEntityToRegionResponse(RegionEntity regionEntity) {
+ RegionResponseBean regionResponseBean = new RegionResponseBean();
+ regionResponseBean.setId(regionEntity.getId());
+ regionResponseBean.setCreatedDate(regionEntity.getCreatedDate());
+ regionResponseBean.setUpdatedDate(regionEntity.getUpdatedDate());
+ regionResponseBean.setCountry(regionEntity.getCountry());
+ regionResponseBean.setDescription(regionEntity.getDescription());
+ regionResponseBean.setGdp(regionEntity.getGdp());
+ regionResponseBean.setRegionName(regionEntity.getRegionName());
+ regionResponseBean.setAreaSize(regionEntity.getAreaSize());
+ regionResponseBean.setPopulation(regionEntity.getPopulation());
+ regionResponseBean.setEnvironmentalScore(regionEntity.getEnvironmentalScore());
+ regionResponseBean.setStatus(regionEntity.getStatus());
+ regionResponseBean.setHealthcareAccess(regionEntity.getHealthcareAccess());
+ regionResponseBean.setInfrastructureScore(regionEntity.getInfrastructureScore());
+ regionResponseBean.setPriorityArea(regionEntity.getPriorityArea());
+ regionResponseBean.setUnemploymentRate(regionEntity.getUnemploymentRate());
+ regionResponseBean.setEducationLevel(regionEntity.getEducationLevel());
+ return regionResponseBean;
+ }
+
+ public RegionResponseBean updateRegion(Long id, RegionReq regionReq) {
+ log.info("Updating region with ID: {}", id);
+ RegionEntity existingRegion = getRegionById(id);
+ log.info("Current region details: {}", existingRegion);
+ log.info("New region details: {}", regionReq);
+
+ setIfUpdated(existingRegion::getRegionName, existingRegion::setRegionName, regionReq.getRegionName());
+ setIfUpdated(existingRegion::getDescription, existingRegion::setDescription, regionReq.getDescription());
+ setIfUpdated(existingRegion::getCountry, existingRegion::setCountry, regionReq.getCountry());
+ setIfUpdated(existingRegion::getStatus, existingRegion::setStatus, regionReq.getStatus());
+ setIfUpdated(existingRegion::getPriorityArea, existingRegion::setPriorityArea, regionReq.getPriorityArea());
+ setIfUpdated(existingRegion::getPopulation, existingRegion::setPopulation, regionReq.getPopulation());
+ setIfUpdated(existingRegion::getAreaSize, existingRegion::setAreaSize, regionReq.getAreaSize());
+ setIfUpdated(existingRegion::getGdp, existingRegion::setGdp, regionReq.getGdp());
+ setIfUpdated(existingRegion::getUnemploymentRate, existingRegion::setUnemploymentRate, regionReq.getUnemploymentRate());
+ setIfUpdated(existingRegion::getInfrastructureScore, existingRegion::setInfrastructureScore, regionReq.getInfrastructureScore());
+ setIfUpdated(existingRegion::getEducationLevel, existingRegion::setEducationLevel, regionReq.getEducationLevel());
+ setIfUpdated(existingRegion::getHealthcareAccess, existingRegion::setHealthcareAccess, regionReq.getHealthcareAccess());
+ setIfUpdated(existingRegion::getEnvironmentalScore, existingRegion::setEnvironmentalScore, regionReq.getEnvironmentalScore());
+
+ existingRegion = regionRepository.save(existingRegion);
+
+ log.info("Region updated with ID: {}", existingRegion.getId());
+ return Utils.convertObject(existingRegion, RegionResponseBean.class);
+ }
+
+ public RegionEntity getRegionById(Long id) {
+ log.info("Fetching region with ID: {}", id);
+ RegionEntity regionEntity = regionRepository.findById(id)
+ .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.REGION_NOT_FOUND_MSG)));
+ log.info("Region found: {}", regionEntity);
+ return regionEntity;
+ }
+
+ public void deleteById(Long id) {
+ log.info("Deleting region with ID: {}", id);
+ regionRepository.findById(id)
+ .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.REGION_NOT_FOUND_MSG)));
+ regionRepository.deleteById(id);
+ log.info("Region deleted with ID: {}", id);
+ }
+
+ public List getAllRegions() {
+ log.info("Fetching all regions");
+ List regions = regionRepository.findAll()
+ .stream()
+ .map(regionEntity -> Utils.convertObject(regionEntity, RegionResponseBean.class))
+ .collect(Collectors.toList());
+ log.info("Total regions found: {}", regions.size());
+ return regions;
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/dao/RoleDao.java b/src/main/java/net/gepafin/tendermanagement/dao/RoleDao.java
new file mode 100644
index 00000000..e7f4c5f9
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/dao/RoleDao.java
@@ -0,0 +1,110 @@
+package net.gepafin.tendermanagement.dao;
+
+import net.gepafin.tendermanagement.config.Translator;
+import net.gepafin.tendermanagement.constants.GepafinConstant;
+import net.gepafin.tendermanagement.entities.RoleEntity;
+import net.gepafin.tendermanagement.model.request.RoleReq;
+import net.gepafin.tendermanagement.model.response.RegionResponseBean;
+import net.gepafin.tendermanagement.model.response.RoleResponseBean;
+import net.gepafin.tendermanagement.repositories.RoleRepository;
+import net.gepafin.tendermanagement.service.RegionService;
+import net.gepafin.tendermanagement.util.Utils;
+import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException;
+import net.gepafin.tendermanagement.web.rest.api.errors.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static net.gepafin.tendermanagement.util.ObjectUtils.setIfUpdated;
+
+@Component
+public class RoleDao {
+ private final Logger log = LoggerFactory.getLogger(RoleDao.class);
+
+ @Autowired
+ private RoleRepository roleRepository;
+
+ @Autowired
+ private RegionService regionService;
+
+ @Autowired
+ private RegionDao regionDao;
+
+ public RoleResponseBean createRole(RoleReq roleReq) {
+ log.info("Creating new role with details: {}", roleReq);
+ RoleEntity roleEntity = convertRoleRequestToRoleEntity(roleReq);
+ roleEntity = roleRepository.save(roleEntity);
+ log.info("Role created with ID: {}", roleEntity.getId());
+ return convertRoleEntityToRoleResponse(roleEntity);
+ }
+
+ private RoleEntity convertRoleRequestToRoleEntity(RoleReq roleReq) {
+ RoleEntity roleEntity = new RoleEntity();
+ roleEntity.setRoleName(roleReq.getRoleName());
+ roleEntity.setPermissions(roleReq.getPermissions());
+ roleEntity.setDescription(roleReq.getDescription());
+ roleEntity.setRegion(regionService.getRegionById(roleReq.getRegionId()));
+ return roleEntity;
+ }
+
+ public RoleResponseBean convertRoleEntityToRoleResponse(RoleEntity roleEntity) {
+ RoleResponseBean roleResponseBean = new RoleResponseBean();
+ roleResponseBean.setId(roleEntity.getId());
+ roleResponseBean.setCreatedDate(roleEntity.getCreatedDate());
+ roleResponseBean.setUpdatedDate(roleEntity.getUpdatedDate());
+ roleResponseBean.setRoleName(roleEntity.getRoleName());
+ roleResponseBean.setDescription(roleEntity.getDescription());
+ roleResponseBean.setPermissions(roleEntity.getPermissions());
+ RegionResponseBean regionResponseBean = regionDao.convertRegionEntityToRegionResponse(roleEntity.getRegion());
+ roleResponseBean.setRegion(regionResponseBean);
+ return roleResponseBean;
+ }
+
+ public RoleResponseBean updateRole(Long id, RoleReq roleReq) {
+ log.info("Updating role with ID: {}", id);
+ RoleEntity existingRole = getRoleById(id);
+
+ // Log changes before update
+ log.info("Current role details: {}", existingRole);
+ log.info("New role details: {}", roleReq);
+
+ setIfUpdated(existingRole::getRoleName, existingRole::setRoleName, roleReq.getRoleName());
+ setIfUpdated(existingRole::getDescription, existingRole::setDescription, roleReq.getDescription());
+ setIfUpdated(existingRole::getPermissions, existingRole::setPermissions, roleReq.getPermissions());
+
+ existingRole = roleRepository.save(existingRole);
+
+ log.info("Role updated with ID: {}", existingRole.getId());
+ return Utils.convertObject(existingRole, RoleResponseBean.class);
+ }
+
+ public RoleEntity getRoleById(Long id) {
+ log.info("Fetching role with ID: {}", id);
+ RoleEntity roleEntity = roleRepository.findById(id)
+ .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.ROLE_NOT_FOUND)));
+ log.info("Role found: {}", roleEntity);
+ return roleEntity;
+ }
+
+ public void deleteById(Long id) {
+ log.info("Deleting role with ID: {}", id);
+ roleRepository.findById(id)
+ .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.ROLE_NOT_FOUND)));
+ roleRepository.deleteById(id);
+ log.info("Role deleted with ID: {}", id);
+ }
+
+ public List getAllRoles() {
+ log.info("Fetching all roles");
+ List roles = roleRepository.findAll()
+ .stream()
+ .map(roleEntity -> Utils.convertObject(roleEntity, RoleResponseBean.class))
+ .collect(Collectors.toList());
+ log.info("Total roles found: {}", roles.size());
+ return roles;
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java
new file mode 100644
index 00000000..b2fd8190
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java
@@ -0,0 +1,145 @@
+package net.gepafin.tendermanagement.dao;
+
+import net.gepafin.tendermanagement.config.Translator;
+import net.gepafin.tendermanagement.constants.GepafinConstant;
+import net.gepafin.tendermanagement.entities.RoleEntity;
+import net.gepafin.tendermanagement.entities.UserEntity;
+import net.gepafin.tendermanagement.model.request.LoginReq;
+import net.gepafin.tendermanagement.model.request.UpdateUserReq;
+import net.gepafin.tendermanagement.model.request.UserReq;
+import net.gepafin.tendermanagement.model.response.RoleResponseBean;
+import net.gepafin.tendermanagement.model.response.UserResponseBean;
+import net.gepafin.tendermanagement.model.util.JWTToken;
+import net.gepafin.tendermanagement.repositories.UserRepository;
+import net.gepafin.tendermanagement.service.RoleService;
+import net.gepafin.tendermanagement.service.impl.AuthenticationService;
+import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException;
+import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException;
+import net.gepafin.tendermanagement.web.rest.api.errors.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Repository;
+
+import static net.gepafin.tendermanagement.util.ObjectUtils.setIfUpdated;
+
+@Repository
+public class UserDao {
+
+ private final Logger log = LoggerFactory.getLogger(UserDao.class);
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private AuthenticationService authService;
+
+ @Autowired
+ private RoleService roleService;
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Autowired
+ private RoleDao roleDao;
+
+ public UserResponseBean createUser(UserReq userReq) {
+ log.info("Creating user with email: {}", userReq.getEmail());
+ if (userRepository.existsByEmail(userReq.getEmail())) {
+ log.error("User creation failed: Email {} already exists", userReq.getEmail());
+ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.EMAIL_ALREADY_EXISTS));
+ }
+ if (!userReq.getPassword().equals(userReq.getConfPassword())) {
+ log.error("User creation failed: Passwords do not match for email {}", userReq.getEmail());
+ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PASSWORD_DOESNT_MATCH));
+ }
+ if (userReq.getPassword().length() < 8) {
+ log.error("User creation failed: Password length is less than 8 characters for email {}", userReq.getEmail());
+ throw new CustomValidationException(Status.VALIDATION_ERROR, Translator.toLocale(GepafinConstant.PASSWORD_MIN_LEN));
+ }
+ UserEntity userEntity = convertUserRequestToUserEntity(userReq);
+ userEntity = userRepository.save(userEntity);
+ log.info("User created with ID: {}", userEntity.getId());
+ return convertUserEntityToUserResponse(userEntity);
+ }
+
+ public UserResponseBean updateUser(Long userId, UpdateUserReq userReq) {
+ log.info("Updating user with ID: {}", userId);
+ UserEntity userEntity = userRepository.findById(userId)
+ .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.REGION_NOT_FOUND_MSG)));
+ log.info("Current user details: {}", userEntity);
+ log.info("New user details: {}", userReq);
+
+ setIfUpdated(userEntity::getStatus, userEntity::setStatus, userReq.getStatus());
+ setIfUpdated(userEntity::getFirstName, userEntity::setFirstName, userReq.getFirstName());
+ setIfUpdated(userEntity::getLastName, userEntity::setLastName, userReq.getLastName());
+ setIfUpdated(userEntity::getOrganization, userEntity::setOrganization, userReq.getOrganization());
+ setIfUpdated(userEntity::getAddress, userEntity::setAddress, userReq.getAddress());
+ setIfUpdated(userEntity::getPhoneNumber, userEntity::setPhoneNumber, userReq.getPhoneNumber());
+ if (userReq.getRoleId() != null) {
+ RoleEntity roleEntity = roleService.getRoleById(userReq.getRoleId());
+ setIfUpdated(userEntity::getRoleEntity, userEntity::setRoleEntity, roleEntity);
+ }
+ userEntity = userRepository.save(userEntity);
+ log.info("User updated with ID: {}", userEntity.getId());
+ return convertUserEntityToUserResponse(userEntity);
+ }
+
+ private UserEntity convertUserRequestToUserEntity(UserReq userReq) {
+ UserEntity userEntity = new UserEntity();
+ userEntity.setPassword(passwordEncoder.encode(userReq.getPassword()));
+ userEntity.setEmail(userReq.getEmail());
+ userEntity.setFirstName(userReq.getFirstName());
+ userEntity.setStatus(userReq.getStatus());
+ userEntity.setLastName(userReq.getLastName());
+ userEntity.setOrganization(userReq.getOrganization());
+ userEntity.setAddress(userReq.getAddress());
+ userEntity.setPhoneNumber(userReq.getPhoneNumber());
+ userEntity.setRoleEntity(roleService.getRoleById(userReq.getRoleId()));
+ return userEntity;
+ }
+
+ private UserResponseBean convertUserEntityToUserResponse(UserEntity userEntity) {
+ UserResponseBean userResponseBean = new UserResponseBean();
+ userResponseBean.setId(userEntity.getId());
+ userResponseBean.setCreatedDate(userEntity.getCreatedDate());
+ userResponseBean.setUpdatedDate(userEntity.getUpdatedDate());
+ userResponseBean.setEmail(userEntity.getEmail());
+ userResponseBean.setFirstName(userEntity.getFirstName());
+ userResponseBean.setLastName(userEntity.getLastName());
+ userResponseBean.setPhoneNumber(userEntity.getPhoneNumber());
+ userResponseBean.setOrganization(userEntity.getOrganization());
+ userResponseBean.setAddress(userEntity.getAddress());
+ userResponseBean.setCity(userEntity.getCity());
+ userResponseBean.setCountry(userEntity.getCountry());
+ userResponseBean.setStatus(userEntity.getStatus());
+ RoleResponseBean roleResponseBean = roleDao.convertRoleEntityToRoleResponse(userEntity.getRoleEntity());
+ userResponseBean.setRole(roleResponseBean);
+ userResponseBean.setLastLogin(userEntity.getLastLogin());
+ return userResponseBean;
+ }
+
+ public UserResponseBean getUserById(Long id) {
+ log.info("Fetching user with ID: {}", id);
+ UserEntity userEntity = userRepository.findById(id)
+ .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG)));
+ log.info("User found: {}", userEntity);
+ return convertUserEntityToUserResponse(userEntity);
+ }
+
+ public void deleteUser(Long id) {
+ log.info("Deleting user with ID: {}", id);
+ userRepository.findById(id)
+ .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG)));
+ userRepository.deleteById(id);
+ log.info("User deleted with ID: {}", id);
+ }
+
+ public JWTToken login(LoginReq loginReq) {
+ log.info("User login attempt for email: {}", loginReq.getEmail());
+ JWTToken jwtToken = authService.login(loginReq);
+ log.info("Login successful for email: {}", loginReq.getEmail());
+ return jwtToken;
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/BaseEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/BaseEntity.java
new file mode 100644
index 00000000..f8427719
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/entities/BaseEntity.java
@@ -0,0 +1,35 @@
+package net.gepafin.tendermanagement.entities;
+
+import jakarta.persistence.*;
+import lombok.Data;
+import net.gepafin.tendermanagement.util.DateTimeUtil;
+
+
+import java.time.LocalDateTime;
+
+@MappedSuperclass
+@Data
+public class BaseEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Column(name = "ID", unique = true)
+ private Long id;
+
+
+ @Column(name = "CREATED_DATE", updatable = false)
+ LocalDateTime createdDate;
+
+ @Column(name = "UPDATED_DATE")
+ LocalDateTime updatedDate;
+
+ @PrePersist
+ public void setCreatedDate() {
+ this.createdDate = DateTimeUtil.DateServerToUTC(LocalDateTime.now());
+ this.updatedDate = DateTimeUtil.DateServerToUTC(LocalDateTime.now());
+ }
+ @PreUpdate
+ public void setUpdatedDate() {
+ this.updatedDate = DateTimeUtil.DateServerToUTC(LocalDateTime.now());
+ }
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/CallEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/CallEntity.java
new file mode 100644
index 00000000..1ee48d6b
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/entities/CallEntity.java
@@ -0,0 +1,66 @@
+package net.gepafin.tendermanagement.entities;
+
+import jakarta.persistence.*;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "CALL")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class CallEntity extends BaseEntity {
+
+ @Column(name = "NAME", nullable = false, length = 255)
+ private String name;
+
+ @Column(name = "DESCRIPTION_SHORT", columnDefinition = "TEXT")
+ private String descriptionShort;
+
+ @Column(name = "DESCRIPTION_LONG", columnDefinition = "TEXT")
+ private String descriptionLong;
+
+ @Column(name = "START_DATE", nullable = false)
+ private LocalDateTime startDate;
+
+ @Column(name = "END_DATE", nullable = false)
+ private LocalDateTime endDate;
+
+ @Column(name = "STATUS", nullable = false, length = 255)
+ private String status;
+
+ @ManyToOne
+ @JoinColumn(name = "REGION_ID", nullable = false, foreignKey = @ForeignKey(name = "fk_region_call"))
+ private RegionEntity region;
+
+ @Column(name = "AMOUNT", nullable = false)
+ private BigDecimal amount;
+
+ @Column(name = "AMOUNT_MAX", nullable = false)
+ private BigDecimal amountMax;
+
+ @Column(name = "CONTACT_INFO", columnDefinition = "TEXT")
+ private String contactInfo;
+
+ @Column(name = "SUBMISSION_METHOD", columnDefinition = "TEXT")
+ private String submissionMethod;
+
+ @Column(name = "THRESHOLD", nullable = false)
+ private Integer threshold;
+
+ @Column(name="DOCUMENTATION_REQUESTED",columnDefinition = "TEXT")
+ private String documentation_requested;
+
+ @Column(name = "PRIORITY_AREA", columnDefinition = "TEXT")
+ private String priorityArea;
+
+ @Column(name = "CONFIDI")
+ private Boolean confidi;
+}
+
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/CallTargetAudienceChecklistEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/CallTargetAudienceChecklistEntity.java
new file mode 100644
index 00000000..be94ee59
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/entities/CallTargetAudienceChecklistEntity.java
@@ -0,0 +1,23 @@
+package net.gepafin.tendermanagement.entities;
+
+import jakarta.persistence.*;
+import lombok.Data;
+
+@Entity
+@Table(name = "CALL_TARGET_AUDIENCE_CHECKLIST")
+@Data
+public class CallTargetAudienceChecklistEntity extends BaseEntity{
+
+ @ManyToOne
+ @JoinColumn(name = "CALL_ID")
+ private CallEntity call;
+
+ @ManyToOne
+ @JoinColumn(name = "LOOKUP_DATA_ID")
+ private LookUpDataEntity lookupData;
+
+ @Column(name = "IS_VALIDATED")
+ private Boolean isValidated;
+
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/DocumentEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/DocumentEntity.java
new file mode 100644
index 00000000..5a15351c
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/entities/DocumentEntity.java
@@ -0,0 +1,31 @@
+package net.gepafin.tendermanagement.entities;
+
+import jakarta.persistence.*;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+
+@Entity
+@Table(name = "DOCUMENT")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class DocumentEntity extends BaseEntity{
+ @Column(name = "FILE_NAME", length = 255)
+ private String fileName;
+
+ @Column(name = "FILE_PATH", length = 255)
+ private String filePath;
+
+ @Column(name="TYPE")
+ private String type;
+
+ @ManyToOne
+ @JoinColumn(name = "CALL_ID")
+ private CallEntity call;
+
+ @Column(name = "DESCRIPTION", columnDefinition = "TEXT")
+ private String description;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/EvaluationCriteriaEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/EvaluationCriteriaEntity.java
new file mode 100644
index 00000000..539d9c30
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/entities/EvaluationCriteriaEntity.java
@@ -0,0 +1,30 @@
+package net.gepafin.tendermanagement.entities;
+import jakarta.persistence.*;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+
+
+@Entity
+@Table(name = "EVALUATION_CRITERIA")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class EvaluationCriteriaEntity extends BaseEntity {
+
+ @ManyToOne
+ @JoinColumn(name = "CALL_ID", nullable = false)
+ private CallEntity call;
+
+ @Column(name = "NAME", nullable = false, columnDefinition = "TEXT")
+ private String name;
+
+ @Column(name = "DESCRIPTION", columnDefinition = "TEXT")
+ private String description;
+
+ @Column(name = "SCORE", nullable = false)
+ private Integer score;
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/FaqEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/FaqEntity.java
new file mode 100644
index 00000000..aa521521
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/entities/FaqEntity.java
@@ -0,0 +1,46 @@
+package net.gepafin.tendermanagement.entities;
+
+import jakarta.persistence.*;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "FAQ")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class FaqEntity extends BaseEntity {
+
+ @ManyToOne
+ @JoinColumn(name = "CALL_ID", nullable = false)
+ private CallEntity call;
+
+ @ManyToOne
+ @JoinColumn(name = "USER_ID", nullable = false, foreignKey = @ForeignKey(name = "fk_user_faq"))
+ private UserEntity user;
+
+ @Column(name = "IS_VISIBLE", nullable = false)
+ private Boolean isVisible;
+
+ @Column(name = "QUESTION_SHORT", length = 255)
+ private String questionShort;
+
+ @Column(name = "QUESTION", columnDefinition = "TEXT")
+ private String question;
+
+ @Column(name = "RESPONSE_SHORT", length = 255)
+ private String responseShort;
+
+ @Column(name = "RESPONSE", columnDefinition = "TEXT")
+ private String response;
+
+ @Column(name = "RESPONSE_DATE")
+ private LocalDateTime responseDate;
+
+}
+
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/LookUpDataEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/LookUpDataEntity.java
new file mode 100644
index 00000000..41ca9ba7
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/entities/LookUpDataEntity.java
@@ -0,0 +1,37 @@
+package net.gepafin.tendermanagement.entities;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+import jakarta.persistence.*;
+import lombok.Data;
+
+@Entity
+@Table(name = "LOOKUP_DATA")
+@Data
+public class LookUpDataEntity extends BaseEntity{
+
+ @Column(name = "TITLE", length = 255, nullable = true)
+ private String title;
+
+ @Column(name = "TYPE", length = 255, nullable = false)
+ private String type;
+
+ @Column(name = "VALUE", columnDefinition = "TEXT", nullable = true)
+ private String value;
+
+ public enum LookUpDataTypeEnum {
+ CHECKLIST("CHECKLIST"),
+ AIMED_TO("AIMED_TO"),
+ EVALUATION_CRITERIA("EVALUATION_CRITERIA");
+
+ private String value;
+
+ LookUpDataTypeEnum(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/RegionEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/RegionEntity.java
new file mode 100644
index 00000000..386b9787
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/entities/RegionEntity.java
@@ -0,0 +1,56 @@
+package net.gepafin.tendermanagement.entities;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.Table;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Entity
+@Table(name = "REGION")
+@Getter
+@Setter
+public class RegionEntity extends BaseEntity {
+
+ @Column(name = "REGION_NAME", length = 255, nullable = true)
+ private String regionName;
+
+ @Column(name = "DESCRIPTION", length = 255, nullable = true)
+ private String description;
+
+ @Column(name = "COUNTRY", length = 50, nullable = true)
+ private String country;
+
+ @Column(name = "STATUS", length = 30, nullable = true)
+ private String status;
+
+ @Column(name = "PRIORITY_AREA", length = 255, nullable = true)
+ private String priorityArea;
+
+ @Column(name = "POPULATION", nullable = true)
+ private Long population;
+
+ @Column(name = "AREA_SIZE", nullable = true)
+ private BigDecimal areaSize;
+
+ @Column(name = "GDP", nullable = true)
+ private BigDecimal gdp;
+
+ @Column(name = "UNEMPLOYMENT_RATE", nullable = true)
+ private BigDecimal unemploymentRate;
+
+ @Column(name = "INFRASTRUCTURE_SCORE", nullable = true)
+ private BigDecimal infrastructureScore;
+
+ @Column(name = "EDUCATION_LEVEL", nullable = true)
+ private BigDecimal educationLevel;
+
+ @Column(name = "HEALTHCARE_ACCESS", nullable = true)
+ private BigDecimal healthcareAccess;
+
+ @Column(name = "ENVIRONMENTAL_SCORE", nullable = true)
+ private BigDecimal environmentalScore;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/RoleEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/RoleEntity.java
new file mode 100644
index 00000000..ff741702
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/entities/RoleEntity.java
@@ -0,0 +1,26 @@
+package net.gepafin.tendermanagement.entities;
+
+import jakarta.persistence.*;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Entity
+@Table(name = "ROLE")
+@Getter
+@Setter
+public class RoleEntity extends BaseEntity {
+
+ @Column(name = "ROLE_NAME", length = 50, nullable = true)
+ private String roleName;
+
+ @Column(name = "DESCRIPTION", length = 255, nullable = true)
+ private String description;
+
+ @Column(name = "PERMISSIONS", length = 255, nullable = true)
+ private String permissions;
+ @ManyToOne
+ @JoinColumn(name = "REGION_ID", nullable = true)
+ private RegionEntity region;
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/entities/UserEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/UserEntity.java
new file mode 100644
index 00000000..719f9a5b
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/entities/UserEntity.java
@@ -0,0 +1,76 @@
+package net.gepafin.tendermanagement.entities;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+import jakarta.persistence.*;
+import jakarta.validation.constraints.Email;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "GEPAFIN_USER")
+@Getter
+@Setter
+public class UserEntity extends BaseEntity {
+
+ @Column(name = "PASSWORD", columnDefinition = "TEXT",nullable = false)
+ @JsonIgnore
+ private String password;
+
+ @Email
+ @Column(name = "EMAIL", length = 255, unique = true, nullable = false)
+ private String email;
+
+ @ManyToOne
+ @JoinColumn(name = "ROLE_ID")
+ @JsonIgnore
+ private RoleEntity roleEntity;
+
+
+ @Column(name = "LAST_LOGIN")
+ private LocalDateTime lastLogin;
+
+ @Column(name = "STATUS", length = 30, nullable = true)
+ private String status;
+
+ @Column(name = "FIRST_NAME", length = 50, nullable = true)
+ private String firstName;
+
+ @Column(name = "LAST_NAME", length = 50, nullable = true)
+ private String lastName;
+
+ @Column(name = "PHONE_NUMBER", length = 15, nullable = true)
+ private String phoneNumber;
+
+ @Column(name = "ORGANIZATION", length = 255, nullable = true)
+ private String organization;
+
+ @Column(name = "ADDRESS", length = 255, nullable = true)
+ private String address;
+
+ @Column(name = "CITY", length = 50, nullable = true)
+ private String city;
+
+ @Column(name = "COUNTRY", length = 50, nullable = true)
+ private String country;
+
+ public enum UserStatusEnum {
+ ACTIVE("ACTIVE"),
+ INACTIVE("INACTIVE");
+
+ private String value;
+
+ UserStatusEnum(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/enums/CallTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/CallTypeEnum.java
new file mode 100644
index 00000000..46b88869
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/enums/CallTypeEnum.java
@@ -0,0 +1,21 @@
+package net.gepafin.tendermanagement.enums;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+public enum CallTypeEnum {
+
+ DRAFT("DRAFT"),
+ PUBLISH("PUBLISH"),
+ EXPIRE("EXPIRE");
+
+ private String value;
+
+ CallTypeEnum(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/enums/DocumentTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/DocumentTypeEnum.java
new file mode 100644
index 00000000..d5275796
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/enums/DocumentTypeEnum.java
@@ -0,0 +1,20 @@
+package net.gepafin.tendermanagement.enums;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+public enum DocumentTypeEnum {
+
+ DOCUMENT("DOCUMENT"),
+ IMAGES("IMAGES");
+
+ private String value;
+
+ DocumentTypeEnum(String value) {
+ this.value = value;
+ }
+
+ @JsonValue
+ public String getValue() {
+ return value;
+ }
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/BaseBean.java b/src/main/java/net/gepafin/tendermanagement/model/BaseBean.java
new file mode 100644
index 00000000..49eb0d41
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/BaseBean.java
@@ -0,0 +1,16 @@
+package net.gepafin.tendermanagement.model;
+
+import java.time.LocalDateTime;
+
+import lombok.Data;
+
+@Data
+public class BaseBean {
+
+ private Long id;
+
+ private LocalDateTime createdDate;
+
+ private LocalDateTime updatedDate;
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/User.java b/src/main/java/net/gepafin/tendermanagement/model/User.java
deleted file mode 100644
index 8b3fe662..00000000
--- a/src/main/java/net/gepafin/tendermanagement/model/User.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package net.gepafin.tendermanagement.model;
-
-public class User {
- private Long id;
- private String name;
- private String email;
-
- public User() {}
-
- public User(Long id, String name, String email) {
- this.id = id;
- this.name = name;
- this.email = email;
- }
- public Long getId() {
- return id;
- }
-
- public void setId(Long id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getEmail() {
- return email;
- }
-
- public void setEmail(String email) {
- this.email = email;
- }
-}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/CreateCallRequest.java b/src/main/java/net/gepafin/tendermanagement/model/request/CreateCallRequest.java
new file mode 100644
index 00000000..80d828fc
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/CreateCallRequest.java
@@ -0,0 +1,49 @@
+package net.gepafin.tendermanagement.model.request;
+
+import lombok.Data;
+import net.gepafin.tendermanagement.enums.CallTypeEnum;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Data
+public class CreateCallRequest {
+
+ private String name;
+
+ private String descriptionShort;
+
+ private String descriptionLong;
+
+ private LocalDateTime startDate;
+
+ private LocalDateTime endDate;
+
+ private Long regionId;
+
+ private BigDecimal amount;
+
+ private BigDecimal amountMax;
+
+ private List aimedTo;
+
+ private String documentationRequested;
+
+ private Integer threshold;
+
+ private Boolean Confidi;
+
+ List criteria;
+
+ private List faq;
+
+ private List checkList;
+
+ private List docs;
+
+ private List images;
+
+ private CallTypeEnum status;
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/DocumentReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/DocumentReq.java
new file mode 100644
index 00000000..a2f65bba
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/DocumentReq.java
@@ -0,0 +1,11 @@
+package net.gepafin.tendermanagement.model.request;
+
+import lombok.Data;
+
+@Data
+public class DocumentReq {
+
+ private Long id;
+ private String url;
+ private String fileName;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaReq.java
new file mode 100644
index 00000000..a8b90e1c
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/EvaluationCriteriaReq.java
@@ -0,0 +1,11 @@
+package net.gepafin.tendermanagement.model.request;
+
+import lombok.Data;
+
+@Data
+public class EvaluationCriteriaReq {
+
+ private String name;
+ private String value;
+ private Integer score;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/FaqReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/FaqReq.java
new file mode 100644
index 00000000..de9f5225
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/FaqReq.java
@@ -0,0 +1,13 @@
+package net.gepafin.tendermanagement.model.request;
+
+import lombok.Data;
+
+@Data
+public class FaqReq {
+
+ private Boolean isVisible;
+ private String questionShort;
+ private String question;
+ private String responseShort;
+ private String response;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/LoginReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/LoginReq.java
new file mode 100644
index 00000000..d337d231
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/LoginReq.java
@@ -0,0 +1,18 @@
+package net.gepafin.tendermanagement.model.request;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class LoginReq {
+ @NotBlank(message = "{email.not.blank}")
+ @Email(message = "{email.invalid}")
+ private String email;
+ @NotEmpty
+ private String password;
+ private Boolean rememberMe;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/LookUpDataReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/LookUpDataReq.java
new file mode 100644
index 00000000..18b847b4
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/LookUpDataReq.java
@@ -0,0 +1,11 @@
+package net.gepafin.tendermanagement.model.request;
+
+import lombok.Data;
+
+@Data
+public class LookUpDataReq {
+
+ private Long lookUpDataId;
+
+ private String value;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/RegionReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/RegionReq.java
new file mode 100644
index 00000000..fae42f3c
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/RegionReq.java
@@ -0,0 +1,39 @@
+package net.gepafin.tendermanagement.model.request;
+
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Getter
+@Setter
+public class RegionReq {
+
+ private String regionName;
+
+ private String description;
+
+ private String country;
+
+ private String status;
+
+ private String priorityArea;
+
+ private Long population;
+
+ private BigDecimal areaSize;
+
+ private BigDecimal gdp;
+
+ private BigDecimal unemploymentRate;
+
+ private BigDecimal infrastructureScore;
+
+ private BigDecimal educationLevel;
+
+ private BigDecimal healthcareAccess;
+
+ private BigDecimal environmentalScore;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/RoleReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/RoleReq.java
new file mode 100644
index 00000000..1e4ec6f4
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/RoleReq.java
@@ -0,0 +1,27 @@
+package net.gepafin.tendermanagement.model.request;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class RoleReq {
+
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ private Long id;
+
+ private String roleName;
+
+ private String description;
+
+ private String permissions;
+
+ private String status;
+
+ private Long regionId;
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/UpdateRegionReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/UpdateRegionReq.java
new file mode 100644
index 00000000..8d32dc83
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/UpdateRegionReq.java
@@ -0,0 +1,35 @@
+package net.gepafin.tendermanagement.model.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class UpdateRegionReq {
+ private String regionName;
+
+ private String description;
+
+ private String country;
+
+ private String status;
+
+ private String priorityArea;
+
+ private Long population;
+
+ private Double areaSize;
+
+ private Double gdp;
+
+ private Double unemploymentRate;
+
+ private Double infrastructureScore;
+
+ private Double educationLevel;
+
+ private Double healthcareAccess;
+
+ private Double environmentalScore;
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/UpdateUserReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/UpdateUserReq.java
new file mode 100644
index 00000000..63eb2b89
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/UpdateUserReq.java
@@ -0,0 +1,21 @@
+package net.gepafin.tendermanagement.model.request;
+
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class UpdateUserReq {
+
+ private String firstName;
+ private String lastName;
+ private String phoneNumber;
+ private Long roleId;
+ private String organization;
+ private String address;
+ private String city;
+ private String status;
+ private String country;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/UserReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/UserReq.java
new file mode 100644
index 00000000..97a59438
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/request/UserReq.java
@@ -0,0 +1,40 @@
+package net.gepafin.tendermanagement.model.request;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class UserReq {
+
+ @NotBlank
+ @Email
+ private String email;
+ @NotEmpty
+ private String password;
+ @NotEmpty
+ private String confPassword;
+
+ private String firstName;
+
+ private String lastName;
+
+ private String phoneNumber;
+ @NotNull
+ private Long roleId;
+
+ private String organization;
+
+ private String address;
+
+ private String city;
+
+ private String country;
+
+ private String status;
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/CallResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/CallResponseBean.java
new file mode 100644
index 00000000..0efff823
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/CallResponseBean.java
@@ -0,0 +1,42 @@
+package net.gepafin.tendermanagement.model.response;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Data
+public class CallResponseBean {
+
+
+ private Long id;
+
+ private String title;
+
+ private String description;
+
+ private LocalDateTime startDate;
+
+ private LocalDateTime endDate;
+
+ private String status;
+
+ private RegionResponseBean region;
+
+ private BigDecimal fundingAmount;
+
+ private String contactInfo;
+
+ private String submissionMethod;
+
+ private Integer totalScore;
+
+ private Integer minimumScore;
+
+ private String priorityArea;
+
+ private LocalDateTime createdDate;
+
+ private LocalDateTime updatedDate;
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/CreateCallResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/CreateCallResponseBean.java
new file mode 100644
index 00000000..b913f85b
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/CreateCallResponseBean.java
@@ -0,0 +1,60 @@
+package net.gepafin.tendermanagement.model.response;
+
+import lombok.Data;
+import net.gepafin.tendermanagement.enums.CallTypeEnum;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Data
+public class CreateCallResponseBean {
+
+ private Long id;
+
+ private String name;
+
+ private String descriptionShort;
+
+ private String descriptionLong;
+
+ private List dates;
+
+ private CallTypeEnum status;
+
+ private Long regionId;
+
+ private BigDecimal amount;
+
+ private BigDecimal amountMax;
+
+ private String contactInfo;
+
+ private String submissionMethod;
+
+ private Integer threshold;
+
+ private String priorityArea;
+
+ private String documentationReqested;
+
+ private LocalDateTime createdDate;
+
+ private LocalDateTime updatedDate;
+
+ private List aimedTo;
+
+ private List criteria;
+
+ private List docs;
+
+ private List faq;
+
+ private List images;
+
+ private List checkList;
+
+}
+
+
+
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/DocumentResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/DocumentResponseBean.java
new file mode 100644
index 00000000..82aa9b9a
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/DocumentResponseBean.java
@@ -0,0 +1,21 @@
+package net.gepafin.tendermanagement.model.response;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class DocumentResponseBean {
+
+ private Long id;
+
+ private String name;
+
+ private String filePath;
+
+ private String description;
+
+ private LocalDateTime createdDate;
+
+ private LocalDateTime updatedDate;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/EvaluationCriteriaResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/EvaluationCriteriaResponseBean.java
new file mode 100644
index 00000000..29cfed21
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/EvaluationCriteriaResponseBean.java
@@ -0,0 +1,21 @@
+package net.gepafin.tendermanagement.model.response;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class EvaluationCriteriaResponseBean {
+
+ private Long id;
+
+ private String name;
+
+ private String description;
+
+ private Integer score;
+
+ private LocalDateTime createdDate;
+
+ private LocalDateTime updatedDate;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/FaqResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/FaqResponseBean.java
new file mode 100644
index 00000000..fdc4be63
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/FaqResponseBean.java
@@ -0,0 +1,30 @@
+package net.gepafin.tendermanagement.model.response;
+
+import lombok.Data;
+
+
+import java.time.LocalDateTime;
+
+@Data
+public class FaqResponseBean {
+
+ private Long id;
+
+ private Long userId;
+
+ private Boolean isVisible;
+
+ private String questionShort;
+
+ private String question;
+
+ private String responseShort;
+
+ private String response;
+
+ private LocalDateTime responseDate;
+
+ private LocalDateTime createdDate;
+
+ private LocalDateTime updatedDate;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/LoginResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/LoginResponse.java
new file mode 100644
index 00000000..64af6b1a
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/LoginResponse.java
@@ -0,0 +1,42 @@
+package net.gepafin.tendermanagement.model.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class LoginResponse {
+ private Long id;
+
+ private String email;
+
+ private String firstName;
+
+ private String lastName;
+
+ private RoleResponseBean role;
+
+ private String phoneNumber;
+
+ private String organization;
+
+ private String address;
+
+ private String city;
+
+ private String country;
+
+ private String status;
+
+ private LocalDateTime lastLogin;
+
+ private LocalDateTime createdDate;
+
+ private LocalDateTime updatedDate;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/LookUpDataResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/LookUpDataResponse.java
new file mode 100644
index 00000000..27811e63
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/LookUpDataResponse.java
@@ -0,0 +1,22 @@
+package net.gepafin.tendermanagement.model.response;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+public class LookUpDataResponse {
+
+ private Long id;
+
+ private Long lookUpDataId;
+
+ private String title;
+
+ private String value;
+
+ private LocalDateTime createdDate;
+
+ private LocalDateTime updatedDate;
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/RegionResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/RegionResponseBean.java
new file mode 100644
index 00000000..55182822
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/RegionResponseBean.java
@@ -0,0 +1,26 @@
+package net.gepafin.tendermanagement.model.response;
+
+import lombok.Getter;
+import lombok.Setter;
+import net.gepafin.tendermanagement.model.BaseBean;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+public class RegionResponseBean extends BaseBean {
+ private String regionName;
+ private String description;
+ private String country;
+ private String status;
+ private String priorityArea;
+ private Long population;
+ private BigDecimal areaSize;
+ private BigDecimal gdp;
+ private BigDecimal unemploymentRate;
+ private BigDecimal infrastructureScore;
+ private BigDecimal educationLevel;
+ private BigDecimal healthcareAccess;
+ private BigDecimal environmentalScore;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/RoleResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/RoleResponseBean.java
new file mode 100644
index 00000000..d5d579e5
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/RoleResponseBean.java
@@ -0,0 +1,17 @@
+package net.gepafin.tendermanagement.model.response;
+
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+import net.gepafin.tendermanagement.entities.RegionEntity;
+import net.gepafin.tendermanagement.model.BaseBean;
+
+import java.time.LocalDateTime;
+
+@Data
+public class RoleResponseBean extends BaseBean {
+ private String roleName;
+ private String description;
+ private String permissions;
+ private RegionResponseBean region;
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java
new file mode 100644
index 00000000..1dcaa944
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/response/UserResponseBean.java
@@ -0,0 +1,39 @@
+package net.gepafin.tendermanagement.model.response;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+import net.gepafin.tendermanagement.entities.RoleEntity;
+import net.gepafin.tendermanagement.model.BaseBean;
+
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+public class UserResponseBean extends BaseBean {
+
+ private String email;
+
+ private String firstName;
+
+ private String lastName;
+
+ private RoleResponseBean role;
+
+ private String phoneNumber;
+
+ private String organization;
+
+ private String address;
+
+ private String city;
+
+ private String country;
+
+ private String status;
+
+ private LocalDateTime lastLogin;
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java b/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java
new file mode 100644
index 00000000..a57b7d59
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/util/JWTToken.java
@@ -0,0 +1,24 @@
+package net.gepafin.tendermanagement.model.util;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import lombok.Data;
+import net.gepafin.tendermanagement.model.response.LoginResponse;
+
+/**
+ * JWTToken
+ */
+@Data
+public class JWTToken {
+ @JsonProperty("token")
+ private String token;
+
+ @JsonProperty("user")
+ private LoginResponse loginResponse;
+ public JWTToken(String token, LoginResponse loginResponse) {
+ this.token = token;
+ this.loginResponse = loginResponse;
+ }
+
+}
+
diff --git a/src/main/java/net/gepafin/tendermanagement/model/util/Response.java b/src/main/java/net/gepafin/tendermanagement/model/util/Response.java
new file mode 100644
index 00000000..7d0c768d
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/model/util/Response.java
@@ -0,0 +1,29 @@
+package net.gepafin.tendermanagement.model.util;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import net.gepafin.tendermanagement.web.rest.api.errors.Status;
+
+import java.io.Serializable;
+
+/**
+ * A generic response class used for API responses.
+ *
+ * @param the type of the response data
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class Response implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private T data; // The response data
+ private Status status; // The status of the response
+ private String message; // Additional message or error description
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/CallRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/CallRepository.java
new file mode 100644
index 00000000..ef6e144f
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/CallRepository.java
@@ -0,0 +1,8 @@
+package net.gepafin.tendermanagement.repositories;
+import net.gepafin.tendermanagement.entities.CallEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface CallRepository extends JpaRepository {
+
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/CallTargetAudienceChecklistRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/CallTargetAudienceChecklistRepository.java
new file mode 100644
index 00000000..fe70f982
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/CallTargetAudienceChecklistRepository.java
@@ -0,0 +1,7 @@
+package net.gepafin.tendermanagement.repositories;
+
+import net.gepafin.tendermanagement.entities.CallTargetAudienceChecklistEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface CallTargetAudienceChecklistRepository extends JpaRepository {
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java
new file mode 100644
index 00000000..d8d4f07a
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java
@@ -0,0 +1,9 @@
+package net.gepafin.tendermanagement.repositories;
+import net.gepafin.tendermanagement.entities.DocumentEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface DocumentRepository extends JpaRepository {
+
+ DocumentEntity findById(Long id);
+}
+
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/EvaluationCriteriaRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/EvaluationCriteriaRepository.java
new file mode 100644
index 00000000..057566a6
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/EvaluationCriteriaRepository.java
@@ -0,0 +1,7 @@
+package net.gepafin.tendermanagement.repositories;
+
+import net.gepafin.tendermanagement.entities.EvaluationCriteriaEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface EvaluationCriteriaRepository extends JpaRepository {
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/FaqRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/FaqRepository.java
new file mode 100644
index 00000000..9453ade3
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/FaqRepository.java
@@ -0,0 +1,7 @@
+package net.gepafin.tendermanagement.repositories;
+
+import net.gepafin.tendermanagement.entities.FaqEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface FaqRepository extends JpaRepository {
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/LookUpDataRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/LookUpDataRepository.java
new file mode 100644
index 00000000..e4ffb08a
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/LookUpDataRepository.java
@@ -0,0 +1,7 @@
+package net.gepafin.tendermanagement.repositories;
+
+import net.gepafin.tendermanagement.entities.LookUpDataEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface LookUpDataRepository extends JpaRepository {
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/RegionRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/RegionRepository.java
new file mode 100644
index 00000000..87dfdfa0
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/RegionRepository.java
@@ -0,0 +1,9 @@
+package net.gepafin.tendermanagement.repositories;
+
+import net.gepafin.tendermanagement.entities.RegionEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface RegionRepository extends JpaRepository {
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/RoleRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/RoleRepository.java
new file mode 100644
index 00000000..e009e6a3
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/RoleRepository.java
@@ -0,0 +1,9 @@
+package net.gepafin.tendermanagement.repositories;
+
+import net.gepafin.tendermanagement.entities.RoleEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface RoleRepository extends JpaRepository {
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/UserRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/UserRepository.java
new file mode 100644
index 00000000..dc0aad37
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/repositories/UserRepository.java
@@ -0,0 +1,11 @@
+package net.gepafin.tendermanagement.repositories;
+
+import net.gepafin.tendermanagement.entities.UserEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.Optional;
+
+public interface UserRepository extends JpaRepository {
+ UserEntity findByEmail(String email);
+ boolean existsByEmail(String email);
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java b/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java
new file mode 100644
index 00000000..188d131a
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java
@@ -0,0 +1,20 @@
+package net.gepafin.tendermanagement.service;
+
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+@Component
+public interface AmazonS3Service {
+
+
+ public String upload(String fileName,
+ MultipartFile file) throws IOException;
+
+ public Boolean delete(String bucketName ,String fileName);
+
+ InputStream getFile(String filePath) throws IOException;
+}
\ No newline at end of file
diff --git a/src/main/java/net/gepafin/tendermanagement/service/CallService.java b/src/main/java/net/gepafin/tendermanagement/service/CallService.java
new file mode 100644
index 00000000..40dfd65f
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/service/CallService.java
@@ -0,0 +1,11 @@
+package net.gepafin.tendermanagement.service;
+
+import jakarta.servlet.http.HttpServletRequest;
+import net.gepafin.tendermanagement.model.request.CreateCallRequest;
+import net.gepafin.tendermanagement.model.response.CreateCallResponseBean;
+
+public interface CallService {
+
+ CreateCallResponseBean createCall(HttpServletRequest request, CreateCallRequest createCallRequest);
+
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/service/DocumentService.java b/src/main/java/net/gepafin/tendermanagement/service/DocumentService.java
new file mode 100644
index 00000000..806d81cc
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/service/DocumentService.java
@@ -0,0 +1,14 @@
+package net.gepafin.tendermanagement.service;
+
+import net.gepafin.tendermanagement.enums.DocumentTypeEnum;
+import net.gepafin.tendermanagement.model.response.DocumentResponseBean;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+public interface DocumentService {
+
+ public List uploadFile(List files, DocumentTypeEnum fileType);
+
+ public Void deleteFile(Long documentId);
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/service/RegionService.java b/src/main/java/net/gepafin/tendermanagement/service/RegionService.java
new file mode 100644
index 00000000..2288fa17
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/service/RegionService.java
@@ -0,0 +1,22 @@
+package net.gepafin.tendermanagement.service;
+
+import net.gepafin.tendermanagement.entities.RegionEntity;
+import net.gepafin.tendermanagement.model.request.RegionReq;
+import net.gepafin.tendermanagement.model.response.RegionResponseBean;
+import net.gepafin.tendermanagement.model.request.UpdateRegionReq;
+
+import java.util.List;
+
+
+public interface RegionService {
+
+ RegionResponseBean createRegion(RegionReq regionReq);
+
+ RegionResponseBean updateRegion(Long regionId, RegionReq regionReq);
+
+ RegionEntity getRegionById(Long regionId);
+
+ void deleteRegion(Long regionId);
+
+ List getAllRegions();
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/service/RoleService.java b/src/main/java/net/gepafin/tendermanagement/service/RoleService.java
new file mode 100644
index 00000000..448197b4
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/service/RoleService.java
@@ -0,0 +1,19 @@
+package net.gepafin.tendermanagement.service;
+
+import net.gepafin.tendermanagement.entities.RoleEntity;
+import net.gepafin.tendermanagement.model.request.RoleReq;
+import net.gepafin.tendermanagement.model.response.RoleResponseBean;
+
+import java.util.List;
+
+public interface RoleService {
+ RoleResponseBean createRole(RoleReq roleReq);
+
+ RoleResponseBean updateRole(Long roleId, RoleReq roleReq);
+
+ RoleEntity getRoleById(Long roleId);
+
+ void deleteRole(Long roleId);
+
+ List getAllRoles();
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/service/UserService.java b/src/main/java/net/gepafin/tendermanagement/service/UserService.java
new file mode 100644
index 00000000..68912240
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/service/UserService.java
@@ -0,0 +1,19 @@
+package net.gepafin.tendermanagement.service;
+
+import net.gepafin.tendermanagement.model.request.LoginReq;
+import net.gepafin.tendermanagement.model.request.UpdateUserReq;
+import net.gepafin.tendermanagement.model.request.UserReq;
+import net.gepafin.tendermanagement.model.response.UserResponseBean;
+import net.gepafin.tendermanagement.model.util.JWTToken;
+
+public interface UserService {
+ UserResponseBean createUser(UserReq userReq);
+
+ UserResponseBean updateUser(Long userId, UpdateUserReq userReq);
+
+ UserResponseBean getUserById(Long userId);
+
+ void deleteUser(Long userId);
+
+ JWTToken login(LoginReq loginReq);
+}
diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java
new file mode 100644
index 00000000..ad865d13
--- /dev/null
+++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java
@@ -0,0 +1,91 @@
+package net.gepafin.tendermanagement.service.impl;
+
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.model.*;
+import net.gepafin.tendermanagement.service.AmazonS3Service;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+
+@Service
+public class AmazonS3ServiceImpl implements AmazonS3Service {
+
+ @Autowired
+ private AmazonS3 amazonS3;
+
+ @Autowired
+ private Environment environment;
+
+ @Value("${aws.s3.bucket.name}")
+ private String bucketName;
+
+ @Value("${aws.s3.url.folder}")
+ private String s3Folder;
+
+ @Value("${aws.s3.url}")
+ private String s3Url;
+
+
+ @Override
+ public String upload(String fileName,
+ MultipartFile file) throws IOException {
+
+ String path = bucketName+"/"+s3Folder;
+
+ InputStream inputStream = file.getInputStream();
+
+ ObjectMetadata objectMetadata = new ObjectMetadata();
+ Map metadata = new HashMap<>();
+ metadata.put("Content-Type", file.getContentType());
+ metadata.put("Content-Length", String.valueOf(file.getSize()));
+
+ Optional