package main import ( "strconv" amodels "github.com/abhinavxd/libredesk/internal/auth/models" "github.com/abhinavxd/libredesk/internal/automation/models" "github.com/abhinavxd/libredesk/internal/envelope" medModels "github.com/abhinavxd/libredesk/internal/media/models" "github.com/valyala/fasthttp" "github.com/zerodha/fastglue" ) type messageReq struct { Attachments []int `json:"attachments"` Message string `json:"message"` Private bool `json:"private"` To []string `json:"to"` CC []string `json:"cc"` BCC []string `json:"bcc"` } // handleGetMessages returns messages for a conversation. func handleGetMessages(r *fastglue.Request) error { var ( app = r.Context.(*App) uuid = r.RequestCtx.UserValue("uuid").(string) auser = r.RequestCtx.UserValue("user").(amodels.User) page, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page"))) pageSize, _ = strconv.Atoi(string(r.RequestCtx.QueryArgs().Peek("page_size"))) total = 0 ) user, err := app.user.GetAgent(auser.ID, "") if err != nil { return sendErrorEnvelope(r, err) } // Check permission _, err = enforceConversationAccess(app, uuid, user) if err != nil { return sendErrorEnvelope(r, err) } messages, pageSize, err := app.conversation.GetConversationMessages(uuid, page, pageSize) if err != nil { return sendErrorEnvelope(r, err) } for i := range messages { total = messages[i].Total // Populate attachment URLs for j := range messages[i].Attachments { messages[i].Attachments[j].URL = app.media.GetURL(messages[i].Attachments[j].UUID) } // Redact CSAT survey link messages[i].CensorCSATContent() } return r.SendEnvelope(envelope.PageResults{ Total: total, Results: messages, Page: page, PerPage: pageSize, TotalPages: (total + pageSize - 1) / pageSize, }) } // handleGetMessage fetches a single from DB using the uuid. func handleGetMessage(r *fastglue.Request) error { var ( app = r.Context.(*App) uuid = r.RequestCtx.UserValue("uuid").(string) cuuid = r.RequestCtx.UserValue("cuuid").(string) auser = r.RequestCtx.UserValue("user").(amodels.User) ) user, err := app.user.GetAgent(auser.ID, "") if err != nil { return sendErrorEnvelope(r, err) } // Check permission _, err = enforceConversationAccess(app, cuuid, user) if err != nil { return sendErrorEnvelope(r, err) } message, err := app.conversation.GetMessage(uuid) if err != nil { return sendErrorEnvelope(r, err) } // Redact CSAT survey link message.CensorCSATContent() for j := range message.Attachments { message.Attachments[j].URL = app.media.GetURL(message.Attachments[j].UUID) } return r.SendEnvelope(message) } // handleRetryMessage changes message status so it can be retried for sending. func handleRetryMessage(r *fastglue.Request) error { var ( app = r.Context.(*App) uuid = r.RequestCtx.UserValue("uuid").(string) cuuid = r.RequestCtx.UserValue("cuuid").(string) auser = r.RequestCtx.UserValue("user").(amodels.User) ) user, err := app.user.GetAgent(auser.ID, "") if err != nil { return sendErrorEnvelope(r, err) } // Check permission _, err = enforceConversationAccess(app, cuuid, user) if err != nil { return sendErrorEnvelope(r, err) } if err = app.conversation.MarkMessageAsPending(uuid); err != nil { return sendErrorEnvelope(r, err) } return r.SendEnvelope(true) } // handleSendMessage sends a message in a conversation. func handleSendMessage(r *fastglue.Request) error { var ( app = r.Context.(*App) auser = r.RequestCtx.UserValue("user").(amodels.User) cuuid = r.RequestCtx.UserValue("cuuid").(string) req = messageReq{} ) user, err := app.user.GetAgent(auser.ID, "") if err != nil { return sendErrorEnvelope(r, err) } // Check access to conversation. conv, err := enforceConversationAccess(app, cuuid, user) if err != nil { return sendErrorEnvelope(r, err) } if err := r.Decode(&req, "json"); err != nil { app.lo.Error("error unmarshalling message request", "error", err) return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, app.i18n.Ts("globals.messages.errorParsing", "name", "{globals.terms.request}"), nil, envelope.InputError) } // Prepare attachments. var media = make([]medModels.Media, 0, len(req.Attachments)) for _, id := range req.Attachments { m, err := app.media.Get(id, "") if err != nil { app.lo.Error("error fetching media", "error", err) return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, app.i18n.Ts("globals.messages.errorFetching", "name", "{globals.terms.media}"), nil, envelope.GeneralError) } media = append(media, m) } if req.Private { if err := app.conversation.SendPrivateNote(media, user.ID, cuuid, req.Message); err != nil { return sendErrorEnvelope(r, err) } } else { if err := app.conversation.SendReply(media, conv.InboxID, user.ID, cuuid, req.Message, req.To, req.CC, req.BCC, map[string]any{} /**meta**/); err != nil { return sendErrorEnvelope(r, err) } // Evaluate automation rules. app.automation.EvaluateConversationUpdateRules(cuuid, models.EventConversationMessageOutgoing) } return r.SendEnvelope(true) }