diff --git a/services/contracts/pom.xml b/services/contracts/pom.xml index a377bb9a..2a000b1c 100644 --- a/services/contracts/pom.xml +++ b/services/contracts/pom.xml @@ -20,6 +20,10 @@ 21 + + org.springframework.boot + spring-boot-starter-amqp + org.springframework.boot spring-boot-starter-web @@ -36,17 +40,57 @@ org.springframework.boot - spring-boot-starter-data-cassandra + spring-boot-testcontainers + test - org.springframework.boot - spring-boot-starter-amqp + org.testcontainers + junit-jupiter + 1.19.7 + test + + + org.testcontainers + cassandra + 1.19.7 + test + + + org.testcontainers + rabbitmq + 1.19.7 + test + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.16.0 org.springframework.amqp spring-rabbit-test test + + org.springframework.boot + spring-boot-starter-data-cassandra + + + org.springframework.boot + spring-boot-starter-data-redis + 3.1.2 + + + com.redis.testcontainers + testcontainers-redis-junit-jupiter + 1.4.6 + test + + + redis.clients + jedis + 3.7.0 + org.projectlombok lombok diff --git a/services/contracts/src/main/java/com/workup/contracts/ContractsApplication.java b/services/contracts/src/main/java/com/workup/contracts/ContractsApplication.java index f4d5087c..fac6783f 100644 --- a/services/contracts/src/main/java/com/workup/contracts/ContractsApplication.java +++ b/services/contracts/src/main/java/com/workup/contracts/ContractsApplication.java @@ -12,9 +12,13 @@ import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; @SpringBootApplication +@ComponentScan(basePackages = "com.workup") +@EnableCaching public class ContractsApplication { public static void main(String[] args) { diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/ContractCommand.java b/services/contracts/src/main/java/com/workup/contracts/commands/ContractCommand.java index b2fef076..998734e3 100644 --- a/services/contracts/src/main/java/com/workup/contracts/commands/ContractCommand.java +++ b/services/contracts/src/main/java/com/workup/contracts/commands/ContractCommand.java @@ -6,14 +6,20 @@ import com.workup.shared.commands.Command; import com.workup.shared.commands.CommandRequest; import com.workup.shared.commands.CommandResponse; +import com.workup.shared.redis.RedisService; import lombok.Setter; +import org.springframework.amqp.core.AmqpTemplate; public abstract class ContractCommand implements Command { + @Setter AmqpTemplate rabbitTemplate; + @Setter ContractRepository contractRepository; @Setter ContractMilestoneRepository contractMilestoneRepository; @Setter TerminationRequestRepository terminationRequestRepository; + + @Setter RedisService redisService; } diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/ContractCommandMap.java b/services/contracts/src/main/java/com/workup/contracts/commands/ContractCommandMap.java index acacec8e..1f12ad3b 100644 --- a/services/contracts/src/main/java/com/workup/contracts/commands/ContractCommandMap.java +++ b/services/contracts/src/main/java/com/workup/contracts/commands/ContractCommandMap.java @@ -6,6 +6,8 @@ import com.workup.shared.commands.CommandMap; import com.workup.shared.commands.CommandRequest; import com.workup.shared.commands.CommandResponse; +import com.workup.shared.redis.RedisService; +import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -19,6 +21,10 @@ public class ContractCommandMap @Autowired TerminationRequestRepository terminationRequestRepository; + @Autowired AmqpTemplate rabbitTemplate; + + @Autowired RedisService redisService; + public void registerCommands() { commands.put("InitiateContract", InitiateContractCommand.class); commands.put("RequestContractTermination", RequestContractTerminationCommand.class); @@ -34,5 +40,7 @@ public void setupCommand( command.setContractRepository(contractRepository); command.setContractMilestoneRepository(contractMilestoneRepository); command.setTerminationRequestRepository(terminationRequestRepository); + command.setRabbitTemplate(rabbitTemplate); + command.setRedisService(redisService); } } diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/EvaluateMilestoneCommand.java b/services/contracts/src/main/java/com/workup/contracts/commands/EvaluateMilestoneCommand.java new file mode 100644 index 00000000..f5df099d --- /dev/null +++ b/services/contracts/src/main/java/com/workup/contracts/commands/EvaluateMilestoneCommand.java @@ -0,0 +1,82 @@ +package com.workup.contracts.commands; + +import com.workup.contracts.logger.ContractsLogger; +import com.workup.contracts.models.Contract; +import com.workup.contracts.models.ContractMilestone; +import com.workup.shared.commands.contracts.requests.EvaluateMilestoneRequest; +import com.workup.shared.commands.contracts.responses.EvaluateMilestoneResponse; +import com.workup.shared.commands.payments.paymentrequest.requests.CreatePaymentRequestRequest; +import com.workup.shared.enums.HttpStatusCode; +import com.workup.shared.enums.ServiceQueueNames; +import com.workup.shared.enums.contracts.MilestoneState; +import java.util.Optional; +import java.util.UUID; + +public class EvaluateMilestoneCommand + extends ContractCommand { + private EvaluateMilestoneResponse isValid(Optional milestoneOptional) { + if (milestoneOptional.isEmpty()) + return EvaluateMilestoneResponse.builder() + .withStatusCode(HttpStatusCode.BAD_REQUEST) + .withErrorMessage("Milestone is not found") + .build(); + if (milestoneOptional.get().getStatus() != MilestoneState.IN_REVIEW) + return EvaluateMilestoneResponse.builder() + .withStatusCode(HttpStatusCode.BAD_REQUEST) + .withErrorMessage("Milestone cannot be evaluated as it has not progressed enough") + .build(); + return null; + } + + @Override + public EvaluateMilestoneResponse Run(EvaluateMilestoneRequest request) { + Optional milestoneOptional = + contractMilestoneRepository.findById(UUID.fromString(request.getMilestoneId())); + + EvaluateMilestoneResponse checkerResponse = isValid(milestoneOptional); + if (checkerResponse != null) return checkerResponse; + + ContractMilestone updatedMilestone = milestoneOptional.get(); + + updatedMilestone.setStatus(request.getEvaluatedState()); + + try { + contractMilestoneRepository.save(updatedMilestone); + ContractsLogger.print(" [x] Milestone evaluated " + updatedMilestone); + + if (request.getEvaluatedState() == MilestoneState.ACCEPTED) { + ContractsLogger.print(" [x] Sending payment request "); + // Getting the contract as we need to send the freelancer and client id since they are + // in the payment request parameters. + Optional contractOptional = + contractRepository.findById(UUID.fromString(updatedMilestone.getContractId())); + if (contractOptional.isEmpty()) + throw new Exception("Contract Optional was empty, therefore unable to fetch data"); + + Contract milestoneContract = contractOptional.get(); + + CreatePaymentRequestRequest externalRequest = + CreatePaymentRequestRequest.builder() + .withAmount(updatedMilestone.getAmount()) + .withClientId(milestoneContract.getClientId()) + .withFreelancerId(milestoneContract.getFreelancerId()) + .withDescription(updatedMilestone.getMilestoneId().toString()) + .build(); + rabbitTemplate.convertSendAndReceive(ServiceQueueNames.PAYMENTS, externalRequest); + ContractsLogger.print(" [x] Payment request sent "); + } + + return EvaluateMilestoneResponse.builder() + .withStatusCode(HttpStatusCode.OK) + .withErrorMessage("") + .build(); + + } catch (Exception e) { + e.printStackTrace(); + return EvaluateMilestoneResponse.builder() + .withStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR) + .withErrorMessage(e.getMessage()) + .build(); + } + } +} diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/GetContractCommand.java b/services/contracts/src/main/java/com/workup/contracts/commands/GetContractCommand.java new file mode 100644 index 00000000..8621c65e --- /dev/null +++ b/services/contracts/src/main/java/com/workup/contracts/commands/GetContractCommand.java @@ -0,0 +1,54 @@ +package com.workup.contracts.commands; + +import com.workup.contracts.logger.ContractsLogger; +import com.workup.contracts.models.Contract; +import com.workup.shared.commands.contracts.requests.GetContractRequest; +import com.workup.shared.commands.contracts.responses.GetContractResponse; +import com.workup.shared.enums.HttpStatusCode; +import java.util.Optional; +import java.util.UUID; + +public class GetContractCommand extends ContractCommand { + + @Override + public GetContractResponse Run(GetContractRequest request) { + String cachingKey = request.getContractId(); + GetContractResponse cachedResponse = + (GetContractResponse) redisService.getValue(cachingKey, GetContractResponse.class); + if (cachedResponse != null) { + ContractsLogger.print( + "[x] Contract request response fetched from cache: " + cachedResponse.toString()); + + return cachedResponse; + } + + Optional contractOptional = + contractRepository.findById(UUID.fromString(request.getContractId())); + + if (contractOptional.isEmpty()) { + return GetContractResponse.builder() + .withStatusCode(HttpStatusCode.NOT_FOUND) + .withErrorMessage("Requested contract does not exist") + .build(); + } + + Contract contract = contractOptional.get(); + + GetContractResponse response = + GetContractResponse.builder() + .withContractId(contract.getContractId().toString()) + .withProposalId(contract.getProposalId()) + .withJobId(contract.getJobId()) + .withJobTitle(contract.getJobTitle()) + .withClientId(contract.getClientId()) + .withFreelancerId(contract.getFreelancerId()) + .withMilestonesIds(contract.getMilestonesIds()) + .withStatus(contract.getStatus()) + .withStatusCode(HttpStatusCode.OK) + .withErrorMessage("") + .build(); + + redisService.setValue(cachingKey, response); + return response; + } +} diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/GetMilestoneCommand.java b/services/contracts/src/main/java/com/workup/contracts/commands/GetMilestoneCommand.java new file mode 100644 index 00000000..3b28b78b --- /dev/null +++ b/services/contracts/src/main/java/com/workup/contracts/commands/GetMilestoneCommand.java @@ -0,0 +1,54 @@ +package com.workup.contracts.commands; + +import com.workup.contracts.logger.ContractsLogger; +import com.workup.contracts.models.ContractMilestone; +import com.workup.shared.commands.contracts.requests.GetMilestoneRequest; +import com.workup.shared.commands.contracts.responses.GetMilestoneResponse; +import com.workup.shared.enums.HttpStatusCode; +import java.util.Optional; +import java.util.UUID; + +public class GetMilestoneCommand + extends ContractCommand { + + @Override + public GetMilestoneResponse Run(GetMilestoneRequest request) { + String cachingKey = request.getMilestoneId(); + + GetMilestoneResponse cachedResponse = + (GetMilestoneResponse) redisService.getValue(cachingKey, GetMilestoneResponse.class); + if (cachedResponse != null) { + ContractsLogger.print( + "[x] Milestone request response fetched from cache: " + cachedResponse.toString()); + + return cachedResponse; + } + + Optional milestoneOptional = + contractMilestoneRepository.findById(UUID.fromString(request.getMilestoneId())); + + if (milestoneOptional.isEmpty()) { + return GetMilestoneResponse.builder() + .withStatusCode(HttpStatusCode.NOT_FOUND) + .withErrorMessage("Requested milestone does not exist") + .build(); + } + + ContractMilestone milestone = milestoneOptional.get(); + + GetMilestoneResponse response = + GetMilestoneResponse.builder() + .withContractId(milestone.getContractId()) + .withMilestoneId(milestone.getMilestoneId().toString()) + .withAmount(milestone.getAmount()) + .withDescription(milestone.getDescription()) + .withDueDate(milestone.getDueDate()) + .withAmount(milestone.getAmount()) + .withStatusCode(HttpStatusCode.OK) + .withErrorMessage("") + .build(); + + redisService.setValue(cachingKey, response); + return response; + } +} diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/GetPendingTerminationsCommand.java b/services/contracts/src/main/java/com/workup/contracts/commands/GetPendingTerminationsCommand.java new file mode 100644 index 00000000..bfcf3470 --- /dev/null +++ b/services/contracts/src/main/java/com/workup/contracts/commands/GetPendingTerminationsCommand.java @@ -0,0 +1,53 @@ +package com.workup.contracts.commands; + +import com.workup.contracts.logger.ContractsLogger; +import com.workup.contracts.models.TerminationRequest; +import com.workup.shared.commands.contracts.requests.GetPendingTerminationsRequest; +import com.workup.shared.commands.contracts.responses.GetPendingTerminationsResponse; +import com.workup.shared.enums.HttpStatusCode; +import java.util.List; + +public class GetPendingTerminationsCommand + extends ContractCommand { + + @Override + public GetPendingTerminationsResponse Run(GetPendingTerminationsRequest request) { + String cachingKey = request.getContractId() + "/pending_terminations"; + + GetPendingTerminationsResponse cachedResponse = + (GetPendingTerminationsResponse) + redisService.getValue(cachingKey, GetPendingTerminationsResponse.class); + if (cachedResponse != null) { + ContractsLogger.print( + "[x] Contract terminations response fetched from cache: " + cachedResponse.toString()); + + return cachedResponse; + } + + List terminationsList = + terminationRequestRepository.findByContractId(request.getContractId()); + + if (terminationsList.isEmpty()) { + return GetPendingTerminationsResponse.builder() + .withStatusCode(HttpStatusCode.NOT_FOUND) + .withErrorMessage("No pending terminations exist") + .build(); + } + + TerminationRequest terminationRequest = terminationsList.getFirst(); + + GetPendingTerminationsResponse response = + GetPendingTerminationsResponse.builder() + .withRequestId(terminationRequest.getRequestId().toString()) + .withRequesterId(terminationRequest.getRequesterId()) + .withContractId(terminationRequest.getContractId()) + .withReason(terminationRequest.getReason()) + .withStatus(terminationRequest.getStatus()) + .withStatusCode(HttpStatusCode.OK) + .withErrorMessage("") + .build(); + + redisService.setValue(cachingKey, response); + return response; + } +} diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/HandleTerminationRequestCommand.java b/services/contracts/src/main/java/com/workup/contracts/commands/HandleTerminationRequestCommand.java index c55e6fcd..d8fd432d 100644 --- a/services/contracts/src/main/java/com/workup/contracts/commands/HandleTerminationRequestCommand.java +++ b/services/contracts/src/main/java/com/workup/contracts/commands/HandleTerminationRequestCommand.java @@ -1,5 +1,6 @@ package com.workup.contracts.commands; +import com.workup.contracts.logger.ContractsLogger; import com.workup.contracts.models.Contract; import com.workup.contracts.models.TerminationRequest; import com.workup.shared.commands.contracts.requests.HandleTerminationRequest; @@ -41,7 +42,7 @@ private HandleTerminationResponse handleTerminationRequest( } try { TerminationRequest updatedRequest = terminationRequestRepository.save(terminationRequest); - System.out.println(" [x] Updated Termination Request " + updatedRequest); + ContractsLogger.print(" [x] Updated Termination Request " + updatedRequest); return HandleTerminationResponse.builder() .withRequestStatus(updatedRequest.getStatus()) .withStatusCode(HttpStatusCode.OK) @@ -67,7 +68,7 @@ private HandleTerminationResponse terminateContract(String contractId) { updatedContract.setStatus(ContractState.TERMINATED); try { updatedContract = contractRepository.save(updatedContract); - System.out.println(" [x] Updated Contract Status to Terminated " + updatedContract); + ContractsLogger.print(" [x] Updated Contract Status to Terminated " + updatedContract); } catch (Exception e) { e.printStackTrace(); return HandleTerminationResponse.builder() diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/InitiateContractCommand.java b/services/contracts/src/main/java/com/workup/contracts/commands/InitiateContractCommand.java index 45a191b5..d85dd4c5 100644 --- a/services/contracts/src/main/java/com/workup/contracts/commands/InitiateContractCommand.java +++ b/services/contracts/src/main/java/com/workup/contracts/commands/InitiateContractCommand.java @@ -1,5 +1,6 @@ package com.workup.contracts.commands; +import com.workup.contracts.logger.ContractsLogger; import com.workup.contracts.models.Contract; import com.workup.contracts.models.ContractMilestone; import com.workup.shared.commands.contracts.Milestone; @@ -56,11 +57,11 @@ public InitiateContractResponse Run(InitiateContractRequest request) { try { Contract savedContract = contractRepository.save(contract); - System.out.println(" [x] Saved Contract '" + savedContract.getJobTitle()); + ContractsLogger.print(" [x] Saved Contract '" + savedContract.getJobTitle()); contractMilestoneRepository.saveAll(milestonesToAdd); - System.out.println(" [x] Saved All Milestones '" + savedContract.getJobTitle()); + ContractsLogger.print(" [x] Saved All Milestones '" + savedContract.getJobTitle()); return InitiateContractResponse.builder() .withContractId(savedContract.getContractId().toString()) diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/MarkMilestoneAsPaidCommand.java b/services/contracts/src/main/java/com/workup/contracts/commands/MarkMilestoneAsPaidCommand.java index 99720855..9922fd13 100644 --- a/services/contracts/src/main/java/com/workup/contracts/commands/MarkMilestoneAsPaidCommand.java +++ b/services/contracts/src/main/java/com/workup/contracts/commands/MarkMilestoneAsPaidCommand.java @@ -39,6 +39,7 @@ public MarkPaymentCompletedResponse Run(MarkPaymentCompletedRequest request) { try { contractMilestoneRepository.save(updatedMilestone); System.out.println(" [x] Marked Milestone as Paid '" + updatedMilestone); + return MarkPaymentCompletedResponse.builder().withStatusCode(HttpStatusCode.OK).build(); } catch (Exception e) { e.printStackTrace(); return MarkPaymentCompletedResponse.builder() @@ -46,8 +47,6 @@ public MarkPaymentCompletedResponse Run(MarkPaymentCompletedRequest request) { .withErrorMessage(e.getMessage()) .build(); } - - return null; } private void pay(ContractMilestone milestone) { diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/ProgressMilestoneCommand.java b/services/contracts/src/main/java/com/workup/contracts/commands/ProgressMilestoneCommand.java new file mode 100644 index 00000000..3f480e3f --- /dev/null +++ b/services/contracts/src/main/java/com/workup/contracts/commands/ProgressMilestoneCommand.java @@ -0,0 +1,66 @@ +package com.workup.contracts.commands; + +import com.workup.contracts.logger.ContractsLogger; +import com.workup.contracts.models.ContractMilestone; +import com.workup.shared.commands.contracts.requests.ProgressMilestoneRequest; +import com.workup.shared.commands.contracts.responses.ProgressMilestoneResponse; +import com.workup.shared.enums.HttpStatusCode; +import com.workup.shared.enums.contracts.MilestoneState; +import java.util.Optional; +import java.util.UUID; + +public class ProgressMilestoneCommand + extends ContractCommand { + + private ProgressMilestoneResponse isValid(Optional milestoneOptional) { + if (milestoneOptional.isEmpty()) + return ProgressMilestoneResponse.builder() + .withStatusCode(HttpStatusCode.BAD_REQUEST) + .withErrorMessage("Milestone is not found") + .build(); + + MilestoneState milestoneState = milestoneOptional.get().getStatus(); + if (milestoneState != MilestoneState.OPEN && milestoneState != MilestoneState.IN_PROGRESS) + return ProgressMilestoneResponse.builder() + .withStatusCode(HttpStatusCode.BAD_REQUEST) + .withErrorMessage("Milestone cannot be progressed through this command") + .build(); + return null; + } + + @Override + public ProgressMilestoneResponse Run(ProgressMilestoneRequest request) { + Optional milestoneOptional = + contractMilestoneRepository.findById(UUID.fromString(request.getMilestoneId())); + + ProgressMilestoneResponse checkerResponse = isValid(milestoneOptional); + if (checkerResponse != null) return checkerResponse; + + ContractMilestone updatedMilestone = milestoneOptional.get(); + + progress(updatedMilestone); + + try { + contractMilestoneRepository.save(updatedMilestone); + ContractsLogger.print(" [x] Milestone Progressed " + updatedMilestone); + return ProgressMilestoneResponse.builder() + .withStatusCode(HttpStatusCode.OK) + .withErrorMessage("") + .build(); + + } catch (Exception e) { + e.printStackTrace(); + return ProgressMilestoneResponse.builder() + .withStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR) + .withErrorMessage(e.getMessage()) + .build(); + } + } + + private void progress(ContractMilestone milestone) { + if (milestone.getStatus() == MilestoneState.OPEN) + milestone.setStatus(MilestoneState.IN_PROGRESS); + else if (milestone.getStatus() == MilestoneState.IN_PROGRESS) + milestone.setStatus(MilestoneState.IN_REVIEW); + } +} diff --git a/services/contracts/src/main/java/com/workup/contracts/commands/RequestContractTerminationCommand.java b/services/contracts/src/main/java/com/workup/contracts/commands/RequestContractTerminationCommand.java index 5eedd8c0..9cd7850d 100644 --- a/services/contracts/src/main/java/com/workup/contracts/commands/RequestContractTerminationCommand.java +++ b/services/contracts/src/main/java/com/workup/contracts/commands/RequestContractTerminationCommand.java @@ -1,5 +1,6 @@ package com.workup.contracts.commands; +import com.workup.contracts.logger.ContractsLogger; import com.workup.contracts.models.Contract; import com.workup.contracts.models.TerminationRequest; import com.workup.shared.commands.contracts.requests.ContractTerminationRequest; @@ -68,7 +69,7 @@ public ContractTerminationResponse Run(ContractTerminationRequest request) { try { TerminationRequest savedRequest = terminationRequestRepository.save(terminationRequest); - System.out.println(" [x] Saved Termination Request '" + savedRequest); + ContractsLogger.print(" [x] Saved Termination Request '" + savedRequest); return ContractTerminationResponse.builder() .withRequestId(savedRequest.getRequestId().toString()) diff --git a/services/contracts/src/main/java/com/workup/contracts/logger/ContractsLogger.java b/services/contracts/src/main/java/com/workup/contracts/logger/ContractsLogger.java new file mode 100644 index 00000000..1e2e71d6 --- /dev/null +++ b/services/contracts/src/main/java/com/workup/contracts/logger/ContractsLogger.java @@ -0,0 +1,8 @@ +package com.workup.contracts.logger; + +public class ContractsLogger { + + public static void print(String logMessage) { + System.out.println(logMessage); + } +} diff --git a/services/contracts/src/main/java/com/workup/contracts/repositories/TerminationRequestRepository.java b/services/contracts/src/main/java/com/workup/contracts/repositories/TerminationRequestRepository.java index 16734af9..098dd1e6 100644 --- a/services/contracts/src/main/java/com/workup/contracts/repositories/TerminationRequestRepository.java +++ b/services/contracts/src/main/java/com/workup/contracts/repositories/TerminationRequestRepository.java @@ -6,6 +6,7 @@ import java.util.UUID; import org.springframework.data.cassandra.repository.AllowFiltering; import org.springframework.data.cassandra.repository.CassandraRepository; +import org.springframework.data.cassandra.repository.Query; import org.springframework.stereotype.Repository; @Repository @@ -14,4 +15,7 @@ public interface TerminationRequestRepository @AllowFiltering List findByRequesterIdAndContractIdAndStatus( String requesterId, String contractId, TerminationRequestStatus status); + + @Query("SELECT * FROM contracts_data.termination_requests WHERE contractid = ?0") + List findByContractId(String contractId); } diff --git a/services/contracts/src/test/java/com/workup/contracts/ContractApplicationTests.java b/services/contracts/src/test/java/com/workup/contracts/ContractApplicationTests.java deleted file mode 100644 index 83a3f093..00000000 --- a/services/contracts/src/test/java/com/workup/contracts/ContractApplicationTests.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.workup.contracts; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class ContractApplicationTests { - - @Test - void contextLoads() {} -} diff --git a/services/contracts/src/test/java/com/workup/contracts/ContractsApplicationTests.java b/services/contracts/src/test/java/com/workup/contracts/ContractsApplicationTests.java new file mode 100644 index 00000000..ac6e5ec8 --- /dev/null +++ b/services/contracts/src/test/java/com/workup/contracts/ContractsApplicationTests.java @@ -0,0 +1,95 @@ +package com.workup.contracts; + +import com.workup.contracts.repositories.ContractMilestoneRepository; +import com.workup.contracts.repositories.ContractRepository; +import com.workup.contracts.repositories.TerminationRequestRepository; +import java.text.ParseException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.amqp.core.AmqpTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.CassandraContainer; +import org.testcontainers.containers.RabbitMQContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +@SpringBootTest +@Testcontainers +@Import(TestConfigBase.class) +class ContractsApplicationTests { + + @Container + static CassandraContainer cassandraContainer = + new CassandraContainer<>("cassandra:4.0.7").withConfigurationOverride("cassandra-config"); + + @Container + static RabbitMQContainer rabbitMQContainer = new RabbitMQContainer("rabbitmq:3.13-management"); + + static String GetCassandraContactPoint() { + return cassandraContainer.getHost() + ":" + cassandraContainer.getFirstMappedPort(); + } + + @DynamicPropertySource + static void datasourceProperties(DynamicPropertyRegistry registry) { + registry.add( + "spring.cassandra.contact-points", ContractsApplicationTests::GetCassandraContactPoint); + + registry.add("spring.rabbitmq.host", rabbitMQContainer::getHost); + registry.add("spring.rabbitmq.port", rabbitMQContainer::getFirstMappedPort); + registry.add("spring.rabbitmq.username", rabbitMQContainer::getAdminUsername); + registry.add("spring.rabbitmq.password", rabbitMQContainer::getAdminPassword); + } + + private static final String CLIENT_ONE_ID = "123"; + private static final String CLIENT_TWO_ID = "456"; + private static final String FREELANCER_ONE_ID = "789"; + + @Autowired AmqpTemplate template; + @Autowired ContractRepository contractRepository; + @Autowired ContractMilestoneRepository contractMilestoneRepository; + @Autowired TerminationRequestRepository terminationRequestRepository; + + @BeforeEach + void clearAll() { + contractRepository.deleteAll(); + contractMilestoneRepository.deleteAll(); + terminationRequestRepository.deleteAll(); + } + + /** + * Creates a job request. + * + * @throws ParseException + */ + @Test + void testCreateJob() { + // Example test from jobs + // CreateJobRequest createJobRequest = + // CreateJobRequest.builder() + // .withTitle("Convert HTML Template to React 3") + // .withDescription( + // "I have an HTML template that I have purchased and own the rights + // to. I would like" + // + " it converted into a React application.") + // .withSkills(new String[] {"HTML", "CSS", "JavaScript", "React"}) + // .withUserId(CLIENT_ONE_ID) + // .build(); + // + // CreateJobResponse response = + // (CreateJobResponse) + // template.convertSendAndReceive(ServiceQueueNames.JOBS, createJobRequest); + // + // assertNotNull(response); + // assertTrue(response.getStatusCode() == HttpStatusCode.CREATED); + // + // jobRepository + // .findById(UUID.fromString(response.getJobId())) + // .ifPresentOrElse( + // job -> assertTrue(job.getTitle().equals(createJobRequest.getTitle())), + // () -> new RuntimeException("Job not found")); + } +} diff --git a/services/contracts/src/test/java/com/workup/contracts/TestConfigBase.java b/services/contracts/src/test/java/com/workup/contracts/TestConfigBase.java new file mode 100644 index 00000000..acf2801d --- /dev/null +++ b/services/contracts/src/test/java/com/workup/contracts/TestConfigBase.java @@ -0,0 +1,14 @@ +package com.workup.contracts; + +import com.workup.shared.enums.ServiceQueueNames; +import org.springframework.amqp.core.Queue; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; + +@TestConfiguration +public class TestConfigBase { + @Bean + public Queue contractsQueueMock() { + return new Queue(ServiceQueueNames.CONTRACTS); + } +} diff --git a/shared/src/main/java/com/workup/shared/commands/contracts/Milestone.java b/shared/src/main/java/com/workup/shared/commands/contracts/Milestone.java index 308163c5..159dac47 100644 --- a/shared/src/main/java/com/workup/shared/commands/contracts/Milestone.java +++ b/shared/src/main/java/com/workup/shared/commands/contracts/Milestone.java @@ -11,7 +11,7 @@ @Jacksonized public class Milestone { - private final String milestoneId; // Not Needed when initiating contract, make it null + private final String milestoneId; // Not needed when initiating contract, make it null private final String contractId; // Not needed when initiating contract, make it null private final String description; diff --git a/shared/src/main/java/com/workup/shared/commands/contracts/requests/GetContractRequest.java b/shared/src/main/java/com/workup/shared/commands/contracts/requests/GetContractRequest.java new file mode 100644 index 00000000..e9ba104e --- /dev/null +++ b/shared/src/main/java/com/workup/shared/commands/contracts/requests/GetContractRequest.java @@ -0,0 +1,14 @@ +package com.workup.shared.commands.contracts.requests; + +import com.workup.shared.commands.CommandRequest; +import lombok.Getter; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; + +// PURPOSE : To fulfill the need for the read of CRUD for our contract repository +@Getter +@SuperBuilder(setterPrefix = "with") +@Jacksonized +public class GetContractRequest extends CommandRequest { + private final String contractId; +} diff --git a/shared/src/main/java/com/workup/shared/commands/contracts/requests/GetMilestoneRequest.java b/shared/src/main/java/com/workup/shared/commands/contracts/requests/GetMilestoneRequest.java new file mode 100644 index 00000000..6d87533f --- /dev/null +++ b/shared/src/main/java/com/workup/shared/commands/contracts/requests/GetMilestoneRequest.java @@ -0,0 +1,15 @@ +package com.workup.shared.commands.contracts.requests; + +import com.workup.shared.commands.CommandRequest; +import lombok.Getter; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; + +// PURPOSE : To fulfill the need for the read of CRUD for our milestone repository +@Getter +@SuperBuilder(setterPrefix = "with") +@Jacksonized +public class GetMilestoneRequest extends CommandRequest { + + private final String milestoneId; +} diff --git a/shared/src/main/java/com/workup/shared/commands/contracts/requests/GetPendingTerminationsRequest.java b/shared/src/main/java/com/workup/shared/commands/contracts/requests/GetPendingTerminationsRequest.java new file mode 100644 index 00000000..c550287c --- /dev/null +++ b/shared/src/main/java/com/workup/shared/commands/contracts/requests/GetPendingTerminationsRequest.java @@ -0,0 +1,14 @@ +package com.workup.shared.commands.contracts.requests; + +import com.workup.shared.commands.CommandRequest; +import lombok.Getter; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; + +// PURPOSE : To fulfill the need for the read of CRUD for our terminations repository +@Getter +@SuperBuilder(setterPrefix = "with") +@Jacksonized +public class GetPendingTerminationsRequest extends CommandRequest { + private final String contractId; +} diff --git a/shared/src/main/java/com/workup/shared/commands/contracts/responses/EvaluatedMilestoneResponse.java b/shared/src/main/java/com/workup/shared/commands/contracts/responses/EvaluateMilestoneResponse.java similarity index 80% rename from shared/src/main/java/com/workup/shared/commands/contracts/responses/EvaluatedMilestoneResponse.java rename to shared/src/main/java/com/workup/shared/commands/contracts/responses/EvaluateMilestoneResponse.java index c119e14f..c1319d9d 100644 --- a/shared/src/main/java/com/workup/shared/commands/contracts/responses/EvaluatedMilestoneResponse.java +++ b/shared/src/main/java/com/workup/shared/commands/contracts/responses/EvaluateMilestoneResponse.java @@ -8,4 +8,4 @@ @Getter @SuperBuilder(setterPrefix = "with") @Jacksonized -public class EvaluatedMilestoneResponse extends CommandResponse {} +public class EvaluateMilestoneResponse extends CommandResponse {} diff --git a/shared/src/main/java/com/workup/shared/commands/contracts/responses/GetContractResponse.java b/shared/src/main/java/com/workup/shared/commands/contracts/responses/GetContractResponse.java new file mode 100644 index 00000000..6b526bb9 --- /dev/null +++ b/shared/src/main/java/com/workup/shared/commands/contracts/responses/GetContractResponse.java @@ -0,0 +1,22 @@ +package com.workup.shared.commands.contracts.responses; + +import com.workup.shared.commands.CommandResponse; +import com.workup.shared.enums.contracts.ContractState; +import java.util.List; +import lombok.Getter; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; + +@Getter +@SuperBuilder(setterPrefix = "with") +@Jacksonized +public class GetContractResponse extends CommandResponse { + private final String contractId; + private final String jobTitle; + private final String jobId; + private final String proposalId; + private final String freelancerId; + private final String clientId; + private final List milestonesIds; + private final ContractState status; +} diff --git a/shared/src/main/java/com/workup/shared/commands/contracts/responses/GetMilestoneResponse.java b/shared/src/main/java/com/workup/shared/commands/contracts/responses/GetMilestoneResponse.java new file mode 100644 index 00000000..190d4ad6 --- /dev/null +++ b/shared/src/main/java/com/workup/shared/commands/contracts/responses/GetMilestoneResponse.java @@ -0,0 +1,22 @@ +package com.workup.shared.commands.contracts.responses; + +import com.workup.shared.commands.CommandResponse; +import com.workup.shared.enums.contracts.MilestoneState; +import java.util.Date; +import lombok.Getter; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; + +@Getter +@SuperBuilder(setterPrefix = "with") +@Jacksonized +public class GetMilestoneResponse extends CommandResponse { + private final String milestoneId; + + private final String contractId; + + private final String description; + private final Date dueDate; + private final double amount; + private final MilestoneState status; +} diff --git a/shared/src/main/java/com/workup/shared/commands/contracts/responses/GetPendingTerminationsResponse.java b/shared/src/main/java/com/workup/shared/commands/contracts/responses/GetPendingTerminationsResponse.java new file mode 100644 index 00000000..7f45a4bc --- /dev/null +++ b/shared/src/main/java/com/workup/shared/commands/contracts/responses/GetPendingTerminationsResponse.java @@ -0,0 +1,20 @@ +package com.workup.shared.commands.contracts.responses; + +import com.workup.shared.commands.CommandResponse; +import com.workup.shared.enums.contracts.TerminationRequestStatus; +import lombok.Getter; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; + +@Getter +@SuperBuilder(setterPrefix = "with") +@Jacksonized +public class GetPendingTerminationsResponse extends CommandResponse { + private final String requestId; + + private final String contractId; + private final String requesterId; + private final String reason; + + private final TerminationRequestStatus status; +}