Merge pull request #2 from Kitzanos/feature/GEPAFINBE-8

GEPAFINBE-8(Created call API)
This commit is contained in:
rbonazzo-KZ
2024-08-22 09:11:23 +02:00
committed by GitHub
46 changed files with 1764 additions and 8 deletions

27
pom.xml
View File

@@ -78,6 +78,25 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.12.312</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-core</artifactId>
<version>1.12.341</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId> <artifactId>spring-boot-starter-security</artifactId>
@@ -110,6 +129,14 @@
<artifactId>hibernate-validator</artifactId> <artifactId>hibernate-validator</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version> <!-- or the latest version -->
</dependency>
</dependencies> </dependencies>

View File

@@ -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();
}
}

View File

@@ -5,8 +5,10 @@ import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys; import io.jsonwebtoken.security.Keys;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.entities.UserEntity; 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.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -18,11 +20,17 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.google.gson.Gson;
import static io.micrometer.common.util.StringUtils.isEmpty;
@Component @Component
public class TokenProvider { public class TokenProvider {
private final Logger log = LoggerFactory.getLogger(TokenProvider.class); private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
@@ -35,13 +43,19 @@ public class TokenProvider {
private SecretKey key; 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 @PostConstruct
public void init() { public void init() {
this.key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8)); this.key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8));
log.info("JWT Secret Key initialized."); log.info("JWT Secret Key initialized.");
} }
public String createToken(Authentication authentication, Boolean rememberMe, UserEntity user) { public String createToken(Authentication authentication, Boolean rememberMe, UserEntity user) {
String authorities = authentication.getAuthorities().stream() String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority) .map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(",")); .collect(Collectors.joining(","));
@@ -60,7 +74,7 @@ public class TokenProvider {
String payload = authentication.getName(); String payload = authentication.getName();
if(user != null) { if(user != null) {
payload += ":"+user.getId(); payload += ":"+user.getId();
} }
String token = Jwts.builder() String token = Jwts.builder()
@@ -110,4 +124,76 @@ public class TokenProvider {
return false; return false;
} }
} }
public Map<String, Object> getUserInfoAndUserIdFromToken(HttpServletRequest request) {
Map<String, Object> 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<String, Object> extractDetailsFromTheToken(Map<String, Object> userInfo, String authSecretHeader,
String token) {
String payload = null;
Boolean isSuperAdmin = false;
// if (StringUtils.hasText(token) && token.endsWith("_superKey" + getSuperUserToken())) {
// Map<String, Object> 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<String, Object> 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();
}
} }

View File

