Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

package com.spice.profitmandi.web.controller;

import com.spice.profitmandi.service.NotificationService;
import com.spice.profitmandi.service.whatsapp.CpassWhatsappService;
import com.spice.profitmandi.service.whatsapp.WhatsappMessageType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Manual verification endpoints for the cpass (notify24x7 CPaaS) WhatsApp gateway.
 *
 * <p>These call {@link CpassWhatsappService} directly, regardless of the {@code whatsapp.provider}
 * flag, so cpass can be exercised end-to-end against the configured gateway. The raw gateway
 * response is returned in {@code gatewayResponse} on success; any transport / config failure is
 * returned in {@code error}. Endpoints are unauthenticated (see {@code WebMVCConfig} whitelist) and
 * intended for testing only — remove or secure before relying on them in production.</p>
 *
 * <p>Examples:
 * <pre>
 *   GET /cpass-test/text?mobile=9876543210&amp;body=Hello%20from%20cpass
 *   GET /cpass-test/document?mobile=9876543210&amp;link=https://host/file.pdf&amp;filename=INV.pdf&amp;caption=Your%20invoice
 * </pre>
 * </p>
 */
@RestController
@RequestMapping("/cpass-test")
@Transactional(rollbackFor = Throwable.class)
public class CpassTestController {

    private static final Logger LOGGER = LogManager.getLogger(CpassTestController.class);

    @Autowired
    private CpassWhatsappService cpassWhatsappService;

    @Autowired
    private NotificationService notificationService;

    @Value("${whatsapp.provider:cpass}")
    private String whatsappProvider;

    @Value("${prod:false}")
    private boolean isProd;

    @GetMapping("/text")
    public ResponseEntity<?> text(@RequestParam String mobile, @RequestParam String body) {
        LOGGER.info("cpass-test text: mobile={}", mobile);
        try {
            return ResponseEntity.ok(ok("text", mobile, cpassWhatsappService.sendTextDebug(mobile, body)));
        } catch (Exception e) {
            LOGGER.error("cpass-test text failed", e);
            return ResponseEntity.ok(err("text", mobile, e));
        }
    }

    @GetMapping("/image")
    public ResponseEntity<?> image(@RequestParam String mobile, @RequestParam String link,
                                   @RequestParam(required = false) String caption) {
        LOGGER.info("cpass-test image: mobile={} link={}", mobile, link);
        try {
            return ResponseEntity.ok(ok("image", mobile, cpassWhatsappService.sendImageDebug(mobile, link, caption)));
        } catch (Exception e) {
            LOGGER.error("cpass-test image failed", e);
            return ResponseEntity.ok(err("image", mobile, e));
        }
    }

    @GetMapping("/document")
    public ResponseEntity<?> document(@RequestParam String mobile, @RequestParam String link,
                                      @RequestParam(required = false) String caption,
                                      @RequestParam(required = false) String filename) {
        LOGGER.info("cpass-test document: mobile={} link={} filename={}", mobile, link, filename);
        try {
            return ResponseEntity.ok(ok("document", mobile,
                    cpassWhatsappService.sendDocumentDebug(mobile, link, caption, filename)));
        } catch (Exception e) {
            LOGGER.error("cpass-test document failed", e);
            return ResponseEntity.ok(err("document", mobile, e));
        }
    }

