otpOpt = otpRepository.findByUsernameAndOtpTypeAndOtpAndOtpStatus(
+ username, otpType, otpCode, Status.ACTIVE);
if (otpOpt.isEmpty()) {
return false;
diff --git a/src/main/java/zw/qantra/tm/domain/workflows/RegistrationWorkflow.java b/src/main/java/zw/qantra/tm/domain/workflows/RegistrationWorkflow.java
index f6ee5e9..b1c90b0 100644
--- a/src/main/java/zw/qantra/tm/domain/workflows/RegistrationWorkflow.java
+++ b/src/main/java/zw/qantra/tm/domain/workflows/RegistrationWorkflow.java
@@ -3,14 +3,15 @@ package zw.qantra.tm.domain.workflows;
import io.nflow.engine.workflow.definition.WorkflowStateType;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import io.nflow.engine.workflow.definition.NextAction;
import io.nflow.engine.workflow.definition.StateExecution;
import io.nflow.engine.workflow.definition.WorkflowDefinition;
import zw.qantra.tm.domain.dtos.EmailRequest;
+import zw.qantra.tm.domain.dtos.VerifyRequest;
import zw.qantra.tm.domain.models.Otp;
-import zw.qantra.tm.domain.services.EmailService;
import zw.qantra.tm.domain.services.OtpService;
import zw.qantra.tm.domain.services.UserService;
import io.nflow.engine.workflow.curated.State;
@@ -19,24 +20,16 @@ import zw.qantra.tm.domain.dtos.RegisterRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
+import zw.qantra.tm.rest.RestService;
+
+import org.springframework.http.HttpHeaders;
+import java.util.LinkedHashMap;
import java.util.Set;
@Component
public class RegistrationWorkflow extends WorkflowDefinition {
Logger log = org.slf4j.LoggerFactory.getLogger(RegistrationWorkflow.class);
- public static final String TYPE = "registrationWorkflow";
-
- public static final State BEGIN = new State("begin", WorkflowStateType.start);
- public static final State REGISTER = new State("register", WorkflowStateType.normal);
- public static final State SEND_OTP = new State("sendOtp", WorkflowStateType.manual);
- public static final State VERIFY_OTP = new State("verifyOtp", WorkflowStateType.normal);
- public static final State RESEND_OTP = new State("resendOtp", WorkflowStateType.manual);
- public static final State SET_PIN = new State("setPin", WorkflowStateType.normal);
- public static final State UPDATE_ERP = new State("updateErp", WorkflowStateType.normal);
- public static final State FAILED = new State("failed", WorkflowStateType.manual);
- public static final State DONE = new State("done", WorkflowStateType.end);
-
@Autowired
private UserService userService;
@Autowired
@@ -44,16 +37,35 @@ public class RegistrationWorkflow extends WorkflowDefinition {
@Autowired
private OtpService otpService;
@Autowired
- private EmailService emailService;
+ private RestService restService;
+
+ @Value("${infobip.url}")
+ private String infobipUrl;
+ @Value("${infobip.apikey}")
+ private String infobipApiKey;
+
+ public static final String TYPE = "registrationWorkflow";
+
+ public static final State BEGIN = new State("begin", WorkflowStateType.start);
+ public static final State REGISTER = new State("register");
+ public static final State SEND_OTP = new State("sendOtp", WorkflowStateType.manual);
+ public static final State VERIFY_OTP = new State("verifyOtp");
+ public static final State OTP_SUCCESS = new State("otpSuccess", WorkflowStateType.manual);
+ public static final State RESEND_OTP = new State("resendOtp", WorkflowStateType.manual);
+ public static final State SET_PIN = new State("setPin", WorkflowStateType.normal);
+ public static final State UPDATE_ERP = new State("updateErp", WorkflowStateType.normal);
+ public static final State FAILED = new State("failed", WorkflowStateType.manual);
+ public static final State DONE = new State("done", WorkflowStateType.end);
public RegistrationWorkflow() {
super(TYPE, BEGIN, FAILED);
permit(BEGIN, REGISTER);
permit(REGISTER, SEND_OTP);
- permit(SEND_OTP, VERIFY_OTP, RESEND_OTP);
- permit(RESEND_OTP, VERIFY_OTP, FAILED);
- permit(VERIFY_OTP, SET_PIN, FAILED);
+ permit(SEND_OTP, VERIFY_OTP);
+ permit(VERIFY_OTP, OTP_SUCCESS, FAILED);
+ permit(RESEND_OTP, OTP_SUCCESS, FAILED);
+ permit(OTP_SUCCESS, SET_PIN, FAILED);
permit(SET_PIN, UPDATE_ERP);
permit(UPDATE_ERP, DONE);
}
@@ -65,7 +77,7 @@ public class RegistrationWorkflow extends WorkflowDefinition {
// register validates most of the initial registration details
public NextAction register(StateExecution execution) {
- RegisterRequest payload = execution.getVariable("metadata", RegisterRequest.class);
+ RegisterRequest payload = execution.getVariable("body", RegisterRequest.class);
if(payload == null)
return NextAction.moveToState(FAILED, "No payload provided");
@@ -82,65 +94,71 @@ public class RegistrationWorkflow extends WorkflowDefinition {
}
// todo: add this to the appropriate action
- execution.setVariable("metadata", payload);
+ execution.setVariable("body", payload);
return NextAction.moveToState(SEND_OTP, "Initial registration success for: " + payload.getUsername());
}
public void sendOtp(StateExecution execution) {
try {
- RegisterRequest registerRequest = execution.getVariable("metadata", RegisterRequest.class);
+ RegisterRequest registerRequest = execution.getVariable("body", RegisterRequest.class);
String username = registerRequest.getUsername();
String email = registerRequest.getEmail();
// Generate OTP
Otp otp = otpService.generateOtp(username, "REGISTRATION");
- // Create email content
- String subject = "Your Verification Code";
- String body = String.format(
- "" +
- "Email Verification
" +
- "Hello %s,
" +
- "Your verification code is: %s
" +
- "This code will expire in 10 minutes.
" +
- "If you didn't request this code, please ignore this email.
" +
- "",
- username, otp.getOtp()
- );
-
- // Send email
- EmailRequest emailRequest = EmailRequest.builder()
- .to(email)
- .subject(subject)
- .body(body)
- .isHtml(true)
- .build();
-
- boolean emailSent = emailService.sendEmail(emailRequest);
-
- if (!emailSent) {
- log.error("Failed to send OTP email to: {}", email);
- }
+ String string = getSMSString(registerRequest.getPhone(), otp.getOtp());
+ HttpHeaders headers = new HttpHeaders();
+ headers.add("Authorization", "App " + infobipApiKey);
+ headers.add("Content-Type", "application/json");
+ headers.add("Accept", "application/json");
+ // LinkedHashMap response = restService.postAs(infobipUrl, string, headers, LinkedHashMap.class);
+ log.info("otp generated successfully: {}", otp.getOtp());
} catch (Exception e) {
log.error("Error sending OTP: {}", e.getMessage(), e);
}
}
public NextAction verifyOtp(StateExecution execution) {
- return NextAction.stopInState(SET_PIN, "OTP verified successfully for: " );
+ VerifyRequest payload = execution.getVariable("body", VerifyRequest.class);
+ boolean otpValid = otpService.verifyOtp(payload.getUsername(), payload.getOtpCode(), payload.getOtpType());
+
+ if(!otpValid) {
+ return NextAction.moveToState(FAILED, "Invalid OTP");
+ }
+
+ return NextAction.moveToState(OTP_SUCCESS, "OTP verified successfully");
+ }
+
+ public void otpSuccess(StateExecution execution) {
+ log.info("OTP verified successfully");
}
public NextAction setPin(StateExecution execution) {
- RegisterRequest response = execution.getVariable("response", RegisterRequest.class);
+ RegisterRequest response = execution.getVariable("body", RegisterRequest.class);
return NextAction.stopInState(UPDATE_ERP, "PIN set successfully for: " + response.getUsername());
}
public NextAction updateErp(StateExecution execution) {
- RegisterRequest response = execution.getVariable("response", RegisterRequest.class);
+ RegisterRequest response = execution.getVariable("body", RegisterRequest.class);
return NextAction.stopInState(DONE, "ERP updated successfully for: " + response.getUsername());
}
-
+ String getSMSString(String to, String otp) {
+ return String.format("{\n" +
+ " \"messages\": [\n" +
+ " {\n" +
+ " \"destinations\": [\n" +
+ " {\n" +
+ " \"to\": \"%s\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"from\": \"447491163443\",\n" +
+ " \"text\": \"Your verification code is: %s\"\n" +
+ " }\n" +
+ " ]\n" +
+ "}", to, otp);
+ }
}
diff --git a/src/main/java/zw/qantra/tm/domain/workflows/WorkflowUtils.java b/src/main/java/zw/qantra/tm/domain/workflows/WorkflowUtils.java
index f3197a5..1f91cd5 100644
--- a/src/main/java/zw/qantra/tm/domain/workflows/WorkflowUtils.java
+++ b/src/main/java/zw/qantra/tm/domain/workflows/WorkflowUtils.java
@@ -1,19 +1,23 @@
package zw.qantra.tm.domain.workflows;
import java.util.EnumSet;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
-import io.nflow.engine.service.WorkflowInstanceInclude;
+import io.nflow.engine.service.WorkflowInstanceInclude.*;
import org.springframework.stereotype.Component;
import io.nflow.engine.service.WorkflowInstanceService;
import io.nflow.engine.workflow.instance.WorkflowInstance;
import lombok.RequiredArgsConstructor;
+import zw.qantra.tm.domain.dtos.StateResponse;
+import zw.qantra.tm.utils.Utils;
+
+import static io.nflow.engine.service.WorkflowInstanceInclude.*;
@Component
@RequiredArgsConstructor
-
public class WorkflowUtils {
private final WorkflowInstanceService workflowInstanceService;
@@ -22,22 +26,35 @@ public class WorkflowUtils {
while(!future.isDone()){ // check if the future is done
WorkflowInstance instance = workflowInstanceService.getWorkflowInstance(
- workflowId, EnumSet.of(WorkflowInstanceInclude.ACTIONS), 1L);
+ workflowId,
+ EnumSet.of(ACTIONS, ACTION_STATE_VARIABLES, CURRENT_STATE_VARIABLES),
+ 1L);
try {
- if(instance.state.equalsIgnoreCase(state)){
- future.complete(instance.getStateVariable("metadata"));
- }
Thread.sleep(pollingInterval);
+ if(instance.state.equalsIgnoreCase(state) &&
+ instance.status.equals(WorkflowInstance.WorkflowInstanceStatus.manual)){
+ future.complete(getStateResponse(instance, "success"));
+ }
} catch (InterruptedException e) {
future.completeExceptionally(e);
}
timeout -= pollingInterval;
if(timeout <= 0){
- future.complete(instance);
+ future.complete(getStateResponse(instance, "Request timed out"));
}
}
return future;
}
+
+ public StateResponse getStateResponse(WorkflowInstance instance, String message){
+ return StateResponse.builder()
+ .state(instance.state)
+ .body(Utils.fromJson(instance.getStateVariable("body"), Map.class))
+ .message(instance.getStateVariable("message"))
+ .workflowId(instance.id.toString())
+ .externalId(instance.externalId)
+ .build();
+ }
}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 0799893..2bdfb20 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -49,13 +49,6 @@ jwt.expiration=86400000
logging.level.root=WARN
# Email Configuration
-spring.mail.host=smtp.gmail.com
-spring.mail.port=587
-spring.mail.username=vusakhoza@gmail.com
-spring.mail.password=Stikbanch@14
-spring.mail.properties.mail.smtp.auth=true
-spring.mail.properties.mail.smtp.starttls.enable=true
-spring.mail.properties.mail.smtp.starttls.required=true
-spring.mail.properties.mail.smtp.connectiontimeout=5000
-spring.mail.properties.mail.smtp.timeout=5000
-spring.mail.properties.mail.smtp.writetimeout=5000
+infobip.url=https://z3m696.api.infobip.com/sms/2/text/advanced
+infobip.apikey=0ede918b7c1110465a0518021521638c-ebc4fdb7-547d-413b-bbca-781949ac6597
+