@@ -24,6 +24,19 @@ public class GepafinConstant {
public static final String DELETE_REGION_SUCCESS_MSG = "delete.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 REGION_NOT_FOUND_MSG = "user.region.not.found";
public static final String PASSWORD_DOESNT_MATCH ="password.doesnt.match"; 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 LOGIN_SUCCESS_MSG="login.successfully";
public static final String PASSWORD_MIN_LEN ="pass.min.len.msg"; public static final String PASSWORD_MIN_LEN ="pass.min.len.msg";
public static final String EMAIL_ALREADY_EXISTS = "email.already.exists"; public static final String EMAIL_ALREADY_EXISTS = "email.already.exists";

View File

@@ -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<EvaluationCriteriaEntity> evaluationCriteriaEntities = convertToEvaluationCriteriaEntities(createCallRequest.getCriteria(), callEntity);
List<DocumentEntity> documentEntities = convertToDocumentEntities(createCallRequest.getDocs(), callEntity);
List<DocumentEntity> imageEntities=convertToDocumentEntities(createCallRequest.getImages(),callEntity);
List<FaqEntity> faqEntities = convertToFaqEntities(createCallRequest.getFaq(), callEntity, userId);
List<LookUpDataResponse> amiedTo=convertLookUpDataEntities(createCallRequest.getAimedTo(),callEntity,LookUpDataTypeEnum.AIMED_TO);
List<LookUpDataResponse> 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<EvaluationCriteriaEntity> convertToEvaluationCriteriaEntities(List<EvaluationCriteriaReq> criteriaReqList, CallEntity callEntity) {
List<EvaluationCriteriaEntity> 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<DocumentEntity> convertToDocumentEntities(List<DocumentReq> documentReqList, CallEntity callEntity) {
List<DocumentEntity> 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<FaqEntity> convertToFaqEntities(List<FaqReq> faqReqList, CallEntity callEntity, Long userId) {
List<FaqEntity> 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<EvaluationCriteriaEntity> evaluationCriteriaEntities,
List<DocumentEntity> documentEntities,
List<FaqEntity> faqEntities,List<DocumentEntity> images) {
CreateCallResponseBean callResponseBean = convertToCallResponseBean(callEntity);
List<EvaluationCriteriaResponseBean> evaluationCriteriaResponseBeans = evaluationCriteriaEntities.stream()
.map(this::convertToEvaluationCriteriaResponseBean)
.collect(Collectors.toList());
List<DocumentResponseBean> documentResponseBeans = documentEntities.stream()
.map(this::convertToDocumentResponseBean)
.collect(Collectors.toList());
List<FaqResponseBean> faqResponseBeans = faqEntities.stream()
.map(this::convertToFaqResponseBean)
.collect(Collectors.toList());
List<DocumentResponseBean> 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<LookUpDataResponse> convertLookUpDataEntities(List<LookUpDataReq> lookUpData, CallEntity callEntity, LookUpDataEntity.LookUpDataTypeEnum type) {
List<LookUpDataEntity> lookUpDataEntities = lookUpData.stream()
.map(req -> convertLookUpDataRequestIntoLookUpDataEntity(req, type))
.collect(Collectors.toList());
lookUpDataRepository.saveAll(lookUpDataEntities);
return createCallTargetAudienceCheckList(callEntity, lookUpDataEntities);
}
private List<LookUpDataResponse> createCallTargetAudienceCheckList(CallEntity callEntity, List<LookUpDataEntity> lookUpDataEntities) {
List<LookUpDataResponse> lookUpDataResponses=new ArrayList<>();
List<CallTargetAudienceChecklistEntity> 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;
}
}

View File

@@ -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<DocumentResponseBean> uploadFiles(List<MultipartFile> files, DocumentTypeEnum fileType) {
List<DocumentEntity> 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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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<LookUpDataReq> aimedTo;
private String documentationRequested;
private Integer threshold;
private Boolean Confidi;
List<EvaluationCriteriaReq> criteria;
private List<FaqReq> faq;
private List<LookUpDataReq> checkList;
private List<DocumentReq> docs;
private List<DocumentReq> images;
private CallTypeEnum status;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,11 @@
package net.gepafin.tendermanagement.model.request;
import lombok.Data;
@Data
public class LookUpDataReq {
private Long lookUpDataId;
private String value;
}

View File

@@ -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;
}

View File

@@ -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<LocalDateTime> 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<LookUpDataResponse> aimedTo;
private List<EvaluationCriteriaResponseBean> criteria;
private List<DocumentResponseBean> docs;
private List<FaqResponseBean> faq;
private List<DocumentResponseBean> images;
private List<LookUpDataResponse> checkList;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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<CallEntity, Integer> {
}

View File

@@ -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<CallTargetAudienceChecklistEntity,Long> {
}

View File

@@ -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, Integer> {
DocumentEntity findById(Long id);
}

View File

@@ -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<EvaluationCriteriaEntity, Integer> {
}

View File

@@ -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<FaqEntity, Integer> {
}

View File

@@ -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<LookUpDataEntity,Long> {
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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<DocumentResponseBean> uploadFile(List<MultipartFile> files, DocumentTypeEnum fileType);
public Void deleteFile(Long documentId);
}

View File

@@ -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<String, String> metadata = new HashMap<>();
metadata.put("Content-Type", file.getContentType());
metadata.put("Content-Length", String.valueOf(file.getSize()));
Optional<Map<String, String>> optionalMetaData = Optional.of(metadata);
optionalMetaData.ifPresent(map -> {
if (!map.isEmpty()) {
map.forEach(objectMetadata::addUserMetadata);
}
});
if(Boolean.FALSE.equals(isTestProfileActivated())) {
amazonS3.putObject(path, fileName, inputStream, objectMetadata);
}
return s3Url + s3Folder +"/"+ fileName;
}
@Override
public Boolean delete(String bucketName,String fileName) {
final DeleteObjectRequest deleteObjectRequest = new DeleteObjectRequest(bucketName, fileName);
if(Boolean.FALSE.equals(isTestProfileActivated())) {
amazonS3.deleteObject(deleteObjectRequest);
}
return true;
}
public Boolean isTestProfileActivated() {
String[] activeProfiles = environment.getActiveProfiles();
return Arrays.stream(activeProfiles).anyMatch("test"::equals);
}
@Override
public InputStream getFile(String filePath) throws IOException {
try {
String path = bucketName+ s3Folder +"/";
GetObjectRequest getObjectRequest = new GetObjectRequest(path, filePath);
S3Object s3Object = amazonS3.getObject(getObjectRequest);
return s3Object.getObjectContent();
} catch (AmazonS3Exception e) {
throw new IOException("Error getting file from Amazon S3", e);
}
}
}

View File

@@ -0,0 +1,29 @@
package net.gepafin.tendermanagement.service.impl;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.config.jwt.TokenProvider;
import net.gepafin.tendermanagement.dao.CallDao;
import net.gepafin.tendermanagement.model.request.CreateCallRequest;
import net.gepafin.tendermanagement.model.response.CreateCallResponseBean;
import net.gepafin.tendermanagement.service.CallService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
public class CallServiceImpl implements CallService {
@Autowired
private CallDao callDao;
@Autowired
private TokenProvider tokenProvider;
@Override
public CreateCallResponseBean createCall(HttpServletRequest request, CreateCallRequest createCallRequest) {
Map<String, Object> userInfo= tokenProvider.getUserInfoAndUserIdFromToken(request);
return callDao.createCall(createCallRequest, Long.parseLong(userInfo.get("userId").toString()));
}
}

View File

@@ -0,0 +1,28 @@
package net.gepafin.tendermanagement.service.impl;
import net.gepafin.tendermanagement.dao.DocumentDao;
import net.gepafin.tendermanagement.enums.DocumentTypeEnum;
import net.gepafin.tendermanagement.model.response.DocumentResponseBean;
import net.gepafin.tendermanagement.service.DocumentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Service
public class DocumentServiceImpl implements DocumentService {
@Autowired
private DocumentDao fileDao;
@Override
public List<DocumentResponseBean> uploadFile(List<MultipartFile> files, DocumentTypeEnum fileType) {
return fileDao.uploadFiles(files,fileType);
}
@Override
public Void deleteFile(Long documentId){
return fileDao.deleteFile(documentId);
}
}

View File

@@ -3,9 +3,12 @@ package net.gepafin.tendermanagement.util;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import io.micrometer.common.util.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -46,4 +49,24 @@ public class Utils {
} }
return null; return null;
} }
public static String extractFileName(String filePath) {
if (filePath == null || filePath.isEmpty()) {
return null;
}
int lastSlashIndex = filePath.lastIndexOf('/');
if (lastSlashIndex >= 0 && lastSlashIndex < filePath.length() - 1) {
return filePath.substring(lastSlashIndex + 1);
} else {
return filePath;
}
}
public static String decodeBase64String(String decodedString) {
if (StringUtils.isBlank(decodedString)) {
return decodedString;
}
byte[] decode = Base64.getDecoder().decode(decodedString.getBytes(StandardCharsets.UTF_8));
return new String(decode, StandardCharsets.UTF_8);
}
} }

