mirror of
https://github.com/abhinavxd/libredesk.git
synced 2025-10-23 05:11:57 +00:00
feat: add support for sending messages as contact
- introduce new permission `messages:write_as_contact` that needs to be set to allow this.
This commit is contained in:
@@ -734,7 +734,7 @@ func handleCreateConversation(r *fastglue.Request) error {
|
|||||||
return sendErrorEnvelope(r, envelope.NewError(envelope.GeneralError, app.i18n.Ts("globals.messages.errorSending", "name", "{globals.terms.message}"), nil))
|
return sendErrorEnvelope(r, envelope.NewError(envelope.GeneralError, app.i18n.Ts("globals.messages.errorSending", "name", "{globals.terms.message}"), nil))
|
||||||
}
|
}
|
||||||
case umodels.UserTypeContact:
|
case umodels.UserTypeContact:
|
||||||
// Create message on behalf of contact.
|
// Create contact message.
|
||||||
if _, err := app.conversation.CreateContactMessage(media, contact.ID, conversationUUID, req.Content, cmodels.ContentTypeHTML); err != nil {
|
if _, err := app.conversation.CreateContactMessage(media, contact.ID, conversationUUID, req.Content, cmodels.ContentTypeHTML); err != nil {
|
||||||
// Delete the conversation if message creation fails.
|
// Delete the conversation if message creation fails.
|
||||||
if err := app.conversation.DeleteConversation(conversationUUID); err != nil {
|
if err := app.conversation.DeleteConversation(conversationUUID); err != nil {
|
||||||
|
@@ -2,10 +2,14 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
amodels "github.com/abhinavxd/libredesk/internal/auth/models"
|
amodels "github.com/abhinavxd/libredesk/internal/auth/models"
|
||||||
|
authzModels "github.com/abhinavxd/libredesk/internal/authz/models"
|
||||||
|
cmodels "github.com/abhinavxd/libredesk/internal/conversation/models"
|
||||||
"github.com/abhinavxd/libredesk/internal/envelope"
|
"github.com/abhinavxd/libredesk/internal/envelope"
|
||||||
medModels "github.com/abhinavxd/libredesk/internal/media/models"
|
medModels "github.com/abhinavxd/libredesk/internal/media/models"
|
||||||
|
umodels "github.com/abhinavxd/libredesk/internal/user/models"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
"github.com/zerodha/fastglue"
|
"github.com/zerodha/fastglue"
|
||||||
)
|
)
|
||||||
@@ -17,6 +21,7 @@ type messageReq struct {
|
|||||||
To []string `json:"to"`
|
To []string `json:"to"`
|
||||||
CC []string `json:"cc"`
|
CC []string `json:"cc"`
|
||||||
BCC []string `json:"bcc"`
|
BCC []string `json:"bcc"`
|
||||||
|
SenderType string `json:"sender_type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleGetMessages returns messages for a conversation.
|
// handleGetMessages returns messages for a conversation.
|
||||||
@@ -150,7 +155,31 @@ func handleSendMessage(r *fastglue.Request) error {
|
|||||||
return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, app.i18n.Ts("globals.messages.errorParsing", "name", "{globals.terms.request}"), nil, envelope.InputError)
|
return r.SendErrorEnvelope(fasthttp.StatusInternalServerError, app.i18n.Ts("globals.messages.errorParsing", "name", "{globals.terms.request}"), nil, envelope.InputError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare attachments.
|
if req.SenderType != umodels.UserTypeAgent && req.SenderType != umodels.UserTypeContact {
|
||||||
|
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.Ts("globals.messages.invalid", "name", "`sender_type`"), nil, envelope.InputError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contacts cannot send private messages
|
||||||
|
if req.SenderType == umodels.UserTypeContact && req.Private {
|
||||||
|
return r.SendErrorEnvelope(fasthttp.StatusBadRequest, app.i18n.T("globals.messages.badRequest"), nil, envelope.InputError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user has permission to send messages as contact
|
||||||
|
if req.SenderType == umodels.UserTypeContact {
|
||||||
|
parts := strings.Split(authzModels.PermMessagesWriteAsContact, ":")
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return sendErrorEnvelope(r, envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.errorChecking", "name", "{globals.terms.permission}"), nil))
|
||||||
|
}
|
||||||
|
ok, err := app.authz.Enforce(user, parts[0], parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return sendErrorEnvelope(r, envelope.NewError(envelope.InputError, app.i18n.Ts("globals.messages.errorChecking", "name", "{globals.terms.permission}"), nil))
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return r.SendErrorEnvelope(fasthttp.StatusForbidden, app.i18n.Ts("globals.messages.denied", "name", "{globals.terms.permission}"), nil, envelope.PermissionError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get media for all attachments.
|
||||||
var media = make([]medModels.Media, 0, len(req.Attachments))
|
var media = make([]medModels.Media, 0, len(req.Attachments))
|
||||||
for _, id := range req.Attachments {
|
for _, id := range req.Attachments {
|
||||||
m, err := app.media.Get(id, "")
|
m, err := app.media.Get(id, "")
|
||||||
@@ -161,6 +190,16 @@ func handleSendMessage(r *fastglue.Request) error {
|
|||||||
media = append(media, m)
|
media = append(media, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create contact message.
|
||||||
|
if req.SenderType == umodels.UserTypeContact {
|
||||||
|
message, err := app.conversation.CreateContactMessage(media, int(conv.ContactID), cuuid, req.Message, cmodels.ContentTypeHTML)
|
||||||
|
if err != nil {
|
||||||
|
return sendErrorEnvelope(r, err)
|
||||||
|
}
|
||||||
|
return r.SendEnvelope(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send private note.
|
||||||
if req.Private {
|
if req.Private {
|
||||||
message, err := app.conversation.SendPrivateNote(media, user.ID, cuuid, req.Message)
|
message, err := app.conversation.SendPrivateNote(media, user.ID, cuuid, req.Message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -168,6 +207,8 @@ func handleSendMessage(r *fastglue.Request) error {
|
|||||||
}
|
}
|
||||||
return r.SendEnvelope(message)
|
return r.SendEnvelope(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Queue reply.
|
||||||
message, err := app.conversation.QueueReply(media, conv.InboxID, user.ID, cuuid, req.Message, req.To, req.CC, req.BCC, map[string]any{} /**meta**/)
|
message, err := app.conversation.QueueReply(media, conv.InboxID, user.ID, cuuid, req.Message, req.To, req.CC, req.BCC, map[string]any{} /**meta**/)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sendErrorEnvelope(r, err)
|
return sendErrorEnvelope(r, err)
|
||||||
|
@@ -12,6 +12,7 @@ export const permissions = {
|
|||||||
CONVERSATIONS_UPDATE_TAGS: 'conversations:update_tags',
|
CONVERSATIONS_UPDATE_TAGS: 'conversations:update_tags',
|
||||||
MESSAGES_READ: 'messages:read',
|
MESSAGES_READ: 'messages:read',
|
||||||
MESSAGES_WRITE: 'messages:write',
|
MESSAGES_WRITE: 'messages:write',
|
||||||
|
MESSAGES_WRITE_AS_CONTACT: 'messages:write_as_contact',
|
||||||
VIEW_MANAGE: 'view:manage',
|
VIEW_MANAGE: 'view:manage',
|
||||||
GENERAL_SETTINGS_MANAGE: 'general_settings:manage',
|
GENERAL_SETTINGS_MANAGE: 'general_settings:manage',
|
||||||
NOTIFICATION_SETTINGS_MANAGE: 'notification_settings:manage',
|
NOTIFICATION_SETTINGS_MANAGE: 'notification_settings:manage',
|
||||||
|
@@ -140,6 +140,7 @@ const permissions = ref([
|
|||||||
{ name: perms.CONVERSATIONS_UPDATE_TAGS, label: t('admin.role.conversations.updateTags') },
|
{ name: perms.CONVERSATIONS_UPDATE_TAGS, label: t('admin.role.conversations.updateTags') },
|
||||||
{ name: perms.MESSAGES_READ, label: t('admin.role.messages.read') },
|
{ name: perms.MESSAGES_READ, label: t('admin.role.messages.read') },
|
||||||
{ name: perms.MESSAGES_WRITE, label: t('admin.role.messages.write') },
|
{ name: perms.MESSAGES_WRITE, label: t('admin.role.messages.write') },
|
||||||
|
{ name: perms.MESSAGES_WRITE_AS_CONTACT, label: t('admin.role.messages.writeAsContact') },
|
||||||
{ name: perms.VIEW_MANAGE, label: t('admin.role.view.manage') }
|
{ name: perms.VIEW_MANAGE, label: t('admin.role.view.manage') }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@@ -122,6 +122,7 @@ import { Input } from '@/components/ui/input'
|
|||||||
import { useEmitter } from '@/composables/useEmitter'
|
import { useEmitter } from '@/composables/useEmitter'
|
||||||
import { useFileUpload } from '@/composables/useFileUpload'
|
import { useFileUpload } from '@/composables/useFileUpload'
|
||||||
import ReplyBoxContent from '@/features/conversation/ReplyBoxContent.vue'
|
import ReplyBoxContent from '@/features/conversation/ReplyBoxContent.vue'
|
||||||
|
import { UserTypeAgent } from '@/constants/user'
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormField,
|
FormField,
|
||||||
@@ -252,6 +253,7 @@ const processSend = async () => {
|
|||||||
if (hasTextContent.value > 0 || mediaFiles.value.length > 0) {
|
if (hasTextContent.value > 0 || mediaFiles.value.length > 0) {
|
||||||
const message = htmlContent.value
|
const message = htmlContent.value
|
||||||
await api.sendMessage(conversationStore.current.uuid, {
|
await api.sendMessage(conversationStore.current.uuid, {
|
||||||
|
sender_type: UserTypeAgent,
|
||||||
private: messageType.value === 'private_note',
|
private: messageType.value === 'private_note',
|
||||||
message: message,
|
message: message,
|
||||||
attachments: mediaFiles.value.map((file) => file.id),
|
attachments: mediaFiles.value.map((file) => file.id),
|
||||||
|
@@ -500,6 +500,7 @@
|
|||||||
"admin.role.conversations.updateTags": "Add or remove conversation tags",
|
"admin.role.conversations.updateTags": "Add or remove conversation tags",
|
||||||
"admin.role.messages.read": "View conversation messages",
|
"admin.role.messages.read": "View conversation messages",
|
||||||
"admin.role.messages.write": "Send messages in conversations",
|
"admin.role.messages.write": "Send messages in conversations",
|
||||||
|
"admin.role.messages.writeAsContact": "Send messages as contact",
|
||||||
"admin.role.view.manage": "Create and manage conversation views",
|
"admin.role.view.manage": "Create and manage conversation views",
|
||||||
"admin.role.generalSettings.manage": "Manage General Settings",
|
"admin.role.generalSettings.manage": "Manage General Settings",
|
||||||
"admin.role.notificationSettings.manage": "Manage Notification Settings",
|
"admin.role.notificationSettings.manage": "Manage Notification Settings",
|
||||||
|
@@ -15,6 +15,7 @@ const (
|
|||||||
PermConversationWrite = "conversations:write"
|
PermConversationWrite = "conversations:write"
|
||||||
PermMessagesRead = "messages:read"
|
PermMessagesRead = "messages:read"
|
||||||
PermMessagesWrite = "messages:write"
|
PermMessagesWrite = "messages:write"
|
||||||
|
PermMessagesWriteAsContact = "messages:write_as_contact"
|
||||||
|
|
||||||
// View
|
// View
|
||||||
PermViewManage = "view:manage"
|
PermViewManage = "view:manage"
|
||||||
@@ -102,6 +103,7 @@ var validPermissions = map[string]struct{}{
|
|||||||
PermConversationWrite: {},
|
PermConversationWrite: {},
|
||||||
PermMessagesRead: {},
|
PermMessagesRead: {},
|
||||||
PermMessagesWrite: {},
|
PermMessagesWrite: {},
|
||||||
|
PermMessagesWriteAsContact: {},
|
||||||
PermViewManage: {},
|
PermViewManage: {},
|
||||||
PermStatusManage: {},
|
PermStatusManage: {},
|
||||||
PermTagsManage: {},
|
PermTagsManage: {},
|
||||||
|
Reference in New Issue
Block a user