    /**
     * Sends a template via cpass. Supports every variant: body variables ({@code body}, comma-separated),
     * a media header ({@code headerType}=image|video|document + {@code mediaUrl}, plus {@code filename} for
     * documents), and a dynamic URL call-to-action button ({@code ctaUrl} at {@code ctaIndex}). Omit all
     * optional params for a no-variable template.
     */
    @GetMapping("/template")
    public ResponseEntity<?> template(@RequestParam String mobile, @RequestParam String name,
                                      @RequestParam(required = false, defaultValue = "en") String lang,
                                      @RequestParam(required = false) String body,
                                      @RequestParam(required = false) String headerType,
                                      @RequestParam(required = false) String mediaUrl,
                                      @RequestParam(required = false) String filename,
                                      @RequestParam(required = false) String ctaUrl,
                                      @RequestParam(required = false, defaultValue = "0") String ctaIndex) {
        LOGGER.info("cpass-test template: mobile={} name={} lang={} header={} cta={}", mobile, name, lang, headerType, ctaUrl);
        // body is a comma-separated list of body-variable values; omit for a no-variable template.
        List<String> params = (body == null || body.isEmpty()) ? null : Arrays.asList(body.split(","));
        try {
            return ResponseEntity.ok(ok("template", mobile,
                    cpassWhatsappService.sendTemplateDebug(mobile, name, lang, headerType, mediaUrl, filename, params, ctaIndex, ctaUrl)));
        } catch (Exception e) {
            LOGGER.error("cpass-test template failed", e);
            return ResponseEntity.ok(err("template", mobile, e));
        }
    }

    /**
     * Sends through {@link NotificationService} so the message goes via the <b>active</b> provider
     * (gupshup or cpass per {@code whatsapp.provider}) — i.e. the real production path, not cpass
     * directly. Pass {@code mediaUrl} (+ optional {@code filename}/{@code type}) for a media message;
     * otherwise a text message is sent. Note: text sends are gated by {@code prod=true} in the
     * service, while media sends go out regardless.
     */
    @GetMapping("/provider-send")
    public ResponseEntity<?> providerSend(@RequestParam String mobile,
                                          @RequestParam(required = false) String body,
                                          @RequestParam(required = false) String title,
                                          @RequestParam(required = false) String mediaUrl,
                                          @RequestParam(required = false) String filename,
                                          @RequestParam(required = false, defaultValue = "DOCUMENT") String type) {
        LOGGER.info("cpass-test provider-send: provider={} mobile={} media={}", whatsappProvider, mobile, mediaUrl);
        Map<String, Object> resp = new LinkedHashMap<>();
        resp.put("type", "provider-send");
        resp.put("provider", whatsappProvider);
        resp.put("mobile", mobile);
        resp.put("prod", isProd);
        try {
            boolean sent;
            if (mediaUrl != null && !mediaUrl.isEmpty()) {
                sent = notificationService.sendWhatsappMediaMessage(body, mobile, mediaUrl, filename, parseType(type));
            } else {
                sent = notificationService.sendWhatsappMessage(body, title, mobile);
            }
            resp.put("ok", true);
            resp.put("sent", sent);
            if (!sent) {
                resp.put("note", "sent=false — a text send returns false unless prod=true; media sends go out regardless. See the provider response in logs.");
            }
        } catch (Exception e) {
            LOGGER.error("cpass-test provider-send failed", e);
            resp.put("ok", false);
            resp.put("error", e.getClass().getSimpleName() + ": " + e.getMessage());
        }
        return ResponseEntity.ok(resp);
    }

    private WhatsappMessageType parseType(String type) {
        try {
            return WhatsappMessageType.valueOf(type.toUpperCase());
        } catch (Exception e) {
            return WhatsappMessageType.DOCUMENT;
        }
    }

    private Map<String, Object> ok(String type, String mobile, String gatewayResponse) {
        Map<String, Object> body = new LinkedHashMap<>();
        body.put("ok", true);
        body.put("type", type);
        body.put("mobile", mobile);
        body.put("gatewayResponse", gatewayResponse);
        body.put("note", "ok=true means the gateway was reached; inspect gatewayResponse for the message id or any error, and check the recipient's WhatsApp for delivery.");
        return body;
    }

    private Map<String, Object> err(String type, String mobile, Exception e) {
        Map<String, Object> body = new LinkedHashMap<>();
        body.put("ok", false);
        body.put("type", type);
        body.put("mobile", mobile);
        body.put("error", e.getClass().getSimpleName() + ": " + e.getMessage());
        return body;
    }
}