View File

@@ -0,0 +1,37 @@
package net.gepafin.tendermanagement.web.rest.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import net.gepafin.tendermanagement.model.request.CreateCallRequest;
import net.gepafin.tendermanagement.model.response.CreateCallResponseBean;
import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
public interface CallApi {
@Operation(summary = "API to create call",
responses = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) }))
})
@PostMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Response<CreateCallResponseBean>> createCall(HttpServletRequest request,
@Parameter(description = "Call request object", required = true)
@Valid @RequestBody CreateCallRequest createCallRequest);
}

View File

@@ -0,0 +1,53 @@
package net.gepafin.tendermanagement.web.rest.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.enums.DocumentTypeEnum;
import net.gepafin.tendermanagement.model.response.DocumentResponseBean;
import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public interface DocumentApi {
@Operation(summary = "Api to upload a file",
responses = {
@ApiResponse(responseCode = "200", description = "OK"),
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) }))
})
@PostMapping(value = "/uploadFile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
default ResponseEntity<Response<List<DocumentResponseBean>>> uploadFile(HttpServletRequest httpServletRequest,
@RequestParam("file") List<MultipartFile> files,
@RequestParam("documentType") DocumentTypeEnum documentTypeEnum) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
@Operation(summary = "API to delete a file by document id",
responses = {
@ApiResponse(responseCode = "200", description = "File deleted successfully"),
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
@ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) }))
})
@DeleteMapping(value = "/deleteFile")
default ResponseEntity<Response<Void>> deleteFile(HttpServletRequest httpServletRequest,
@RequestParam( "id") Long id) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}

