From e94be7eb3380b4c43960f95e5ecca15b6a6a4bca Mon Sep 17 00:00:00 2001 From: harish Date: Wed, 9 Oct 2024 20:13:08 +0530 Subject: [PATCH 01/10] Updated application validation related to company delegation --- .../constants/GepafinConstant.java | 1 + .../tendermanagement/dao/ApplicationDao.java | 28 +++++++++++++++++-- .../service/CompanyService.java | 2 ++ .../service/impl/CompanyServiceImpl.java | 3 ++ src/main/resources/message_en.properties | 2 +- src/main/resources/message_it.properties | 2 ++ 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index f67a2ee2..e27e9d65 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -198,5 +198,6 @@ public class GepafinConstant { public static final String DELEGATION_NOT_FOUND = "delegation.not.found"; public static final String USER_COMPANY_RELATION_NOT_FOUND = "user.company.relation.not.found"; public static final String DELEGATION_DELETE_SUCCESS = "delegation.delete.success"; + public static final String USER_NOT_AUTHORIZED_TO_CREATE_APPLICATION = "user.not.authorized.create.application"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index ae8db433..69be125a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -6,12 +6,14 @@ import net.gepafin.tendermanagement.entities.*; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum; import net.gepafin.tendermanagement.enums.RoleStatusEnum; +import net.gepafin.tendermanagement.enums.UserCompanyDelegationStatusEnum; import net.gepafin.tendermanagement.model.request.ApplicationFormFieldRequestBean; import net.gepafin.tendermanagement.model.request.ApplicationRequest; import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.repositories.*; import net.gepafin.tendermanagement.service.CallService; +import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.service.DocumentService; import net.gepafin.tendermanagement.service.FormService; import net.gepafin.tendermanagement.util.DateTimeUtil; @@ -68,10 +70,14 @@ public class ApplicationDao { @Autowired private FlowDataRepository flowDataRepository; - + @Autowired + private UserWithCompanyRepository userWithCompanyRepository; + @Autowired + private UserCompanyDelegationRepository userCompanyDelegationRepository; @Autowired private Validator validator; - + @Autowired + private CompanyService companyService; public ApplicationResponseBean createApplication(ApplicationRequestBean applicationRequestBean, UserEntity userEntity, Long formId, Long applicationId) { FormEntity formEntity = formService.validateForm(formId); @@ -86,6 +92,19 @@ public class ApplicationDao { createOrUpdateMultipleFormFields(applicationRequestBean.getFormFields(), applicationFormEntity,formEntity); return getApplicationById(applicationEntity.getId(),formEntity.getId()); } + public void validateDelegation(UserEntity user, CompanyEntity company) { + UserWithCompanyEntity userWithCompany = companyService.getUserWithCompanyEntity(user.getId(), company.getId()); + + UserCompanyDelegationEntity userCompanyDelegationEntity = userCompanyDelegationRepository + .findByUserIdAndCompanyIdAndStatus(user.getId(), company.getId(), + UserCompanyDelegationStatusEnum.ACTIVE.getValue()); + + if (!userWithCompany.getIsLegalRepresentant() && userCompanyDelegationEntity == null) { + throw new CustomValidationException(Status.BAD_REQUEST, + Translator.toLocale(GepafinConstant.USER_NOT_AUTHORIZED_TO_CREATE_APPLICATION)); + } + } + public ApplicationFormEntity saveApplicationFormEntity(ApplicationFormEntity applicationFormEntity) { ApplicationFormEntity applicationFormEntity1 = applicationFormRepository.save(applicationFormEntity); @@ -101,6 +120,7 @@ public class ApplicationDao { } public ApplicationEntity createApplicationEntity(UserEntity user, CallEntity call, CompanyEntity companyEntity) { + validateDelegation(user,companyEntity); ApplicationEntity entity = new ApplicationEntity(); entity.setUserId(user.getId()); entity.setCompany(companyEntity); @@ -505,7 +525,9 @@ public class ApplicationDao { public ApplicationResponse updateApplicationStatus(Long applicationId, ApplicationStatusTypeEnum status) { ApplicationEntity applicationEntity = validateApplication(applicationId); - + if (ApplicationStatusTypeEnum.SUBMIT.getValue().equals(applicationEntity.getStatus())) { + throw new CustomValidationException(Status.BAD_REQUEST, Translator.toLocale(GepafinConstant.APPLICATION_ALREADY_SUBMITTED)); + } if (status.equals(ApplicationStatusTypeEnum.SUBMIT)) { callService.validatePublishedCall(applicationEntity.getCall().getId()); // CallEntity callEntity = applicationEntity.getCall(); diff --git a/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java b/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java index da05c544..18b6db0c 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/CompanyService.java @@ -39,5 +39,7 @@ public interface CompanyService { CompanyDelegationResponse getCompanyDelegation(HttpServletRequest request, Long companyId); void deleteCompanyDelegation(HttpServletRequest request, Long companyId); + UserWithCompanyEntity getUserWithCompanyEntity(Long userId,Long companyId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java index 0e43265a..1f80b223 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java @@ -114,4 +114,7 @@ public class CompanyServiceImpl implements CompanyService { UserEntity userEntity =validator.validateUser(request); delegationDao.deleteCompanyDelegation(userEntity, companyId); } + public UserWithCompanyEntity getUserWithCompanyEntity(Long userId,Long companyId){ + return companyDao.getUserWithCompany(userId,companyId); + } } diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 84279127..d5d8dd0c 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -223,5 +223,5 @@ application.status.updated.successfully = Application status updated successfull delegation.not.found=Delegation not found. user.company.relation.not.found=User with the specified company relation not found. delegation.delete.success=Delegation deleted successfully. - +user.not.authorized.create.application=User must be a legal representative or have delegation. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 4dfec2b0..7086144c 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -218,5 +218,7 @@ application.status.updated.successfully = Stato dell'applicazione aggiornato con delegation.not.found=Delega non trovata. user.company.relation.not.found=Relazione utente con l'azienda specificata non trovata. delegation.delete.success=Delega eliminata con successo. +user.not.authorized.create.application=L'utente deve essere un rappresentante legale o avere una delega. + From 75ae714a2d22d3bea1e6f51d6d4019fb0692ef7a Mon Sep 17 00:00:00 2001 From: harish Date: Wed, 9 Oct 2024 20:22:25 +0530 Subject: [PATCH 02/10] Updated code --- .../net/gepafin/tendermanagement/constants/GepafinConstant.java | 2 +- src/main/resources/message_en.properties | 2 ++ src/main/resources/message_it.properties | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 944edbe2..afbfbea3 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -200,6 +200,6 @@ public class GepafinConstant { public static final String USER_COMPANY_RELATION_NOT_FOUND = "user.company.relation.not.found"; public static final String DELEGATION_DELETE_SUCCESS = "delegation.delete.success"; public static final String USER_NOT_AUTHORIZED_TO_CREATE_APPLICATION = "user.not.authorized.create.application"; - + public static final String APPLICATION_SUBMITTED_CANNOT_CHANGE = "application.submitted.cannot.change"; } diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 44fcb751..0d68c6d7 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -225,4 +225,6 @@ delegation.not.found=Delegation not found. user.company.relation.not.found=User with the specified company relation not found. delegation.delete.success=Delegation deleted successfully. user.not.authorized.create.application=User must be a legal representative or have delegation. +application.submitted.cannot.change=The submitted application cannot be changed. + diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 419c44fb..3e665e82 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -220,6 +220,7 @@ delegation.not.found=Delega non trovata. user.company.relation.not.found=Relazione utente con l'azienda specificata non trovata. delegation.delete.success=Delega eliminata con successo. user.not.authorized.create.application=L'utente deve essere un rappresentante legale o avere una delega. +application.submitted.cannot.change=La domanda inviata non puņ essere modificata. From b1a2fc891c627d7cdf5a0ed2a5bfbc7027398f78 Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 10 Oct 2024 15:42:43 +0530 Subject: [PATCH 03/10] updated default placeholder --- .../gepafin/tendermanagement/dao/DelegationDao.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/dao/DelegationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/DelegationDao.java index 525c657a..ca58f8be 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/DelegationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/DelegationDao.java @@ -127,15 +127,15 @@ public class DelegationDao { placeholders.put("{{company_last_name}}", ""); placeholders.put("{{company_codice_fiscale}}", ""); placeholders.put("{{company_name}}", ""); - placeholders.put("{{company_city}}", DEFAULT_PLACEHOLDER); - placeholders.put("{{company_address}}", DEFAULT_PLACEHOLDER); - placeholders.put("{{company_province}}", DEFAULT_PLACEHOLDER); - placeholders.put("{{company_cap}}", DEFAULT_PLACEHOLDER); + placeholders.put("{{company_city}}", ""); + placeholders.put("{{company_address}}", ""); + placeholders.put("{{company_province}}", ""); + placeholders.put("{{company_cap}}", ""); placeholders.put("{{company_vat_number}}", ""); placeholders.put("{{user_first_name}}", ""); placeholders.put("{{user_last_name}}", ""); - placeholders.put("{{user_date_of_birth}}", DEFAULT_PLACEHOLDER); + placeholders.put("{{user_date_of_birth}}", ""); placeholders.put("{{user_codice_fiscale}}", ""); return placeholders; } From b842bcee73e08bfd3265d206d669881fa98afcdd Mon Sep 17 00:00:00 2001 From: harish Date: Thu, 10 Oct 2024 18:03:02 +0530 Subject: [PATCH 04/10] Beneficiario must be abfle to dowload Call Documents --- .../constants/GepafinConstant.java | 2 + .../gepafin/tendermanagement/dao/CallDao.java | 45 +++++++++++++++++++ .../repositories/DocumentRepository.java | 1 + .../tendermanagement/service/CallService.java | 2 +- .../service/impl/CallServiceImpl.java | 5 +++ .../web/rest/api/CallApi.java | 15 +++++++ .../web/rest/api/impl/CallApiController.java | 20 +++++++++ src/main/resources/message_en.properties | 3 ++ src/main/resources/message_it.properties | 3 ++ 9 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index afbfbea3..d72853c7 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -201,5 +201,7 @@ public class GepafinConstant { public static final String DELEGATION_DELETE_SUCCESS = "delegation.delete.success"; public static final String USER_NOT_AUTHORIZED_TO_CREATE_APPLICATION = "user.not.authorized.create.application"; public static final String APPLICATION_SUBMITTED_CANNOT_CHANGE = "application.submitted.cannot.change"; + public static final String CALL_DOCUMENTS_FETCH_SUCCESS_MSG = "call.documents.fetch.success"; + public static final String CALL_DOCUMENTS_NOT_FOUND_MSG = "call.documents.not.found"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java index c6345d59..0827b62a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java @@ -1,5 +1,9 @@ package net.gepafin.tendermanagement.dao; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; @@ -8,13 +12,21 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.service.*; import net.gepafin.tendermanagement.util.DateTimeUtil; import net.gepafin.tendermanagement.util.Utils; +import org.h2.util.IOUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @@ -85,6 +97,10 @@ public class CallDao { private FlowDao flowDao; @Autowired private FormDao formDao; + @Value("${aws.s3.url.folder}") + private String s3Folder; + @Autowired + private AmazonS3Service amazonS3Service; public CallResponse createCallStep1(CreateCallRequestStep1 createCallRequest, Long userId) { UserEntity userEntity = userService.validateUser(userId); @@ -101,6 +117,35 @@ public class CallDao { return createCallResponseBean; } + public byte[] downloadCallDocumentsAsZip(Long callId) { + List documents = documentRepository.findBySourceIdAndSourceAndTypeAndIsDeletedFalse(callId, DocumentSourceTypeEnum.CALL.getValue(),DocumentTypeEnum.DOCUMENT.getValue()); + if (documents.isEmpty()) { + throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND)); + } + + try (ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(zipOutputStream)) { + + for (DocumentEntity document : documents) { + try (InputStream fileInputStream = amazonS3Service.getFile(s3Folder, document.getFileName())) { + ZipEntry zipEntry = new ZipEntry(document.getFileName()); + zos.putNextEntry(zipEntry); + IOUtils.copy(fileInputStream, zos); + zos.closeEntry(); + } catch (IOException e) { + throw new RuntimeException("Error downloading or adding document to ZIP: " + document.getFileName(), e); + } + } + + zos.finish(); + return zipOutputStream.toByteArray(); + + } catch (IOException e) { + throw new RuntimeException("Error while creating ZIP file", e); + } + } + + public CallEntity convertToCallEntity(CreateCallRequestStep1 createCallRequest) { CallEntity callEntity = new CallEntity(); diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java index 339efd13..1543def3 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java @@ -20,6 +20,7 @@ public interface DocumentRepository extends JpaRepository Optional findByIdAndSourceIdAndIsDeletedFalse(Long id, Long sourceId); List findBySource(String source); + List findBySourceIdAndSourceAndTypeAndIsDeletedFalse(Long sourceId, String source, String type); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/CallService.java b/src/main/java/net/gepafin/tendermanagement/service/CallService.java index aa6ea872..9a62d89d 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/CallService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/CallService.java @@ -32,5 +32,5 @@ public interface CallService { CallEntity validateCall(Long callId); CallEntity validatePublishedCall(Long callId); - + byte[] downloadCallDocumentsAsZip(Long callId); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java index a6a6a901..f6ca0b66 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java @@ -92,4 +92,9 @@ public class CallServiceImpl implements CallService { public CallEntity validatePublishedCall(Long callId) { return callDao.validatePublishedCall(callId); } + @Override + @Transactional(readOnly = true) + public byte[] downloadCallDocumentsAsZip(Long callId) { + return callDao.downloadCallDocumentsAsZip(callId); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java index cc7f985a..3e2861ff 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java @@ -134,4 +134,19 @@ public interface CallApi { public ResponseEntity> updateCallStatus(HttpServletRequest request, @Parameter(description = "The call id", required = true) @PathVariable("callId") Long callId, @Parameter(description = "status", required = true)@RequestParam(value = "status", required = true) CallStatusEnum status); + + @Operation(summary = "Api to download call documents as a ZIP 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)})) + }) + @GetMapping(value = "/{callId}/documents/zip") + ResponseEntity downloadCallDocumentsAsZip(HttpServletRequest httpServletRequest, + @Parameter(description = "The call ID", required = true) @PathVariable("callId") Long callId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java index e4680428..926dccab 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java @@ -4,7 +4,9 @@ import java.util.List; import net.gepafin.tendermanagement.enums.CallStatusEnum; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestMapping; @@ -84,4 +86,22 @@ public class CallApiController implements CallApi { CallResponse updateCall = callService.updateCallStatus(request, callId, status); return ResponseEntity.ok(new Response<>(updateCall, Status.SUCCESS, Translator.toLocale(GepafinConstant.UPDATE_CALL_STATUS_SUCCESS_MSG))); } + @Override + public ResponseEntity downloadCallDocumentsAsZip(HttpServletRequest request, Long callId) { + byte[] zipFile = callService.downloadCallDocumentsAsZip(callId); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); + headers.setContentDispositionFormData("attachment", "documents.zip"); + + if (zipFile == null || zipFile.length == 0) { + String notFoundMessage = Translator.toLocale(GepafinConstant.CALL_DOCUMENTS_NOT_FOUND_MSG); + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(notFoundMessage.getBytes()); + } + + return new ResponseEntity<>(zipFile, headers, HttpStatus.OK); + } + + } \ No newline at end of file diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 0d68c6d7..8ae7bcfa 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -226,5 +226,8 @@ user.company.relation.not.found=User with the specified company relation not fou delegation.delete.success=Delegation deleted successfully. user.not.authorized.create.application=User must be a legal representative or have delegation. application.submitted.cannot.change=The submitted application cannot be changed. +# Call Document Messages +call.documents.fetch.success=Documents fetched successfully. +call.documents.not.found=No documents found for the specified call. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 3e665e82..9b998124 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -222,5 +222,8 @@ delegation.delete.success=Delega eliminata con successo. user.not.authorized.create.application=L'utente deve essere un rappresentante legale o avere una delega. application.submitted.cannot.change=La domanda inviata non puņ essere modificata. +# Call Document Messages +call.documents.fetch.success=Documenti recuperati con successo. +call.documents.not.found=Nessun documento trovato per la chiamata specificata. From f7c97c108088c10e13f9100424bc76d17cd9b67e Mon Sep 17 00:00:00 2001 From: rajesh Date: Thu, 10 Oct 2024 11:56:08 -0700 Subject: [PATCH 05/10] Updated config --- .../tendermanagement/config/SecurityConfig.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java index 91424195..90c278d4 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java +++ b/src/main/java/net/gepafin/tendermanagement/config/SecurityConfig.java @@ -24,12 +24,12 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; - 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 jakarta.servlet.http.HttpServletResponse; import net.gepafin.tendermanagement.config.jwt.JWTFilter; import net.gepafin.tendermanagement.config.jwt.TokenProvider; @@ -107,7 +107,13 @@ public class SecurityConfig { .requestMatchers("/swagger-ui/**").permitAll() // Swagger docs .requestMatchers("/v1/api-docs/**").permitAll() // API docs .anyRequest().authenticated()) - .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)) + .exceptionHandling(exceptionHandling -> exceptionHandling + .authenticationEntryPoint((request, response, authException) -> { + // Send 403 Forbidden when there is no JWT token provided + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden: Authentication token is missing or invalid"); + }) + ) .addFilterBefore(corsFilter(), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new JWTFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class) // Add SAML2 login configuration (for BENEFICIARI) From 478f16d5660481e7468ce1af1a4d9150102a42eb Mon Sep 17 00:00:00 2001 From: harish Date: Fri, 11 Oct 2024 14:25:30 +0530 Subject: [PATCH 06/10] Refactored code --- .../constants/GepafinConstant.java | 2 + .../gepafin/tendermanagement/dao/CallDao.java | 45 +++++++++++++++++++ .../repositories/DocumentRepository.java | 1 + .../tendermanagement/service/CallService.java | 2 +- .../service/impl/CallServiceImpl.java | 5 +++ .../web/rest/api/CallApi.java | 15 +++++++ .../web/rest/api/impl/CallApiController.java | 20 +++++++++ src/main/resources/message_en.properties | 3 ++ src/main/resources/message_it.properties | 3 ++ 9 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index afbfbea3..d72853c7 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -201,5 +201,7 @@ public class GepafinConstant { public static final String DELEGATION_DELETE_SUCCESS = "delegation.delete.success"; public static final String USER_NOT_AUTHORIZED_TO_CREATE_APPLICATION = "user.not.authorized.create.application"; public static final String APPLICATION_SUBMITTED_CANNOT_CHANGE = "application.submitted.cannot.change"; + public static final String CALL_DOCUMENTS_FETCH_SUCCESS_MSG = "call.documents.fetch.success"; + public static final String CALL_DOCUMENTS_NOT_FOUND_MSG = "call.documents.not.found"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java index c6345d59..0827b62a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CallDao.java @@ -1,5 +1,9 @@ package net.gepafin.tendermanagement.dao; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; @@ -8,13 +12,21 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.service.*; import net.gepafin.tendermanagement.util.DateTimeUtil; import net.gepafin.tendermanagement.util.Utils; +import org.h2.util.IOUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; @@ -85,6 +97,10 @@ public class CallDao { private FlowDao flowDao; @Autowired private FormDao formDao; + @Value("${aws.s3.url.folder}") + private String s3Folder; + @Autowired + private AmazonS3Service amazonS3Service; public CallResponse createCallStep1(CreateCallRequestStep1 createCallRequest, Long userId) { UserEntity userEntity = userService.validateUser(userId); @@ -101,6 +117,35 @@ public class CallDao { return createCallResponseBean; } + public byte[] downloadCallDocumentsAsZip(Long callId) { + List documents = documentRepository.findBySourceIdAndSourceAndTypeAndIsDeletedFalse(callId, DocumentSourceTypeEnum.CALL.getValue(),DocumentTypeEnum.DOCUMENT.getValue()); + if (documents.isEmpty()) { + throw new ResourceNotFoundException(Status.NOT_FOUND, Translator.toLocale(GepafinConstant.DOCUMENT_NOT_FOUND)); + } + + try (ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(zipOutputStream)) { + + for (DocumentEntity document : documents) { + try (InputStream fileInputStream = amazonS3Service.getFile(s3Folder, document.getFileName())) { + ZipEntry zipEntry = new ZipEntry(document.getFileName()); + zos.putNextEntry(zipEntry); + IOUtils.copy(fileInputStream, zos); + zos.closeEntry(); + } catch (IOException e) { + throw new RuntimeException("Error downloading or adding document to ZIP: " + document.getFileName(), e); + } + } + + zos.finish(); + return zipOutputStream.toByteArray(); + + } catch (IOException e) { + throw new RuntimeException("Error while creating ZIP file", e); + } + } + + public CallEntity convertToCallEntity(CreateCallRequestStep1 createCallRequest) { CallEntity callEntity = new CallEntity(); diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java index 339efd13..1543def3 100644 --- a/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java +++ b/src/main/java/net/gepafin/tendermanagement/repositories/DocumentRepository.java @@ -20,6 +20,7 @@ public interface DocumentRepository extends JpaRepository Optional findByIdAndSourceIdAndIsDeletedFalse(Long id, Long sourceId); List findBySource(String source); + List findBySourceIdAndSourceAndTypeAndIsDeletedFalse(Long sourceId, String source, String type); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/CallService.java b/src/main/java/net/gepafin/tendermanagement/service/CallService.java index aa6ea872..9a62d89d 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/CallService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/CallService.java @@ -32,5 +32,5 @@ public interface CallService { CallEntity validateCall(Long callId); CallEntity validatePublishedCall(Long callId); - + byte[] downloadCallDocumentsAsZip(Long callId); } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java index a6a6a901..f6ca0b66 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CallServiceImpl.java @@ -92,4 +92,9 @@ public class CallServiceImpl implements CallService { public CallEntity validatePublishedCall(Long callId) { return callDao.validatePublishedCall(callId); } + @Override + @Transactional(readOnly = true) + public byte[] downloadCallDocumentsAsZip(Long callId) { + return callDao.downloadCallDocumentsAsZip(callId); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java index cc7f985a..3e2861ff 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/CallApi.java @@ -134,4 +134,19 @@ public interface CallApi { public ResponseEntity> updateCallStatus(HttpServletRequest request, @Parameter(description = "The call id", required = true) @PathVariable("callId") Long callId, @Parameter(description = "status", required = true)@RequestParam(value = "status", required = true) CallStatusEnum status); + + @Operation(summary = "Api to download call documents as a ZIP 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)})) + }) + @GetMapping(value = "/{callId}/documents/zip") + ResponseEntity downloadCallDocumentsAsZip(HttpServletRequest httpServletRequest, + @Parameter(description = "The call ID", required = true) @PathVariable("callId") Long callId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java index e4680428..926dccab 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/CallApiController.java @@ -4,7 +4,9 @@ import java.util.List; import net.gepafin.tendermanagement.enums.CallStatusEnum; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RequestMapping; @@ -84,4 +86,22 @@ public class CallApiController implements CallApi { CallResponse updateCall = callService.updateCallStatus(request, callId, status); return ResponseEntity.ok(new Response<>(updateCall, Status.SUCCESS, Translator.toLocale(GepafinConstant.UPDATE_CALL_STATUS_SUCCESS_MSG))); } + @Override + public ResponseEntity downloadCallDocumentsAsZip(HttpServletRequest request, Long callId) { + byte[] zipFile = callService.downloadCallDocumentsAsZip(callId); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); + headers.setContentDispositionFormData("attachment", "documents.zip"); + + if (zipFile == null || zipFile.length == 0) { + String notFoundMessage = Translator.toLocale(GepafinConstant.CALL_DOCUMENTS_NOT_FOUND_MSG); + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(notFoundMessage.getBytes()); + } + + return new ResponseEntity<>(zipFile, headers, HttpStatus.OK); + } + + } \ No newline at end of file diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 0d68c6d7..8ae7bcfa 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -226,5 +226,8 @@ user.company.relation.not.found=User with the specified company relation not fou delegation.delete.success=Delegation deleted successfully. user.not.authorized.create.application=User must be a legal representative or have delegation. application.submitted.cannot.change=The submitted application cannot be changed. +# Call Document Messages +call.documents.fetch.success=Documents fetched successfully. +call.documents.not.found=No documents found for the specified call. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 3e665e82..9b998124 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -222,5 +222,8 @@ delegation.delete.success=Delega eliminata con successo. user.not.authorized.create.application=L'utente deve essere un rappresentante legale o avere una delega. application.submitted.cannot.change=La domanda inviata non puņ essere modificata. +# Call Document Messages +call.documents.fetch.success=Documenti recuperati con successo. +call.documents.not.found=Nessun documento trovato per la chiamata specificata. From d637fd70bdd5aef96b7c72d44ca1487d3b07ab97 Mon Sep 17 00:00:00 2001 From: rajesh Date: Fri, 11 Oct 2024 12:39:04 -0700 Subject: [PATCH 07/10] Added temp API to disbaled faviocn logs --- .../net/gepafin/tendermanagement/web/rest/api/UserApi.java | 6 ++++++ .../web/rest/api/impl/UserApiController.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java index 18281f96..6bb6a388 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java @@ -218,6 +218,12 @@ public interface UserApi { produces = { "application/json" }) ResponseEntity> validateNewUserToken(HttpServletRequest request, @Parameter(description = "The spid token", required = true) @PathVariable("token") String token); + + + + @RequestMapping("favicon.ico") + @ResponseBody + void returnNoFavicon(); diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java index ca13268a..4ffd3e87 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java @@ -140,4 +140,10 @@ public class UserApiController implements UserApi { return ResponseEntity.ok(new Response<>(data, Status.SUCCESS, Translator.toLocale(GepafinConstant.TOKEN_VALIDATE_SUCCESS_MSE))); } + + @Override + public void returnNoFavicon() { + // Do nothing + } + } \ No newline at end of file From e9b7a123fe46c02010a14e72d54423ae92ffe596 Mon Sep 17 00:00:00 2001 From: rajesh Date: Fri, 11 Oct 2024 18:19:24 +0530 Subject: [PATCH 08/10] Done ticket GEPAFINBE-47 --- .../gepafin/tendermanagement/constants/GepafinConstant.java | 1 + .../java/net/gepafin/tendermanagement/dao/CompanyDao.java | 5 +++-- src/main/resources/message_en.properties | 1 + src/main/resources/message_it.properties | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index d72853c7..9fdb1936 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -203,5 +203,6 @@ public class GepafinConstant { public static final String APPLICATION_SUBMITTED_CANNOT_CHANGE = "application.submitted.cannot.change"; public static final String CALL_DOCUMENTS_FETCH_SUCCESS_MSG = "call.documents.fetch.success"; public static final String CALL_DOCUMENTS_NOT_FOUND_MSG = "call.documents.not.found"; + public static final String PERMISSION_DENIED = "permission.denied"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java index 728990b5..3a9b92ad 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/CompanyDao.java @@ -18,6 +18,7 @@ import net.gepafin.tendermanagement.repositories.UserWithCompanyRepository; import net.gepafin.tendermanagement.service.UserService; import net.gepafin.tendermanagement.util.Utils; import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; +import net.gepafin.tendermanagement.web.rest.api.errors.ForbiddenAccessException; import net.gepafin.tendermanagement.web.rest.api.errors.ResourceNotFoundException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; @@ -190,8 +191,8 @@ public class CompanyDao { } public UserWithCompanyEntity validateUserWithCompny(Long userId, Long companyId) { - return userWithCompanyRepository.findByUserIdAndCompanyId(userId, companyId).orElseThrow(() -> new CustomValidationException(Status.UNAUTHORIZED, - Translator.toLocale(GepafinConstant.UNAUTHORIZED))); + return userWithCompanyRepository.findByUserIdAndCompanyId(userId, companyId).orElseThrow(() -> new ForbiddenAccessException(Status.FORBIDDEN, + Translator.toLocale(GepafinConstant.PERMISSION_DENIED))); } public UserWithCompanyEntity getUserWithCompany(Long userId, Long compnayId) { diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 8ae7bcfa..bbf010f5 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -229,5 +229,6 @@ application.submitted.cannot.change=The submitted application cannot be changed. # Call Document Messages call.documents.fetch.success=Documents fetched successfully. call.documents.not.found=No documents found for the specified call. +permission.denied=You are not authorized to access this data. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 9b998124..2235bb51 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -225,5 +225,6 @@ application.submitted.cannot.change=La domanda inviata non pu # Call Document Messages call.documents.fetch.success=Documenti recuperati con successo. call.documents.not.found=Nessun documento trovato per la chiamata specificata. +permission.denied=Non sei autorizzato ad accedere a questi dati. From eb12433a31ba54fcdd57af4b128fedef3125ff58 Mon Sep 17 00:00:00 2001 From: rajesh Date: Sat, 12 Oct 2024 14:47:05 +0530 Subject: [PATCH 09/10] Done ticket GEPAFINBE-41 --- .../constants/GepafinConstant.java | 3 + .../tendermanagement/dao/ApplicationDao.java | 81 ++++++++++++++++++- .../ApplicationSignedDocumentEntity.java | 28 +++++++ .../ApplicationSignedDocumentStatusEnum.java | 18 +++++ .../ApplicationSignedDocumentResponse.java | 14 ++++ .../response/CompanyDelegationResponse.java | 3 +- .../UploadFileOnAmazonS3Response.java | 14 ++++ .../ApplicationSignedDocumentRepository.java | 13 +++ .../service/AmazonS3Service.java | 4 + .../service/ApplicationService.java | 7 ++ .../service/impl/AmazonS3ServiceImpl.java | 25 ++++++ .../service/impl/ApplicationServiceImpl.java | 16 +++- .../service/impl/CompanyServiceImpl.java | 3 +- .../tendermanagement/util/Validator.java | 5 +- .../web/rest/api/ApplicationApi.java | 27 +++++++ .../api/impl/ApplicationApiController.java | 22 +++++ src/main/resources/application.properties | 1 + .../db/changelog/db.changelog-1.0.0.xml | 25 ++++++ src/main/resources/message_en.properties | 3 + src/main/resources/message_it.properties | 3 + 20 files changed, 307 insertions(+), 8 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/ApplicationSignedDocumentEntity.java create mode 100644 src/main/java/net/gepafin/tendermanagement/enums/ApplicationSignedDocumentStatusEnum.java create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/UploadFileOnAmazonS3Response.java create mode 100644 src/main/java/net/gepafin/tendermanagement/repositories/ApplicationSignedDocumentRepository.java diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 9fdb1936..4580af18 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -204,5 +204,8 @@ public class GepafinConstant { public static final String CALL_DOCUMENTS_FETCH_SUCCESS_MSG = "call.documents.fetch.success"; public static final String CALL_DOCUMENTS_NOT_FOUND_MSG = "call.documents.not.found"; public static final String PERMISSION_DENIED = "permission.denied"; + public static final String SIGNED_DOCUMENT_FILE_UPLOAD_SUCCESS = "signed.document.file.upload.success"; + public static final String GET_SIGNED_DOCUMENT_FILE_SUCCESS = "get.signed.document.file.success"; + public static final String APPLICATION_SIGNED_DOCUMENT_NOT_FOUND = "application.signed.document.not.found"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index 634594ba..c12f6d4e 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -3,6 +3,7 @@ package net.gepafin.tendermanagement.dao; import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.*; +import net.gepafin.tendermanagement.enums.ApplicationSignedDocumentStatusEnum; import net.gepafin.tendermanagement.enums.ApplicationStatusTypeEnum; import net.gepafin.tendermanagement.enums.DocumentSourceTypeEnum; import net.gepafin.tendermanagement.enums.RoleStatusEnum; @@ -12,6 +13,7 @@ import net.gepafin.tendermanagement.model.request.ApplicationRequest; import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.response.*; import net.gepafin.tendermanagement.repositories.*; +import net.gepafin.tendermanagement.service.AmazonS3Service; import net.gepafin.tendermanagement.service.CallService; import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.service.DocumentService; @@ -26,10 +28,13 @@ 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.beans.factory.annotation.Value; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; import jakarta.persistence.criteria.Predicate; +import jakarta.servlet.http.HttpServletRequest; import java.text.MessageFormat; import java.time.LocalDateTime; @@ -71,17 +76,27 @@ public class ApplicationDao { @Autowired private FlowDataRepository flowDataRepository; - @Autowired - private UserWithCompanyRepository userWithCompanyRepository; + @Autowired private UserCompanyDelegationRepository userCompanyDelegationRepository; + @Autowired private Validator validator; + @Autowired private CompanyService companyService; @Autowired private ProtocolRepository protocolRepository; + + @Autowired + private AmazonS3Service amazonS3Service; + + @Autowired + private ApplicationSignedDocumentRepository applicationSignedDocumentRepository; + + @Value("${aws.s3.url.folder.signed.document}") + private String signedDocumentS3Folder; public ApplicationResponseBean createApplication(ApplicationRequestBean applicationRequestBean, UserEntity userEntity, Long formId, Long applicationId) { @@ -663,4 +678,66 @@ public class ApplicationDao { protocolRepository.save(protocolEntity); return protocolEntity; } + + public ApplicationSignedDocumentResponse uploadSignedDocument(HttpServletRequest request, Long applicationId, + MultipartFile file) { + ApplicationEntity applicationEntity = validateApplication(applicationId); + validator.validateUserWithCompany(request, applicationEntity.getCompany().getId()); + validateFileType(file); + ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository + .findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); + if (applicationSignedDocument != null) { + applicationSignedDocument.setStatus(ApplicationSignedDocumentStatusEnum.INACTIVE.getValue()); + applicationSignedDocumentRepository.save(applicationSignedDocument); + } + UploadFileOnAmazonS3Response uploadFileOnAmazonS3 = amazonS3Service.uploadFileOnAmazonS3(signedDocumentS3Folder, + file); + applicationSignedDocument = new ApplicationSignedDocumentEntity(); + applicationSignedDocument.setApplication(applicationEntity); + applicationSignedDocument.setFileName(uploadFileOnAmazonS3.getFileName()); + applicationSignedDocument.setFilePath(uploadFileOnAmazonS3.getFilePath()); + applicationSignedDocument.setStatus(ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); + applicationSignedDocumentRepository.save(applicationSignedDocument); + return convertApplicationSignedDocumentToApplicationSignedDocumentResponse(applicationSignedDocument); + } + + private ApplicationSignedDocumentResponse convertApplicationSignedDocumentToApplicationSignedDocumentResponse( + ApplicationSignedDocumentEntity applicationSignedDocument) { + ApplicationSignedDocumentResponse applicationSignedDocumentResponse = new ApplicationSignedDocumentResponse(); + applicationSignedDocumentResponse.setId(applicationSignedDocument.getId()); + applicationSignedDocumentResponse.setApplicationId(applicationSignedDocument.getApplication().getId()); + applicationSignedDocumentResponse.setFileName(applicationSignedDocument.getFileName()); + applicationSignedDocumentResponse.setFilePath(applicationSignedDocument.getFilePath()); + applicationSignedDocumentResponse + .setStatus(ApplicationSignedDocumentStatusEnum.valueOf(applicationSignedDocument.getStatus())); + applicationSignedDocumentResponse.setCreatedDate(applicationSignedDocument.getCreatedDate()); + applicationSignedDocumentResponse.setUpdatedDate(applicationSignedDocument.getUpdatedDate()); + return applicationSignedDocumentResponse; + } + + private void validateFileType(MultipartFile file) { + if (file.isEmpty()) { + throw new CustomValidationException(Status.VALIDATION_ERROR, + Translator.toLocale(GepafinConstant.VALIDATION_ERROR_FILE_EMPTY)); + } + String filename = file.getOriginalFilename(); + if (filename == null || !filename.endsWith(".p7m")) { + throw new CustomValidationException(Status.VALIDATION_ERROR, + Translator.toLocale(GepafinConstant.VALIDATION_ERROR_FILE_INVALIDTYPE)); + } + } + + public ApplicationSignedDocumentResponse getSignedDocument(HttpServletRequest request, Long applicationId) { + + ApplicationEntity applicationEntity = validateApplication(applicationId); + validator.validateUserWithCompany(request, applicationEntity.getCompany().getId()); + + ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository + .findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); + if(applicationSignedDocument == null) { + throw new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.APPLICATION_SIGNED_DOCUMENT_NOT_FOUND)); + } + return convertApplicationSignedDocumentToApplicationSignedDocumentResponse(applicationSignedDocument); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/ApplicationSignedDocumentEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationSignedDocumentEntity.java new file mode 100644 index 00000000..58975cca --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/ApplicationSignedDocumentEntity.java @@ -0,0 +1,28 @@ +package net.gepafin.tendermanagement.entities; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.Data; + +@Data +@Entity +@Table(name = "application_signed_document") +public class ApplicationSignedDocumentEntity extends BaseEntity { + + @ManyToOne + @JoinColumn(name = "APPLICATION_ID") + private ApplicationEntity application; + + @Column(name = "FILE_NAME") + private String fileName; + + @Column(name = "FILE_PATH") + private String filePath; + + @Column(name="STATUS") + private String status; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/enums/ApplicationSignedDocumentStatusEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationSignedDocumentStatusEnum.java new file mode 100644 index 00000000..c0064d87 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/enums/ApplicationSignedDocumentStatusEnum.java @@ -0,0 +1,18 @@ +package net.gepafin.tendermanagement.enums; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum ApplicationSignedDocumentStatusEnum { + ACTIVE("ACTIVE"), INACTIVE("INACTIVE"); + + private String value; + + ApplicationSignedDocumentStatusEnum(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java new file mode 100644 index 00000000..64b380f5 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/ApplicationSignedDocumentResponse.java @@ -0,0 +1,14 @@ +package net.gepafin.tendermanagement.model.response; + +import lombok.Data; +import net.gepafin.tendermanagement.enums.ApplicationSignedDocumentStatusEnum; +import net.gepafin.tendermanagement.model.BaseBean; + +@Data +public class ApplicationSignedDocumentResponse extends BaseBean{ + + private Long applicationId; + private String fileName; + private String filePath; + private ApplicationSignedDocumentStatusEnum status; +} diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/CompanyDelegationResponse.java b/src/main/java/net/gepafin/tendermanagement/model/response/CompanyDelegationResponse.java index 7c23b3b8..f1b69b33 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/CompanyDelegationResponse.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/CompanyDelegationResponse.java @@ -3,9 +3,10 @@ package net.gepafin.tendermanagement.model.response; import lombok.Data; import net.gepafin.tendermanagement.entities.BaseEntity; import net.gepafin.tendermanagement.enums.UserCompanyDelegationStatusEnum; +import net.gepafin.tendermanagement.model.BaseBean; @Data -public class CompanyDelegationResponse extends BaseEntity{ +public class CompanyDelegationResponse extends BaseBean{ private Long userId; private Long companyId; private Long beneficiaryId; diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/UploadFileOnAmazonS3Response.java b/src/main/java/net/gepafin/tendermanagement/model/response/UploadFileOnAmazonS3Response.java new file mode 100644 index 00000000..d0d78428 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/UploadFileOnAmazonS3Response.java @@ -0,0 +1,14 @@ +package net.gepafin.tendermanagement.model.response; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class UploadFileOnAmazonS3Response { + + private String fileName; + + private String filePath; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationSignedDocumentRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationSignedDocumentRepository.java new file mode 100644 index 00000000..35322a6a --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/ApplicationSignedDocumentRepository.java @@ -0,0 +1,13 @@ +package net.gepafin.tendermanagement.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import net.gepafin.tendermanagement.entities.ApplicationSignedDocumentEntity; + +@Repository +public interface ApplicationSignedDocumentRepository extends JpaRepository { + + ApplicationSignedDocumentEntity findByApplicationIdAndStatus(Long applicationId, String status); + +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java b/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java index ce34cd7d..ea3937a3 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java +++ b/src/main/java/net/gepafin/tendermanagement/service/AmazonS3Service.java @@ -3,6 +3,8 @@ package net.gepafin.tendermanagement.service; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; +import net.gepafin.tendermanagement.model.response.UploadFileOnAmazonS3Response; + import java.io.IOException; import java.io.InputStream; @@ -14,4 +16,6 @@ public interface AmazonS3Service { public Boolean delete(String s3Folder, String fileName); InputStream getFile(String s3Folder, String filePath) throws IOException; + + public UploadFileOnAmazonS3Response uploadFileOnAmazonS3(String s3Folder, MultipartFile file); } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java index edb62c93..d05ee2eb 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java @@ -9,10 +9,13 @@ import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.response.ApplicationGetResponseBean; import net.gepafin.tendermanagement.model.response.ApplicationResponse; import net.gepafin.tendermanagement.model.response.ApplicationResponseBean; +import net.gepafin.tendermanagement.model.response.ApplicationSignedDocumentResponse; import net.gepafin.tendermanagement.model.response.NextOrPreviousFormResponse; import java.util.List; +import org.springframework.web.multipart.MultipartFile; + public interface ApplicationService { public ApplicationResponseBean createApplication(HttpServletRequest request, ApplicationRequestBean applicationRequestBean,Long applicationId, Long formId); @@ -31,4 +34,8 @@ public interface ApplicationService { public ApplicationResponse updateApplicationStatus(HttpServletRequest request, Long applicationId, ApplicationStatusTypeEnum status); + public ApplicationSignedDocumentResponse uploadSignedDocument(HttpServletRequest request, Long applicationId, MultipartFile file); + + public ApplicationSignedDocumentResponse getSignedDocument(HttpServletRequest request, Long applicationId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java index 756e4360..a0470c15 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AmazonS3ServiceImpl.java @@ -2,7 +2,16 @@ package net.gepafin.tendermanagement.service.impl; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.*; + +import net.gepafin.tendermanagement.config.Translator; +import net.gepafin.tendermanagement.constants.GepafinConstant; +import net.gepafin.tendermanagement.model.response.UploadFileOnAmazonS3Response; import net.gepafin.tendermanagement.service.AmazonS3Service; +import net.gepafin.tendermanagement.util.Utils; +import net.gepafin.tendermanagement.web.rest.api.errors.CustomValidationException; +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.core.env.Environment; @@ -86,4 +95,20 @@ public class AmazonS3ServiceImpl implements AmazonS3Service { throw new IOException("Error getting file from Amazon S3", e); } } + + @Override + public UploadFileOnAmazonS3Response uploadFileOnAmazonS3(String s3Folder, MultipartFile file) { + String extension = FilenameUtils.getExtension(file.getOriginalFilename()); + String fileName = org.springframework.util.StringUtils.cleanPath(file.getOriginalFilename()); + String firstNameContain = fileName.substring(0, fileName.lastIndexOf('.')); + firstNameContain+=Utils.randomKey(5); + fileName = (firstNameContain + "." + extension); + try { + String filepath = upload(fileName, s3Folder, file); + return UploadFileOnAmazonS3Response.builder().fileName(fileName).filePath(filepath).build(); + } catch (Exception e) { + throw new CustomValidationException(Status.VALIDATION_ERROR, + Translator.toLocale(GepafinConstant.UPLOAD_ERROR_S3)); + } + } } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java index a082a092..56658ee3 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java @@ -13,12 +13,14 @@ import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.response.ApplicationGetResponseBean; import net.gepafin.tendermanagement.model.response.ApplicationResponse; import net.gepafin.tendermanagement.model.response.ApplicationResponseBean; +import net.gepafin.tendermanagement.model.response.ApplicationSignedDocumentResponse; import net.gepafin.tendermanagement.model.response.NextOrPreviousFormResponse; import net.gepafin.tendermanagement.service.ApplicationService; import net.gepafin.tendermanagement.util.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import java.util.List; @@ -64,7 +66,7 @@ public class ApplicationServiceImpl implements ApplicationService { @Transactional(rollbackFor = Exception.class) public ApplicationResponse createApplication(HttpServletRequest request, Long companyId, ApplicationRequest applicationRequest, Long callId) { UserEntity userEntity = validator.validateUser(request); - CompanyEntity companyEntity = validator.validateUSerWithCompany(request, companyId); + CompanyEntity companyEntity = validator.validateUserWithCompany(request, companyId); return applicationDao.createApplicationByCallId(companyEntity, applicationRequest, callId, userEntity); } @@ -87,8 +89,18 @@ public class ApplicationServiceImpl implements ApplicationService { public List getAllApplications(HttpServletRequest request, Long callId, Long companyId) { UserEntity userEntity = validator.validateUser(request); if (companyId != null) { - validator.validateUSerWithCompany(request, companyId); + validator.validateUserWithCompany(request, companyId); } return applicationDao.getAllApplications(userEntity, callId, companyId); } + @Override + @Transactional(rollbackFor = Exception.class) + public ApplicationSignedDocumentResponse uploadSignedDocument(HttpServletRequest request, Long applicationId, MultipartFile file) { + return applicationDao.uploadSignedDocument(request, applicationId, file); + } + + @Override + public ApplicationSignedDocumentResponse getSignedDocument(HttpServletRequest request, Long applicationId) { + return applicationDao.getSignedDocument(request, applicationId); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java index 1f80b223..033ddba3 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/CompanyServiceImpl.java @@ -98,7 +98,8 @@ public class CompanyServiceImpl implements CompanyService { @Override @Transactional(rollbackFor = Exception.class) public CompanyDelegationResponse uploadCompanyDelegation(HttpServletRequest request, Long companyId, MultipartFile file) { - UserEntity userEntity =validator.validateUser(request); + UserEntity userEntity = validator.validateUser(request); + validator.validateUserWithCompany(request, companyId); return delegationDao.uploadCompanyDelegation(userEntity, companyId, file); } diff --git a/src/main/java/net/gepafin/tendermanagement/util/Validator.java b/src/main/java/net/gepafin/tendermanagement/util/Validator.java index e123988a..bb7d4053 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Validator.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Validator.java @@ -9,6 +9,7 @@ import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.enums.RoleStatusEnum; import net.gepafin.tendermanagement.service.CompanyService; import net.gepafin.tendermanagement.service.UserService; +import net.gepafin.tendermanagement.web.rest.api.errors.ForbiddenAccessException; import net.gepafin.tendermanagement.web.rest.api.errors.Status; import net.gepafin.tendermanagement.web.rest.api.errors.UnauthorizedAccessException; @@ -60,7 +61,7 @@ public class Validator { } } - public CompanyEntity validateUSerWithCompany(HttpServletRequest request, Long companyId) { + public CompanyEntity validateUserWithCompany(HttpServletRequest request, Long companyId) { if (checkIsSuperAdmin()) { return companyService.validateCompany(companyId); } @@ -89,7 +90,7 @@ public class Validator { public UserEntity validateUserId(HttpServletRequest request, Long userId) { UserEntity user = validateUser(request); if(user.getRoleEntity().getRoleType().equals(RoleStatusEnum.ROLE_BENEFICIARY.getValue()) && Boolean.FALSE.equals(user.getId().equals(userId))) { - throw new UnauthorizedAccessException(Status.UNAUTHORIZED, Translator.toLocale(GepafinConstant.INVALID_REQUEST)); + throw new ForbiddenAccessException(Status.FORBIDDEN, Translator.toLocale(GepafinConstant.PERMISSION_DENIED)); } return userService.validateUser(userId); } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java index 1869655c..eee93d90 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java @@ -6,6 +6,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -21,6 +22,8 @@ import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.response.ApplicationGetResponseBean; import net.gepafin.tendermanagement.model.response.ApplicationResponse; import net.gepafin.tendermanagement.model.response.ApplicationResponseBean; +import net.gepafin.tendermanagement.model.response.ApplicationSignedDocumentResponse; +import net.gepafin.tendermanagement.model.response.CompanyDelegationResponse; import net.gepafin.tendermanagement.model.response.NextOrPreviousFormResponse; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants; @@ -131,6 +134,30 @@ public interface ApplicationApi { @Parameter(description = "The application id", required = true) @PathVariable("applicationId") Long applicationId, @Parameter(description = "status", required = true)@RequestParam(value = "status", required = true) ApplicationStatusTypeEnum status); + @Operation(summary = "Api to upload signed document (only p7m file format is supported)", 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 = "{applicationId}/signedDocument/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + ResponseEntity> uploadSignedDocument(HttpServletRequest request, + @Parameter(description = "The applicationId id", required = true) @PathVariable("applicationId") Long applicationId, + @Parameter(description = "The signed document", required = true) @RequestParam("file") MultipartFile file); + + + @Operation(summary = "Api to get signed document", 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) })) }) + @GetMapping(value = "{applicationId}/signedDocument", produces = "application/json") + ResponseEntity> getSignedDocument(HttpServletRequest request, + @Parameter(description = "The applicationId id", required = true) @PathVariable("applicationId") Long applicationId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java index bcbf8e80..b79196c3 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java @@ -10,6 +10,8 @@ import net.gepafin.tendermanagement.model.request.ApplicationRequestBean; import net.gepafin.tendermanagement.model.response.ApplicationGetResponseBean; import net.gepafin.tendermanagement.model.response.ApplicationResponse; import net.gepafin.tendermanagement.model.response.ApplicationResponseBean; +import net.gepafin.tendermanagement.model.response.ApplicationSignedDocumentResponse; +import net.gepafin.tendermanagement.model.response.CompanyDelegationResponse; import net.gepafin.tendermanagement.model.response.NextOrPreviousFormResponse; import net.gepafin.tendermanagement.model.util.Response; import net.gepafin.tendermanagement.service.ApplicationService; @@ -21,6 +23,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; import org.slf4j.Logger; import java.util.List; @@ -89,4 +92,23 @@ public class ApplicationApiController implements ApplicationApi { return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(applicationResponse, Status.SUCCESS, Translator.toLocale(GepafinConstant.APPLICATION_STATUS_UPDATED_SUCCESSFULLY))); } + + @Override + public ResponseEntity> uploadSignedDocument(HttpServletRequest request, + Long applicationId, MultipartFile file) { + log.info("upload signed document applicationId: {}", applicationId); + ApplicationSignedDocumentResponse response = applicationService.uploadSignedDocument(request, applicationId, file); + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(response, Status.SUCCESS, Translator.toLocale(GepafinConstant.SIGNED_DOCUMENT_FILE_UPLOAD_SUCCESS))); + } + + @Override + public ResponseEntity> getSignedDocument(HttpServletRequest request, + Long applicationId) { + ApplicationSignedDocumentResponse response = applicationService.getSignedDocument(request, applicationId); + log.info("get signed document applicationId: {}", applicationId); + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(response, Status.SUCCESS, Translator.toLocale(GepafinConstant.GET_SIGNED_DOCUMENT_FILE_SUCCESS))); + } + } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 27151cbc..175c7e6c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -32,6 +32,7 @@ aws.s3.bucket.name=mementoresources aws.s3.url = https://mementoresources.s3.eu-west-1.amazonaws.com/ aws.s3.url.folder=gepafin aws.s3.url.folder.delegation=gepafin/delegation +aws.s3.url.folder.signed.document=gepafin/signed-document # JWT configuration # Ensure these values match your expectations security.authentication.jwt.secret=my-secret-token-to-change-in-prod-environment-your-super-secure-randomly-generated-key diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 98016d3c..a1369e93 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -973,4 +973,29 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index bbf010f5..49208615 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -230,5 +230,8 @@ application.submitted.cannot.change=The submitted application cannot be changed. call.documents.fetch.success=Documents fetched successfully. call.documents.not.found=No documents found for the specified call. permission.denied=You are not authorized to access this data. +signed.document.file.upload.success=Signed document file uploaded successfully. +get.signed.document.file.success=Signed document file retrieved successfully. +application.signed.document.not.found=Signed document for the application not found. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 2235bb51..7fe8f0ff 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -226,5 +226,8 @@ application.submitted.cannot.change=La domanda inviata non pu call.documents.fetch.success=Documenti recuperati con successo. call.documents.not.found=Nessun documento trovato per la chiamata specificata. permission.denied=Non sei autorizzato ad accedere a questi dati. +signed.document.file.upload.success=File del documento firmato caricato con successo. +get.signed.document.file.success=File del documento firmato recuperato con successo. +application.signed.document.not.found=Documento firmato per l'applicazione non trovato. From 628a350959bd4b4bcf5efeb1f553cd29d5685f56 Mon Sep 17 00:00:00 2001 From: rajesh Date: Sat, 12 Oct 2024 15:19:35 +0530 Subject: [PATCH 10/10] updated code --- .../constants/GepafinConstant.java | 1 + .../tendermanagement/dao/ApplicationDao.java | 14 ++++++++++++++ .../service/ApplicationService.java | 2 ++ .../service/impl/ApplicationServiceImpl.java | 8 ++++++++ .../web/rest/api/ApplicationApi.java | 11 +++++++++++ .../rest/api/impl/ApplicationApiController.java | 9 +++++++++ src/main/resources/message_en.properties | 1 + src/main/resources/message_it.properties | 1 + 8 files changed, 47 insertions(+) diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 4580af18..13ca091b 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -207,5 +207,6 @@ public class GepafinConstant { public static final String SIGNED_DOCUMENT_FILE_UPLOAD_SUCCESS = "signed.document.file.upload.success"; public static final String GET_SIGNED_DOCUMENT_FILE_SUCCESS = "get.signed.document.file.success"; public static final String APPLICATION_SIGNED_DOCUMENT_NOT_FOUND = "application.signed.document.not.found"; + public static final String DELETE_SIGNED_DOCUMENT_FILE_SUCCESS = "delete.signed.document.file.success"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java index c12f6d4e..c79f7f99 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/ApplicationDao.java @@ -740,4 +740,18 @@ public class ApplicationDao { } return convertApplicationSignedDocumentToApplicationSignedDocumentResponse(applicationSignedDocument); } + + public void deleteSignedDocument(HttpServletRequest request, Long applicationId) { + ApplicationEntity applicationEntity = validateApplication(applicationId); + validator.validateUserWithCompany(request, applicationEntity.getCompany().getId()); + + ApplicationSignedDocumentEntity applicationSignedDocument = applicationSignedDocumentRepository + .findByApplicationIdAndStatus(applicationId, ApplicationSignedDocumentStatusEnum.ACTIVE.getValue()); + if(applicationSignedDocument == null) { + throw new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.APPLICATION_SIGNED_DOCUMENT_NOT_FOUND)); + } + applicationSignedDocument.setStatus(ApplicationSignedDocumentStatusEnum.INACTIVE.getValue()); + applicationSignedDocumentRepository.save(applicationSignedDocument); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java index d05ee2eb..2d914b64 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/ApplicationService.java @@ -38,4 +38,6 @@ public interface ApplicationService { public ApplicationSignedDocumentResponse getSignedDocument(HttpServletRequest request, Long applicationId); + public void deleteSignedDocument(HttpServletRequest request, Long applicationId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java index 56658ee3..faa890d3 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/ApplicationServiceImpl.java @@ -100,7 +100,15 @@ public class ApplicationServiceImpl implements ApplicationService { } @Override + @Transactional(readOnly = true) public ApplicationSignedDocumentResponse getSignedDocument(HttpServletRequest request, Long applicationId) { return applicationDao.getSignedDocument(request, applicationId); } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteSignedDocument(HttpServletRequest request, Long applicationId) { + applicationDao.deleteSignedDocument(request, applicationId); + } + } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java index eee93d90..e19484b1 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/ApplicationApi.java @@ -157,6 +157,17 @@ public interface ApplicationApi { @GetMapping(value = "{applicationId}/signedDocument", produces = "application/json") ResponseEntity> getSignedDocument(HttpServletRequest request, @Parameter(description = "The applicationId id", required = true) @PathVariable("applicationId") Long applicationId); + + @Operation(summary = "Api to delete signed document", 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) })) }) + @DeleteMapping(value = "{applicationId}/signedDocument", produces = "application/json") + ResponseEntity> deleteSignedDocument(HttpServletRequest request, + @Parameter(description = "The applicationId id", required = true) @PathVariable("applicationId") Long applicationId); } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java index b79196c3..85c1efbb 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/ApplicationApiController.java @@ -110,5 +110,14 @@ public class ApplicationApiController implements ApplicationApi { return ResponseEntity.status(HttpStatus.OK) .body(new Response<>(response, Status.SUCCESS, Translator.toLocale(GepafinConstant.GET_SIGNED_DOCUMENT_FILE_SUCCESS))); } + + @Override + public ResponseEntity> deleteSignedDocument(HttpServletRequest request, + Long applicationId) { + applicationService.deleteSignedDocument(request, applicationId); + log.info("delete signed document applicationId: {}", applicationId); + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.DELETE_SIGNED_DOCUMENT_FILE_SUCCESS))); + } } diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 49208615..d09b9d29 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -233,5 +233,6 @@ permission.denied=You are not authorized to access this data. signed.document.file.upload.success=Signed document file uploaded successfully. get.signed.document.file.success=Signed document file retrieved successfully. application.signed.document.not.found=Signed document for the application not found. +delete.signed.document.file.success=Signed document deleted successfully. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 7fe8f0ff..1b9b3203 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -229,5 +229,6 @@ permission.denied=Non sei autorizzato ad accedere a questi dati. signed.document.file.upload.success=File del documento firmato caricato con successo. get.signed.document.file.success=File del documento firmato recuperato con successo. application.signed.document.not.found=Documento firmato per l'applicazione non trovato. +delete.signed.document.file.success=Documento firmato eliminato con successo.