Files
schedtxt_api/internal/handler/instant_message.go
T
phoenixandphoenix 0d252bc261 tsk-51: Send message endpoint (#52)
Closes #51

Reviewed-on: phoenix/textsender-api#52
Co-authored-by: phoenix <kundeng00@pm.me>
Co-committed-by: phoenix <kundeng00@pm.me>
2025-12-10 21:35:02 +00:00

192 lines
5.8 KiB
Go

package handler
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"strings"
"time"
"git.kundeng.us/phoenix/swoosh/swoop/send"
"git.kundeng.us/phoenix/textsender-models/tx0/contact"
"git.kundeng.us/phoenix/textsender-models/tx0/message"
"github.com/google/uuid"
"git.kundeng.us/phoenix/textsender-api/internal/app"
"git.kundeng.us/phoenix/textsender-api/internal/store"
)
const Contact_Limit = 400
type SendInstantMessageHandler struct {
App *app.App
MERStore store.MessageEventResponseStore
ContactStore store.ContactStore
MessageStore store.MessageStore
}
func NewSendInstantMessageHandler(apiApp *app.App, str store.MessageEventResponseStore, cStore store.ContactStore, mStore store.MessageStore) *SendInstantMessageHandler {
return &SendInstantMessageHandler{App: apiApp, MERStore: str, ContactStore: cStore, MessageStore: mStore}
}
type SendInstantMessageRequest struct {
ContactIds []uuid.UUID `json:"contact_ids"`
MessageId uuid.UUID `json:"message_id"`
UserId uuid.UUID `json:"user_id"`
}
type SendInstantMessageResponse struct {
Message string `json:"message"`
Data []*message.MessageEventResponse `json:"data"`
}
// Sent godoc
// @Summary Send instant message
// @Description Send a message without the constraints of scheduled messages (requires JWT)
// @Tags messages
// @Accept json
// @Produce json
// @Security BearerAuth
// @Param request body SendInstantMessageRequest true "Send an instnt message"
// @Success 201 {object} SendInstantMessageResponse
// @Failure 400 {object} SendInstantMessageResponse
// @Failure 500 {object} SendInstantMessageResponse
// @Router /instant/message [post]
func (s *SendInstantMessageHandler) Send(w http.ResponseWriter, r *http.Request) {
var req SendInstantMessageRequest
if err := ExtractFromRequest(r, &req); err != nil {
http.Error(w, InvalidJson(err), http.StatusBadRequest)
}
defer r.Body.Close()
var statusCode int
var resp SendInstantMessageResponse
if req.UserId == uuid.Nil {
statusCode = http.StatusBadRequest
resp.Message = "User Id is nil"
} else if req.MessageId == uuid.Nil {
statusCode = http.StatusBadRequest
resp.Message = "Message Id is nil"
} else if len(req.ContactIds) == 0 {
statusCode = http.StatusBadRequest
resp.Message = "No contacts provided"
} else {
if len(req.ContactIds) > Contact_Limit {
statusCode = http.StatusBadRequest
resp.Message = "Too many contacts"
} else {
ctx := r.Context()
if msg, contacts, err := s.verify(ctx, &req); err != nil {
statusCode = http.StatusInternalServerError
resp.Message = err.Error()
} else {
if msg == nil {
statusCode = http.StatusBadRequest
resp.Message = "Message is empty"
} else if len(contacts) == 0 {
statusCode = http.StatusBadRequest
resp.Message = "Contacts not found"
} else {
if s.App != nil {
msgSender := send.MessageSender{Config: s.App.TwilioConfig}
for _, c := range contacts {
if twilioResp, err := msgSender.Send(*msg, *c, nil); err != nil {
statusCode = http.StatusInternalServerError
resp.Message = err.Error()
} else {
if data, err := json.Marshal(twilioResp); err != nil {
statusCode = http.StatusInternalServerError
resp.Message = err.Error()
} else {
dateStr := strings.TrimSpace(*twilioResp.DateUpdated)
if parsedTime, err := time.Parse(time.RFC1123Z, dateStr); err != nil {
statusCode = http.StatusInternalServerError
resp.Message = err.Error()
} else {
mer := message.MessageEventResponse{}
mer.Response = data
mer.UserId = req.UserId
mer.Sent = parsedTime
if err := s.MERStore.Create(ctx, &mer); err != nil {
statusCode = http.StatusInternalServerError
resp.Message = err.Error()
} else {
statusCode = http.StatusOK
resp.Message = "Successful"
resp.Data = append(resp.Data, &mer)
}
}
}
}
}
} else {
statusCode = http.StatusInternalServerError
resp.Message = "Config not properly configured"
}
}
}
}
}
RespondWithJSON(w, statusCode, &resp)
}
func (s *SendInstantMessageHandler) verify(ctx context.Context, req *SendInstantMessageRequest) (*message.Message, []*contact.Contact, error) {
if msg, err := s.verifyMessage(ctx, req.MessageId); err != nil {
log.Println("Huh?")
return nil, nil, fmt.Errorf("Error:%v", err)
} else {
log.Println("Okay")
if msg != nil {
if contacts, err := s.verifyContacts(ctx, req.ContactIds); err != nil {
return nil, nil, fmt.Errorf("Error:%v", err)
} else {
if len(contacts) == 0 {
return msg, nil, nil
} else {
return msg, contacts, nil
}
}
} else {
log.Println("How can this be?")
return nil, nil, fmt.Errorf("Could not verify message")
}
}
}
func (s *SendInstantMessageHandler) verifyMessage(ctx context.Context, messageId uuid.UUID) (*message.Message, error) {
if msg, err := s.MessageStore.GetMessageByID(ctx, messageId); err != nil {
return nil, fmt.Errorf("Error getting message:%v", err)
} else {
if msg == nil {
log.Println("Message is nil")
return nil, nil
} else {
return msg, nil
}
}
}
func (s *SendInstantMessageHandler) verifyContacts(ctx context.Context, contactIds []uuid.UUID) ([]*contact.Contact, error) {
var contacts []*contact.Contact
for _, contactId := range contactIds {
if c, err := s.ContactStore.GetContactByID(ctx, contactId); err != nil {
return nil, fmt.Errorf("Error getting contacts:%v", err)
} else {
if c != nil {
contacts = append(contacts, c)
}
}
}
if len(contacts) == 0 {
return nil, nil
} else {
return contacts, nil
}
}