View File

@@ -0,0 +1,35 @@
package net.gepafin.tendermanagement.web.rest.api.impl;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.config.Translator;
import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.model.request.CreateCallRequest;
import net.gepafin.tendermanagement.model.response.CreateCallResponseBean;
import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.service.CallService;
import net.gepafin.tendermanagement.web.rest.api.CallApi;
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("${openapi.gepafin.base-path:/v1/call}")
public class CallApiController implements CallApi {
@Autowired
private CallService callService;
@Override
@Transactional(rollbackFor=Exception.class)
public ResponseEntity<Response<CreateCallResponseBean>> createCall(HttpServletRequest request, CreateCallRequest createCallRequest) {
CreateCallResponseBean createCallResponseBean = callService.createCall(request, createCallRequest);
return ResponseEntity.status(HttpStatus.CREATED)
.body(new Response<>(createCallResponseBean, Status.SUCCESS, Translator.toLocale(GepafinConstant.CALL_CREATED_SUCCESSFULLY_MSG)));
}
}

View File

@@ -0,0 +1,45 @@
package net.gepafin.tendermanagement.web.rest.api.impl;
import jakarta.servlet.http.HttpServletRequest;
import net.gepafin.tendermanagement.config.Translator;
import net.gepafin.tendermanagement.constants.GepafinConstant;
import net.gepafin.tendermanagement.enums.DocumentTypeEnum;
import net.gepafin.tendermanagement.model.response.DocumentResponseBean;
import net.gepafin.tendermanagement.model.util.Response;
import net.gepafin.tendermanagement.service.DocumentService;
import net.gepafin.tendermanagement.web.rest.api.DocumentApi;
import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException;
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@RestController
@RequestMapping("${openapi.swaggerBflowsMiddleware.base-path:/v1/document}")
public class DocumentApiController implements DocumentApi {
@Autowired
private DocumentService fileService;
@Override
public ResponseEntity<Response<List<DocumentResponseBean>>> uploadFile(HttpServletRequest httpServletRequest,
List<MultipartFile> files, DocumentTypeEnum fileType) {
try {
List<DocumentResponseBean> responseBeans=fileService.uploadFile(files,fileType);
return ResponseEntity.status(HttpStatus.CREATED)
.body(new Response<List<DocumentResponseBean>>(responseBeans, Status.SUCCESS, Translator.toLocale(GepafinConstant.FILES_UPLOADED_MSG)));
} catch (CustomValidationException ex) {
throw ex;
}
}
@Override
public ResponseEntity<Response<Void>> deleteFile(HttpServletRequest httpServletRequest, Long documentId) {
fileService.deleteFile(documentId);
return ResponseEntity.status(HttpStatus.CREATED)
.body(new Response<Void>(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.FILE_DELETED_SUCCESSFULLY_MSG)));
}
}

View File

@@ -23,6 +23,13 @@ spring.liquibase.enabled=true
springdoc.api-docs.path=/v1/api-docs springdoc.api-docs.path=/v1/api-docs
#aws configuration
aws.access.key.id=AKIAVWDQWCUEOSUN4LUW
aws.secret.access.key=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
aws.s3.region=eu-west-1
aws.s3.bucket.name=mementoresources
aws.s3.url = https://mementoresources.s3.eu-west-1.amazonaws.com/
aws.s3.url.folder=gepafin
# JWT configuration # JWT configuration
# Ensure these values match your expectations # Ensure these values match your expectations
security.authentication.jwt.secret=my-secret-token-to-change-in-prod-environment-your-super-secure-randomly-generated-key security.authentication.jwt.secret=my-secret-token-to-change-in-prod-environment-your-super-secure-randomly-generated-key

View File

