initial commit
This commit is contained in:
178
src/main/java/com/rit/whatsapp/controller/WebhookController.java
Normal file
178
src/main/java/com/rit/whatsapp/controller/WebhookController.java
Normal file
@@ -0,0 +1,178 @@
|
||||
package com.rit.whatsapp.controller;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.rit.whatsapp.handler.GrievanceHandler;
|
||||
import com.rit.whatsapp.handler.LoginHandler;
|
||||
import com.rit.whatsapp.handler.StudentMenuHandler;
|
||||
import com.rit.whatsapp.model.UserState;
|
||||
import com.rit.whatsapp.service.SessionService;
|
||||
import com.rit.whatsapp.service.WhatsAppMessageService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/webhook")
|
||||
public class WebhookController {
|
||||
|
||||
@Value("${whatsapp.verify-token:my_secure_verify_token}")
|
||||
private String verifyToken;
|
||||
|
||||
private final WhatsAppMessageService messageService;
|
||||
private final SessionService sessionService;
|
||||
private final StudentMenuHandler studentMenuHandler;
|
||||
private final GrievanceHandler grievanceHandler;
|
||||
private final LoginHandler loginHandler;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
public WebhookController(WhatsAppMessageService messageService,
|
||||
SessionService sessionService,
|
||||
StudentMenuHandler studentMenuHandler,
|
||||
GrievanceHandler grievanceHandler,
|
||||
LoginHandler loginHandler) {
|
||||
this.messageService = messageService;
|
||||
this.sessionService = sessionService;
|
||||
this.studentMenuHandler = studentMenuHandler;
|
||||
this.grievanceHandler = grievanceHandler;
|
||||
this.loginHandler = loginHandler;
|
||||
this.objectMapper = new ObjectMapper();
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<String> verifyWebhook(
|
||||
@RequestParam(name = "hub.mode", required = false) String mode,
|
||||
@RequestParam(name = "hub.verify_token", required = false) String token,
|
||||
@RequestParam(name = "hub.challenge", required = false) String challenge) {
|
||||
|
||||
if ("subscribe".equals(mode) && verifyToken.equals(token)) {
|
||||
return ResponseEntity.ok(challenge);
|
||||
} else {
|
||||
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<String> receiveMessage(@RequestBody String payload) {
|
||||
System.out.println("Received Webhook Payload: " + payload);
|
||||
try {
|
||||
JsonNode rootNode = objectMapper.readTree(payload);
|
||||
|
||||
if (rootNode.has("entry") && rootNode.get("entry").isArray()) {
|
||||
JsonNode entryNode = rootNode.get("entry").get(0);
|
||||
|
||||
if (entryNode.has("changes") && entryNode.get("changes").isArray()) {
|
||||
JsonNode changesNode = entryNode.get("changes").get(0);
|
||||
JsonNode valueNode = changesNode.get("value");
|
||||
|
||||
if (valueNode != null && valueNode.has("messages") && valueNode.get("messages").isArray()) {
|
||||
JsonNode messageNode = valueNode.get("messages").get(0);
|
||||
|
||||
String fromPhoneNumber = messageNode.get("from").asText();
|
||||
String messageType = messageNode.get("type").asText();
|
||||
|
||||
UserState currentState = sessionService.getUserState(fromPhoneNumber);
|
||||
boolean isAuthenticated = sessionService.isAuthenticated(fromPhoneNumber);
|
||||
|
||||
// Global reset command
|
||||
if ("text".equals(messageType) && messageNode.get("text").get("body").asText().trim().equalsIgnoreCase("reset")) {
|
||||
sessionService.resetState(fromPhoneNumber);
|
||||
if (isAuthenticated) {
|
||||
studentMenuHandler.sendMainMenu(fromPhoneNumber);
|
||||
} else {
|
||||
loginHandler.startLoginFlow(fromPhoneNumber);
|
||||
}
|
||||
return ResponseEntity.ok("EVENT_RECEIVED");
|
||||
}
|
||||
|
||||
// Route unauthenticated users strictly to Login Flow
|
||||
if (!isAuthenticated) {
|
||||
if ("text".equals(messageType)) {
|
||||
String body = messageNode.get("text").get("body").asText();
|
||||
handleUnauthenticatedUser(fromPhoneNumber, body, currentState);
|
||||
} else {
|
||||
// If they send a sticker/image/etc before logging in, force login
|
||||
handleUnauthenticatedUser(fromPhoneNumber, "", currentState);
|
||||
}
|
||||
return ResponseEntity.ok("EVENT_RECEIVED");
|
||||
}
|
||||
|
||||
// Authenticated users flow
|
||||
if ("text".equals(messageType)) {
|
||||
String messageBody = messageNode.get("text").get("body").asText();
|
||||
handleAuthenticatedTextMessage(fromPhoneNumber, messageBody, currentState);
|
||||
} else if ("interactive".equals(messageType)) {
|
||||
JsonNode interactiveNode = messageNode.get("interactive");
|
||||
String interactiveType = interactiveNode.get("type").asText();
|
||||
|
||||
if ("list_reply".equals(interactiveType)) {
|
||||
String selectedListId = interactiveNode.get("list_reply").get("id").asText();
|
||||
handleInteractiveListSelection(fromPhoneNumber, selectedListId, currentState);
|
||||
} else if ("button_reply".equals(interactiveType)) {
|
||||
String selectedButtonId = interactiveNode.get("button_reply").get("id").asText();
|
||||
handleInteractiveButtonSelection(fromPhoneNumber, selectedButtonId, currentState);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error processing webhook payload: " + e.getMessage());
|
||||
}
|
||||
|
||||
return ResponseEntity.ok("EVENT_RECEIVED");
|
||||
}
|
||||
|
||||
private void handleUnauthenticatedUser(String phoneNumber, String messageBody, UserState currentState) {
|
||||
switch (currentState) {
|
||||
case AWAITING_LOGIN_ID:
|
||||
loginHandler.handleLoginIdInput(phoneNumber, messageBody);
|
||||
break;
|
||||
case AWAITING_LOGIN_PASSCODE:
|
||||
loginHandler.handlePasscodeInput(phoneNumber, messageBody);
|
||||
break;
|
||||
default:
|
||||
// Trigger the start of the login flow
|
||||
loginHandler.startLoginFlow(phoneNumber);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAuthenticatedTextMessage(String phoneNumber, String messageBody, UserState currentState) {
|
||||
switch (currentState) {
|
||||
case AWAITING_GRIEVANCE_DESC:
|
||||
grievanceHandler.handleGrievanceDescription(phoneNumber, messageBody);
|
||||
break;
|
||||
case MAIN_MENU:
|
||||
default:
|
||||
// Fallback to main menu
|
||||
studentMenuHandler.sendMainMenu(phoneNumber);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInteractiveListSelection(String phoneNumber, String selectedListId, UserState currentState) {
|
||||
if (currentState == UserState.MAIN_MENU) {
|
||||
studentMenuHandler.handleMenuSelection(phoneNumber, selectedListId);
|
||||
} else {
|
||||
studentMenuHandler.sendMainMenu(phoneNumber);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInteractiveButtonSelection(String phoneNumber, String selectedButtonId, UserState currentState) {
|
||||
if ("student_logout".equals(selectedButtonId)) {
|
||||
sessionService.logoutUser(phoneNumber);
|
||||
messageService.sendMessage(phoneNumber, "You have been logged out successfully. Type 'Hi' to log in again.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentState == UserState.AWAITING_GRIEVANCE_CATEGORY) {
|
||||
grievanceHandler.handleCategorySelection(phoneNumber, selectedButtonId);
|
||||
} else {
|
||||
studentMenuHandler.sendMainMenu(phoneNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user