Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contracts commands cache implementation #82

Merged
merged 14 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 47 additions & 3 deletions services/contracts/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
<maven.compiler.target>21</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
Expand All @@ -36,17 +40,57 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>cassandra</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>rabbitmq</artifactId>
<version>1.19.7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.16.0</version>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>com.redis.testcontainers</groupId>
<artifactId>testcontainers-redis-junit-jupiter</artifactId>
<version>1.4.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends CommandRequest, Q extends CommandResponse>
implements Command<T, Q> {

@Setter AmqpTemplate rabbitTemplate;

@Setter ContractRepository contractRepository;

@Setter ContractMilestoneRepository contractMilestoneRepository;

@Setter TerminationRequestRepository terminationRequestRepository;

@Setter RedisService redisService;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);
Expand All @@ -34,5 +40,7 @@ public void setupCommand(
command.setContractRepository(contractRepository);
command.setContractMilestoneRepository(contractMilestoneRepository);
command.setTerminationRequestRepository(terminationRequestRepository);
command.setRabbitTemplate(rabbitTemplate);
command.setRedisService(redisService);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.workup.contracts.commands;

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<EvaluateMilestoneRequest, EvaluateMilestoneResponse> {
private EvaluateMilestoneResponse isValid(Optional<ContractMilestone> 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<ContractMilestone> 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);
System.out.println(" [x] Milestone evaluated " + updatedMilestone);

if (request.getEvaluatedState() == MilestoneState.ACCEPTED) {
System.out.println(" [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<Contract> 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);
System.out.println(" [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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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<GetContractRequest, GetContractResponse> {

@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<Contract> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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<GetMilestoneRequest, GetMilestoneResponse> {

@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<ContractMilestone> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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<GetPendingTerminationsRequest, GetPendingTerminationsResponse> {

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