@@ -134,4 +134,162 @@
</createTable> </createTable>
</changeSet> </changeSet>
<changeSet id="21-08-2024_1" author="Rajesh Khore">
<createTable tableName="call">
<column autoIncrement="true" name="id" type="INTEGER">
<constraints nullable="false" primaryKey="true"
primaryKeyName="call_pkey"/>
</column>
<column name="name" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="description_short" type="TEXT"/>
<column name="description_long" type="TEXT"/>
<column name="start_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="end_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="status" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="region_id" type="INTEGER">
<constraints nullable="false" foreignKeyName="fk_region_call" references="region(id)"/>
</column>
<column name="amount" type="numeric">
<constraints nullable="false"/>
</column>
<column name="amount_max" type="numeric">
<constraints nullable="false"/>
</column>
<column name="documentation_requested" type="TEXT"/>
<column name="contact_info" type="TEXT"/>
<column name="submission_method" type="TEXT">
</column>
<column name="threshold" type="INTEGER">
<constraints nullable="false"/>
</column>
<column name="priority_area" type="TEXT"/>
<column name="confidi" type="BOOLEAN"/>
<column name="created_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
<column name="updated_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
</createTable>
<createTable tableName="evaluation_criteria">
<column autoIncrement="true" name="id" type="INTEGER">
<constraints nullable="false" primaryKey="true"
primaryKeyName="evaluation_criteria_pkey"/>
</column>
<column name="call_id" type="INTEGER">
<constraints nullable="false" foreignKeyName="fk_call_evaluation_criteria" references="call(id)"/>
</column>
<column name="name" type="TEXT">
<constraints nullable="false"/>
</column>
<column name="description" type="TEXT"/>
<column name="score" type="INTEGER">
<constraints nullable="false"/>
</column>
<column name="created_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
<column name="updated_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
</createTable>
<createTable tableName="faq">
<column autoIncrement="true" name="id" type="INTEGER">
<constraints nullable="false" primaryKey="true"
primaryKeyName="faq_pkey"/>
</column>
<column name="call_id" type="INTEGER">
<constraints nullable="false" foreignKeyName="fk_call_faq" references="call(id)"/>
</column>
<column name="user_id" type="INTEGER">
<constraints nullable="false" foreignKeyName="fk_gepafin_user_faq" references="gepafin_user(id)"/>
</column>
<column name="is_visible" type="BOOLEAN">
<constraints nullable="false"/>
</column>
<column name="question_short" type="VARCHAR(255)"/>
<column name="question" type="TEXT"/>
<column name="response_short" type="VARCHAR(255)"/>
<column name="response" type="TEXT"/>
<column name="response_date" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="created_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="updated_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
</createTable>
<createTable tableName="document">
<column autoIncrement="true" name="id" type="INTEGER">
<constraints nullable="false" primaryKey="true"
primaryKeyName="document_pkey"/>
</column>
<column name="file_name" type="VARCHAR(255)">
</column>
<column name="file_path" type="TEXT"/>
<column name="call_id" type="INTEGER">
<constraints foreignKeyName="fk_call_document" references="call(id)"/>
</column>
<column name="description" type="TEXT"/>
<column name="type" type="VARCHAR(255)">
</column>
<column name="created_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="updated_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/></column>
</createTable>
<createTable tableName="lookup_data">
<column autoIncrement="true" name="id" type="INTEGER">
<constraints nullable="false" primaryKey="true"
primaryKeyName="lookup_data_pkey"/>
</column>
<column name="title" type="VARCHAR(255)">
<constraints nullable="true"/>
</column>
<column name="type" type="VARCHAR(255)">
<constraints nullable="false"/>
</column>
<column name="value" type="TEXT">
</column>
<column name="created_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="updated_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/></column>
</createTable>
<createTable tableName="call_target_audience_checklist">
<column autoIncrement="true" name="id" type="INTEGER">
<constraints nullable="false" primaryKey="true"
primaryKeyName="call_target_audience_checklist_pkey"/>
</column>
<column name="call_id" type="INTEGER">
<constraints nullable="false" foreignKeyName="fk_call_call_target_audience_checklist" references="call(id)"/>
</column>
<column name="lookup_data_id" type="INTEGER">
<constraints nullable="false" foreignKeyName="fk_lookup_data_call_target_audience_checklist" references="lookup_data(id)"/>
</column>
<column name="is_validated" type="BOOLEAN">
</column>
<column name="created_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="false"/>
</column>
<column name="updated_date" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/></column>
</createTable>
</changeSet>
</databaseChangeLog> </databaseChangeLog>

