2022-04-21 15:07:13 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
"regexp"
|
2022-04-21 16:54:08 +03:00
|
|
|
"time"
|
2022-04-21 15:07:13 +03:00
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
|
|
"github.com/labstack/gommon/log"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
validate = validator.New()
|
|
|
|
NotDigitsRegex = regexp.MustCompile("\\D+")
|
|
|
|
)
|
|
|
|
|
|
|
|
type Mock struct {
|
2022-04-21 16:54:08 +03:00
|
|
|
ContactsSuccess bool `json:"contacts_success"`
|
|
|
|
MessagesSuccess bool `json:"messages_success"`
|
|
|
|
MessagesStatus string `json:"messages_success_status" validate:"oneof=sent read failed"`
|
|
|
|
Webhook string `json:"webhook" validate:"url,startswith=http"`
|
|
|
|
WebhookHeaders map[string]string `json:"webhook_headers"`
|
2022-04-21 15:07:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
type Server struct {
|
2022-04-21 16:54:08 +03:00
|
|
|
g *gin.Engine
|
|
|
|
shooter *Shooter
|
|
|
|
mock Mock
|
2022-04-21 15:07:13 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewServer() (s *Server) {
|
2022-04-21 16:54:08 +03:00
|
|
|
s = &Server{
|
|
|
|
g: gin.New(),
|
|
|
|
mock: Mock{
|
|
|
|
ContactsSuccess: true,
|
|
|
|
MessagesSuccess: true,
|
|
|
|
MessagesStatus: "sent",
|
|
|
|
Webhook: "",
|
|
|
|
WebhookHeaders: map[string]string{},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
s.updateShooter()
|
2022-04-21 15:07:13 +03:00
|
|
|
s.g.GET("/mock", s.mockData)
|
|
|
|
s.g.POST("/mock", s.updateMockData)
|
|
|
|
api := s.g.Group("/v1")
|
|
|
|
{
|
|
|
|
api.POST("/contacts", s.contactsHandler)
|
|
|
|
api.POST("/messages", s.messagesHandler)
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) Run(addr ...string) error {
|
|
|
|
return s.g.Run(addr...)
|
|
|
|
}
|
|
|
|
|
2022-04-21 16:54:08 +03:00
|
|
|
func (s *Server) updateShooter() {
|
|
|
|
if s.shooter == nil {
|
|
|
|
s.shooter = NewShooter(s.mock.Webhook, s.mock.WebhookHeaders)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
s.shooter.Webhook = s.mock.Webhook
|
|
|
|
s.shooter.Headers = s.mock.WebhookHeaders
|
|
|
|
}
|
|
|
|
|
2022-04-21 15:07:13 +03:00
|
|
|
func (s *Server) baseResponseOk() BaseResponse {
|
|
|
|
return BaseResponse{
|
|
|
|
Meta: &Metadata{
|
|
|
|
Success: true,
|
|
|
|
APIStatus: "stable",
|
|
|
|
Version: "v2.31.5",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) bindRequest(c *gin.Context, req interface{}) error {
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
log.Printf("error: %s\n", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := validate.Struct(req); err != nil {
|
|
|
|
log.Printf("error: %s\n", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) mockData(c *gin.Context) {
|
|
|
|
c.JSON(http.StatusOK, s.mock)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) updateMockData(c *gin.Context) {
|
|
|
|
var mock Mock
|
2022-04-21 16:54:08 +03:00
|
|
|
if err := c.ShouldBindJSON(&mock); err != nil {
|
2022-04-21 15:07:13 +03:00
|
|
|
c.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
2022-04-21 16:54:08 +03:00
|
|
|
|
|
|
|
current := s.mock
|
|
|
|
current.ContactsSuccess = mock.ContactsSuccess
|
|
|
|
current.MessagesSuccess = mock.MessagesSuccess
|
|
|
|
|
|
|
|
if mock.MessagesStatus != "" {
|
|
|
|
current.MessagesStatus = mock.MessagesStatus
|
|
|
|
}
|
|
|
|
|
|
|
|
if mock.Webhook != "" {
|
|
|
|
current.Webhook = mock.Webhook
|
|
|
|
}
|
|
|
|
|
|
|
|
if mock.WebhookHeaders != nil {
|
|
|
|
current.WebhookHeaders = mock.WebhookHeaders
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := validate.Struct(current); err != nil {
|
|
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
s.mock = current
|
|
|
|
s.updateShooter()
|
2022-04-21 15:07:13 +03:00
|
|
|
c.JSON(http.StatusOK, s.mock)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) contactsHandler(c *gin.Context) {
|
|
|
|
var req ContactsRequest
|
|
|
|
if err := s.bindRequest(c, &req); err != nil || !s.mock.ContactsSuccess {
|
|
|
|
c.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
res := ContactsResponse{
|
|
|
|
BaseResponse: s.baseResponseOk(),
|
|
|
|
Contacts: make([]Contact, len(req.Contacts)),
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, contact := range req.Contacts {
|
|
|
|
res.Contacts[i] = Contact{
|
|
|
|
WaID: NotDigitsRegex.ReplaceAllString(contact, ""),
|
|
|
|
Input: contact,
|
|
|
|
Status: ContactStatusValid,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, res)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) messagesHandler(c *gin.Context) {
|
|
|
|
var req Message
|
|
|
|
if err := s.bindRequest(c, &req); err != nil || !s.mock.MessagesSuccess {
|
|
|
|
c.AbortWithStatus(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-04-21 16:54:08 +03:00
|
|
|
messageID := RandomString(27)
|
|
|
|
text := ""
|
|
|
|
if req.Text != nil {
|
|
|
|
text = req.Text.Body
|
|
|
|
}
|
|
|
|
|
2022-04-21 15:07:13 +03:00
|
|
|
log.Printf("Received new message: %#v\n", req)
|
|
|
|
|
2022-04-21 16:54:08 +03:00
|
|
|
if s.mock.Webhook != "" {
|
|
|
|
defer func(msgID, text string, to string) {
|
|
|
|
go func(msgID, text string, to string) {
|
|
|
|
time.Sleep(time.Millisecond * 500)
|
|
|
|
|
|
|
|
code, err := s.shooter.SendStatus(InboundStatus{
|
|
|
|
Type: "message",
|
|
|
|
ID: messageID,
|
|
|
|
RecipientID: to,
|
|
|
|
Status: s.mock.MessagesStatus,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("error: %s\n", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Printf("status webhook code: %d\n", code)
|
|
|
|
|
|
|
|
if text == "reply" {
|
|
|
|
code, err := s.shooter.SendText("Replying to the message", to)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("error: %s\n", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
log.Printf("reply webhook code: %d\n", code)
|
|
|
|
}
|
|
|
|
}(msgID, text, req.To)
|
|
|
|
}(messageID, text, req.To)
|
|
|
|
}
|
|
|
|
|
2022-04-21 15:07:13 +03:00
|
|
|
c.JSON(http.StatusOK, MessagesResponse{
|
|
|
|
BaseResponse: s.baseResponseOk(),
|
|
|
|
Messages: []IDModel{{
|
2022-04-21 16:54:08 +03:00
|
|
|
ID: messageID,
|
2022-04-21 15:07:13 +03:00
|
|
|
}},
|
|
|
|
})
|
|
|
|
}
|