View File

@@ -27,6 +27,22 @@ create.regiom.error=Error occurred while creating the region.
update.region.error=Error occurred while updating the region. update.region.error=Error occurred while updating the region.
password.doesnt.match=Password and confirm password do not match. password.doesnt.match=Password and confirm password do not match.
#call related messages
user.not.exist=User does not exist.
region.not.found=Region not found.
user.id.not.null=User ID cannot be null.
question.not.empty=Question cannot be empty.
name.not.empty=Name cannot be empty.
type.not.empty=Type cannot be empty.
region.not.null=Region ID cannot be null.
amount.greater.than.zero=Amount must be greater than zero.
look.up.data.not.valid=Look up data entity is not valid.
files.uploaded=Files uploaded successfully.
call.created.successfully=Call created successfully.
file.deleted.successfully=File deleted successfully.
document.not.found=Document not found.
# Login-related messages
login.successfully=Login successfully. login.successfully=Login successfully.
pass.min.len.msg=Password must be at least 8 characters long. pass.min.len.msg=Password must be at least 8 characters long.
email.already.exists=A user with this email already exists. email.already.exists=A user with this email already exists.

View File

@@ -2,11 +2,11 @@ user.created.success=Utente creato con successo.
user.updated.success=Utente aggiornato con successo. user.updated.success=Utente aggiornato con successo.
user.deleted.success=Utente eliminato con successo. user.deleted.success=Utente eliminato con successo.
user.not.found=Utente non trovato. user.not.found=Utente non trovato.
create_user_error_msg=Si è verificato un errore durante la creazione dell'utente. create_user_error_msg=Si <EFBFBD> verificato un errore durante la creazione dell'utente.
update_user_error_msg=Si è verificato un errore durante l'aggiornamento dell'utente. update_user_error_msg=Si <EFBFBD> verificato un errore durante l'aggiornamento dell'utente.
delete_user_error_msg=Si è verificato un errore durante l'eliminazione dell'utente. delete_user_error_msg=Si <EFBFBD> verificato un errore durante l'eliminazione dell'utente.
get_user_success_msg=Utente recuperato con successo. get_user_success_msg=Utente recuperato con successo.
get_user_error_msg=Si è verificato un errore durante il recupero dell'utente. get_user_error_msg=Si <EFBFBD> verificato un errore durante il recupero dell'utente.
# Role-related messages # Role-related messages
role.created.success=Ruolo creato con successo. role.created.success=Ruolo creato con successo.
role.updated.success=Ruolo aggiornato con successo. role.updated.success=Ruolo aggiornato con successo.
@@ -27,9 +27,23 @@ create.regiom.error=Errore durante la creazione della regione.
update.region.error=Errore durante l'aggiornamento della regione. update.region.error=Errore durante l'aggiornamento della regione.
password.doesnt.match=La password e la conferma della password non corrispondono. password.doesnt.match=La password e la conferma della password non corrispondono.
#call related messages
user.not.exist=L'utente non esiste.
region.not.found=Regione non trovata.
user.id.not.null=L'ID utente non pu<70> essere nullo.
question.not.empty=La domanda non pu<70> essere vuota.
name.not.empty=Il nome non pu<70> essere vuoto.
type.not.empty=Il tipo non pu<70> essere vuoto.
region.not.null=L'ID regione non pu<70> essere nullo.
amount.greater.than.zero=L'importo del finanziamento deve essere maggiore di zero.
look.up.data.not.valid=L'entit<69> dati di ricerca non <20> valida.
files.uploaded=File caricati correttamente.
call.created.successfully=Chiamata creata correttamente.
file.deleted.successfully=File eliminato con successo.
document.not.found=Documento non trovato.
# Login-related messages # Login-related messages
login.successfully=Accesso effettuato con successo. login.successfully=Accesso effettuato con successo.
pass.min.len.msg=La password deve essere lunga almeno 8 caratteri. pass.min.len.msg=La password deve essere lunga almeno 8 caratteri.
email.already.exists=Esiste già un utente con questa email. email.already.exists=Esiste gi<EFBFBD> un utente con questa email.