feat: Add channel-specific file upload rules and size limits (#12237)
This commit is contained in:
parent
19faa7fdfa
commit
39dfa35229
@ -6,15 +6,11 @@ import FileUpload from 'vue-upload-component';
|
|||||||
import * as ActiveStorage from 'activestorage';
|
import * as ActiveStorage from 'activestorage';
|
||||||
import inboxMixin from 'shared/mixins/inboxMixin';
|
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
|
||||||
import {
|
import { getAllowedFileTypesByChannel } from '@chatwoot/utils';
|
||||||
ALLOWED_FILE_TYPES,
|
|
||||||
ALLOWED_FILE_TYPES_FOR_TWILIO_WHATSAPP,
|
|
||||||
ALLOWED_FILE_TYPES_FOR_LINE,
|
|
||||||
ALLOWED_FILE_TYPES_FOR_INSTAGRAM,
|
|
||||||
} from 'shared/constants/messages';
|
|
||||||
import VideoCallButton from '../VideoCallButton.vue';
|
import VideoCallButton from '../VideoCallButton.vue';
|
||||||
import AIAssistanceButton from '../AIAssistanceButton.vue';
|
import AIAssistanceButton from '../AIAssistanceButton.vue';
|
||||||
import { REPLY_EDITOR_MODES } from './constants';
|
import { REPLY_EDITOR_MODES } from './constants';
|
||||||
|
import { INBOX_TYPES } from 'dashboard/helper/inbox';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import NextButton from 'dashboard/components-next/button/Button.vue';
|
import NextButton from 'dashboard/components-next/button/Button.vue';
|
||||||
|
|
||||||
@ -196,17 +192,16 @@ export default {
|
|||||||
return this.conversationType === 'instagram_direct_message';
|
return this.conversationType === 'instagram_direct_message';
|
||||||
},
|
},
|
||||||
allowedFileTypes() {
|
allowedFileTypes() {
|
||||||
if (this.isATwilioWhatsAppChannel) {
|
let channelType = this.channelType || this.inbox?.channel_type;
|
||||||
return ALLOWED_FILE_TYPES_FOR_TWILIO_WHATSAPP;
|
|
||||||
}
|
|
||||||
if (this.isALineChannel) {
|
|
||||||
return ALLOWED_FILE_TYPES_FOR_LINE;
|
|
||||||
}
|
|
||||||
if (this.isAnInstagramChannel || this.isInstagramDM) {
|
if (this.isAnInstagramChannel || this.isInstagramDM) {
|
||||||
return ALLOWED_FILE_TYPES_FOR_INSTAGRAM;
|
channelType = INBOX_TYPES.INSTAGRAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ALLOWED_FILE_TYPES;
|
return getAllowedFileTypesByChannel({
|
||||||
|
channelType,
|
||||||
|
medium: this.inbox?.medium,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
enableDragAndDrop() {
|
enableDragAndDrop() {
|
||||||
return !this.newConversationModalActive;
|
return !this.newConversationModalActive;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useAlert } from 'dashboard/composables';
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { DirectUpload } from 'activestorage';
|
import { DirectUpload } from 'activestorage';
|
||||||
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
||||||
import { MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL } from 'shared/constants/messages';
|
import { getMaxUploadSizeByChannel } from '@chatwoot/utils';
|
||||||
|
|
||||||
vi.mock('dashboard/composables/store');
|
vi.mock('dashboard/composables/store');
|
||||||
vi.mock('dashboard/composables', () => ({
|
vi.mock('dashboard/composables', () => ({
|
||||||
@ -13,6 +13,7 @@ vi.mock('dashboard/composables', () => ({
|
|||||||
vi.mock('vue-i18n');
|
vi.mock('vue-i18n');
|
||||||
vi.mock('activestorage');
|
vi.mock('activestorage');
|
||||||
vi.mock('shared/helpers/FileHelper');
|
vi.mock('shared/helpers/FileHelper');
|
||||||
|
vi.mock('@chatwoot/utils');
|
||||||
|
|
||||||
describe('useFileUpload', () => {
|
describe('useFileUpload', () => {
|
||||||
const mockAttachFile = vi.fn();
|
const mockAttachFile = vi.fn();
|
||||||
@ -22,6 +23,11 @@ describe('useFileUpload', () => {
|
|||||||
file: new File(['test'], 'test.jpg', { type: 'image/jpeg' }),
|
file: new File(['test'], 'test.jpg', { type: 'image/jpeg' }),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const inbox = {
|
||||||
|
channel_type: 'Channel::WhatsApp',
|
||||||
|
medium: 'whatsapp',
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
@ -37,11 +43,12 @@ describe('useFileUpload', () => {
|
|||||||
|
|
||||||
useI18n.mockReturnValue({ t: mockTranslate });
|
useI18n.mockReturnValue({ t: mockTranslate });
|
||||||
checkFileSizeLimit.mockReturnValue(true);
|
checkFileSizeLimit.mockReturnValue(true);
|
||||||
|
getMaxUploadSizeByChannel.mockReturnValue(25); // default max size MB for tests
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle direct file upload when enabled', () => {
|
it('handles direct file upload when direct uploads enabled', () => {
|
||||||
const { onFileUpload } = useFileUpload({
|
const { onFileUpload } = useFileUpload({
|
||||||
isATwilioSMSChannel: false,
|
inbox,
|
||||||
attachFile: mockAttachFile,
|
attachFile: mockAttachFile,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -52,6 +59,16 @@ describe('useFileUpload', () => {
|
|||||||
|
|
||||||
onFileUpload(mockFile);
|
onFileUpload(mockFile);
|
||||||
|
|
||||||
|
// size rules called with inbox + mime
|
||||||
|
expect(getMaxUploadSizeByChannel).toHaveBeenCalledWith({
|
||||||
|
channelType: inbox.channel_type,
|
||||||
|
medium: inbox.medium,
|
||||||
|
mime: 'image/jpeg',
|
||||||
|
});
|
||||||
|
|
||||||
|
// size check called with max from helper
|
||||||
|
expect(checkFileSizeLimit).toHaveBeenCalledWith(mockFile, 25);
|
||||||
|
|
||||||
expect(DirectUpload).toHaveBeenCalledWith(
|
expect(DirectUpload).toHaveBeenCalledWith(
|
||||||
mockFile.file,
|
mockFile.file,
|
||||||
'/api/v1/accounts/123/conversations/456/direct_uploads',
|
'/api/v1/accounts/123/conversations/456/direct_uploads',
|
||||||
@ -63,7 +80,7 @@ describe('useFileUpload', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle indirect file upload when direct upload is disabled', () => {
|
it('handles indirect file upload when direct upload disabled', () => {
|
||||||
useMapGetter.mockImplementation(getter => {
|
useMapGetter.mockImplementation(getter => {
|
||||||
const getterMap = {
|
const getterMap = {
|
||||||
getCurrentAccountId: { value: '123' },
|
getCurrentAccountId: { value: '123' },
|
||||||
@ -75,22 +92,24 @@ describe('useFileUpload', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { onFileUpload } = useFileUpload({
|
const { onFileUpload } = useFileUpload({
|
||||||
isATwilioSMSChannel: false,
|
inbox,
|
||||||
attachFile: mockAttachFile,
|
attachFile: mockAttachFile,
|
||||||
});
|
});
|
||||||
|
|
||||||
onFileUpload(mockFile);
|
onFileUpload(mockFile);
|
||||||
|
|
||||||
expect(DirectUpload).not.toHaveBeenCalled();
|
expect(DirectUpload).not.toHaveBeenCalled();
|
||||||
|
expect(getMaxUploadSizeByChannel).toHaveBeenCalled();
|
||||||
|
expect(checkFileSizeLimit).toHaveBeenCalledWith(mockFile, 25);
|
||||||
expect(mockAttachFile).toHaveBeenCalledWith({ file: mockFile });
|
expect(mockAttachFile).toHaveBeenCalledWith({ file: mockFile });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show alert when file size exceeds limit', () => {
|
it('shows alert when file size exceeds limit', () => {
|
||||||
checkFileSizeLimit.mockReturnValue(false);
|
checkFileSizeLimit.mockReturnValue(false);
|
||||||
mockTranslate.mockReturnValue('File size exceeds limit');
|
mockTranslate.mockReturnValue('File size exceeds limit');
|
||||||
|
|
||||||
const { onFileUpload } = useFileUpload({
|
const { onFileUpload } = useFileUpload({
|
||||||
isATwilioSMSChannel: false,
|
inbox,
|
||||||
attachFile: mockAttachFile,
|
attachFile: mockAttachFile,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -100,28 +119,37 @@ describe('useFileUpload', () => {
|
|||||||
expect(mockAttachFile).not.toHaveBeenCalled();
|
expect(mockAttachFile).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use different max file size for Twilio SMS channel', () => {
|
it('uses per-mime limits from helper', () => {
|
||||||
|
getMaxUploadSizeByChannel.mockImplementation(({ mime }) =>
|
||||||
|
mime.startsWith('image/') ? 10 : 50
|
||||||
|
);
|
||||||
const { onFileUpload } = useFileUpload({
|
const { onFileUpload } = useFileUpload({
|
||||||
isATwilioSMSChannel: true,
|
inbox,
|
||||||
attachFile: mockAttachFile,
|
attachFile: mockAttachFile,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
DirectUpload.mockImplementation(() => ({
|
||||||
|
create: cb => cb(null, { signed_id: 'blob' }),
|
||||||
|
}));
|
||||||
|
|
||||||
onFileUpload(mockFile);
|
onFileUpload(mockFile);
|
||||||
|
|
||||||
expect(checkFileSizeLimit).toHaveBeenCalledWith(
|
expect(getMaxUploadSizeByChannel).toHaveBeenCalledWith({
|
||||||
mockFile,
|
channelType: inbox.channel_type,
|
||||||
MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL
|
medium: inbox.medium,
|
||||||
);
|
mime: 'image/jpeg',
|
||||||
|
});
|
||||||
|
expect(checkFileSizeLimit).toHaveBeenCalledWith(mockFile, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle direct upload errors', () => {
|
it('handles direct upload errors', () => {
|
||||||
const mockError = 'Upload failed';
|
const mockError = 'Upload failed';
|
||||||
DirectUpload.mockImplementation(() => ({
|
DirectUpload.mockImplementation(() => ({
|
||||||
create: callback => callback(mockError, null),
|
create: callback => callback(mockError, null),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const { onFileUpload } = useFileUpload({
|
const { onFileUpload } = useFileUpload({
|
||||||
isATwilioSMSChannel: false,
|
inbox,
|
||||||
attachFile: mockAttachFile,
|
attachFile: mockAttachFile,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -131,15 +159,16 @@ describe('useFileUpload', () => {
|
|||||||
expect(mockAttachFile).not.toHaveBeenCalled();
|
expect(mockAttachFile).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should do nothing when file is null', () => {
|
it('does nothing when file is null', () => {
|
||||||
const { onFileUpload } = useFileUpload({
|
const { onFileUpload } = useFileUpload({
|
||||||
isATwilioSMSChannel: false,
|
inbox,
|
||||||
attachFile: mockAttachFile,
|
attachFile: mockAttachFile,
|
||||||
});
|
});
|
||||||
|
|
||||||
onFileUpload(null);
|
onFileUpload(null);
|
||||||
|
|
||||||
expect(checkFileSizeLimit).not.toHaveBeenCalled();
|
expect(checkFileSizeLimit).not.toHaveBeenCalled();
|
||||||
|
expect(getMaxUploadSizeByChannel).not.toHaveBeenCalled();
|
||||||
expect(mockAttachFile).not.toHaveBeenCalled();
|
expect(mockAttachFile).not.toHaveBeenCalled();
|
||||||
expect(useAlert).not.toHaveBeenCalled();
|
expect(useAlert).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,22 +1,17 @@
|
|||||||
import { computed } from 'vue';
|
|
||||||
import { useMapGetter } from 'dashboard/composables/store';
|
import { useMapGetter } from 'dashboard/composables/store';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { DirectUpload } from 'activestorage';
|
import { DirectUpload } from 'activestorage';
|
||||||
import {
|
|
||||||
MAXIMUM_FILE_UPLOAD_SIZE,
|
|
||||||
MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL,
|
|
||||||
} from 'shared/constants/messages';
|
|
||||||
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
||||||
|
import { getMaxUploadSizeByChannel } from '@chatwoot/utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composable for handling file uploads in conversations
|
* Composable for handling file uploads in conversations
|
||||||
* @param {Object} options - Configuration options
|
* @param {Object} options
|
||||||
* @param {boolean} options.isATwilioSMSChannel - Whether the current channel is Twilio SMS
|
* @param {Object} options.inbox - Current inbox object (has channel_type, medium, etc.)
|
||||||
* @param {Function} options.attachFile - Callback function to handle file attachment
|
* @param {Function} options.attachFile - Callback to handle file attachment
|
||||||
* @returns {Object} File upload methods and utilities
|
|
||||||
*/
|
*/
|
||||||
export const useFileUpload = ({ isATwilioSMSChannel, attachFile }) => {
|
export const useFileUpload = ({ inbox, attachFile }) => {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const accountId = useMapGetter('getCurrentAccountId');
|
const accountId = useMapGetter('getCurrentAccountId');
|
||||||
@ -24,57 +19,66 @@ export const useFileUpload = ({ isATwilioSMSChannel, attachFile }) => {
|
|||||||
const currentChat = useMapGetter('getSelectedChat');
|
const currentChat = useMapGetter('getSelectedChat');
|
||||||
const globalConfig = useMapGetter('globalConfig/get');
|
const globalConfig = useMapGetter('globalConfig/get');
|
||||||
|
|
||||||
const maxFileSize = computed(() =>
|
// helper: compute max upload size for a given file's mime
|
||||||
isATwilioSMSChannel
|
const maxSizeFor = mime =>
|
||||||
? MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL
|
getMaxUploadSizeByChannel({
|
||||||
: MAXIMUM_FILE_UPLOAD_SIZE
|
channelType: inbox?.channel_type,
|
||||||
);
|
medium: inbox?.medium, // e.g. 'sms' | 'whatsapp' | etc.
|
||||||
|
mime, // e.g. 'image/png'
|
||||||
|
});
|
||||||
|
|
||||||
|
const alertOverLimit = maxSizeMB =>
|
||||||
|
useAlert(
|
||||||
|
t('CONVERSATION.FILE_SIZE_LIMIT', {
|
||||||
|
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE: maxSizeMB,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const handleDirectFileUpload = file => {
|
const handleDirectFileUpload = file => {
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
if (checkFileSizeLimit(file, maxFileSize.value)) {
|
const mime = file.file?.type || file.type;
|
||||||
const upload = new DirectUpload(
|
const maxSizeMB = maxSizeFor(mime);
|
||||||
file.file,
|
|
||||||
`/api/v1/accounts/${accountId.value}/conversations/${currentChat.value.id}/direct_uploads`,
|
|
||||||
{
|
|
||||||
directUploadWillCreateBlobWithXHR: xhr => {
|
|
||||||
xhr.setRequestHeader(
|
|
||||||
'api_access_token',
|
|
||||||
currentUser.value.access_token
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
upload.create((error, blob) => {
|
if (!checkFileSizeLimit(file, maxSizeMB)) {
|
||||||
if (error) {
|
alertOverLimit(maxSizeMB);
|
||||||
useAlert(error);
|
return;
|
||||||
} else {
|
|
||||||
attachFile({ file, blob });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
useAlert(
|
|
||||||
t('CONVERSATION.FILE_SIZE_LIMIT', {
|
|
||||||
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE: maxFileSize.value,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const upload = new DirectUpload(
|
||||||
|
file.file,
|
||||||
|
`/api/v1/accounts/${accountId.value}/conversations/${currentChat.value.id}/direct_uploads`,
|
||||||
|
{
|
||||||
|
directUploadWillCreateBlobWithXHR: xhr => {
|
||||||
|
xhr.setRequestHeader(
|
||||||
|
'api_access_token',
|
||||||
|
currentUser.value.access_token
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
upload.create((error, blob) => {
|
||||||
|
if (error) {
|
||||||
|
useAlert(error);
|
||||||
|
} else {
|
||||||
|
attachFile({ file, blob });
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleIndirectFileUpload = file => {
|
const handleIndirectFileUpload = file => {
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
if (checkFileSizeLimit(file, maxFileSize.value)) {
|
const mime = file.file?.type || file.type;
|
||||||
attachFile({ file });
|
const maxSizeMB = maxSizeFor(mime);
|
||||||
} else {
|
|
||||||
useAlert(
|
if (!checkFileSizeLimit(file, maxSizeMB)) {
|
||||||
t('CONVERSATION.FILE_SIZE_LIMIT', {
|
alertOverLimit(maxSizeMB);
|
||||||
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE: maxFileSize.value,
|
return;
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachFile({ file });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFileUpload = file => {
|
const onFileUpload = file => {
|
||||||
@ -85,7 +89,5 @@ export const useFileUpload = ({ isATwilioSMSChannel, attachFile }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return { onFileUpload };
|
||||||
onFileUpload,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import { useAlert } from 'dashboard/composables';
|
import { useAlert } from 'dashboard/composables';
|
||||||
import {
|
|
||||||
MAXIMUM_FILE_UPLOAD_SIZE,
|
|
||||||
MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL,
|
|
||||||
} from 'shared/constants/messages';
|
|
||||||
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
||||||
|
import { getMaxUploadSizeByChannel } from '@chatwoot/utils';
|
||||||
import { DirectUpload } from 'activestorage';
|
import { DirectUpload } from 'activestorage';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -13,7 +10,22 @@ export default {
|
|||||||
accountId: 'getCurrentAccountId',
|
accountId: 'getCurrentAccountId',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
maxSizeFor(mime) {
|
||||||
|
return getMaxUploadSizeByChannel({
|
||||||
|
channelType: this.inbox?.channel_type,
|
||||||
|
medium: this.inbox?.medium, // e.g. 'sms' | 'whatsapp'
|
||||||
|
mime, // e.g. 'image/png'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
alertOverLimit(maxSizeMB) {
|
||||||
|
useAlert(
|
||||||
|
this.$t('CONVERSATION.FILE_SIZE_LIMIT', {
|
||||||
|
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE: maxSizeMB,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
onFileUpload(file) {
|
onFileUpload(file) {
|
||||||
if (this.globalConfig.directUploadsEnabled) {
|
if (this.globalConfig.directUploadsEnabled) {
|
||||||
this.onDirectFileUpload(file);
|
this.onDirectFileUpload(file);
|
||||||
@ -21,59 +33,52 @@ export default {
|
|||||||
this.onIndirectFileUpload(file);
|
this.onIndirectFileUpload(file);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onDirectFileUpload(file) {
|
onDirectFileUpload(file) {
|
||||||
const MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE = this.isATwilioSMSChannel
|
if (!file) return;
|
||||||
? MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL
|
|
||||||
: MAXIMUM_FILE_UPLOAD_SIZE;
|
|
||||||
|
|
||||||
if (!file) {
|
const mime = file.file?.type || file.type;
|
||||||
|
const maxSizeMB = this.maxSizeFor(mime);
|
||||||
|
|
||||||
|
if (!checkFileSizeLimit(file, maxSizeMB)) {
|
||||||
|
this.alertOverLimit(maxSizeMB);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (checkFileSizeLimit(file, MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE)) {
|
|
||||||
const upload = new DirectUpload(
|
|
||||||
file.file,
|
|
||||||
`/api/v1/accounts/${this.accountId}/conversations/${this.currentChat.id}/direct_uploads`,
|
|
||||||
{
|
|
||||||
directUploadWillCreateBlobWithXHR: xhr => {
|
|
||||||
xhr.setRequestHeader(
|
|
||||||
'api_access_token',
|
|
||||||
this.currentUser.access_token
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
upload.create((error, blob) => {
|
const upload = new DirectUpload(
|
||||||
if (error) {
|
file.file,
|
||||||
useAlert(error);
|
`/api/v1/accounts/${this.accountId}/conversations/${this.currentChat.id}/direct_uploads`,
|
||||||
} else {
|
{
|
||||||
this.attachFile({ file, blob });
|
directUploadWillCreateBlobWithXHR: xhr => {
|
||||||
}
|
xhr.setRequestHeader(
|
||||||
});
|
'api_access_token',
|
||||||
} else {
|
this.currentUser.access_token
|
||||||
useAlert(
|
);
|
||||||
this.$t('CONVERSATION.FILE_SIZE_LIMIT', {
|
},
|
||||||
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE,
|
}
|
||||||
})
|
);
|
||||||
);
|
|
||||||
}
|
upload.create((error, blob) => {
|
||||||
|
if (error) {
|
||||||
|
useAlert(error);
|
||||||
|
} else {
|
||||||
|
this.attachFile({ file, blob });
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onIndirectFileUpload(file) {
|
onIndirectFileUpload(file) {
|
||||||
const MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE = this.isATwilioSMSChannel
|
if (!file) return;
|
||||||
? MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL
|
|
||||||
: MAXIMUM_FILE_UPLOAD_SIZE;
|
const mime = file.file?.type || file.type;
|
||||||
if (!file) {
|
const maxSizeMB = this.maxSizeFor(mime);
|
||||||
|
|
||||||
|
if (!checkFileSizeLimit(file, maxSizeMB)) {
|
||||||
|
this.alertOverLimit(maxSizeMB);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (checkFileSizeLimit(file, MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE)) {
|
|
||||||
this.attachFile({ file });
|
this.attachFile({ file });
|
||||||
} else {
|
|
||||||
useAlert(
|
|
||||||
this.$t('CONVERSATION.FILE_SIZE_LIMIT', {
|
|
||||||
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -36,7 +36,6 @@ export const CONVERSATION_PRIORITY_ORDER = {
|
|||||||
|
|
||||||
// Size in mega bytes
|
// Size in mega bytes
|
||||||
export const MAXIMUM_FILE_UPLOAD_SIZE = 40;
|
export const MAXIMUM_FILE_UPLOAD_SIZE = 40;
|
||||||
export const MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL = 5;
|
|
||||||
|
|
||||||
export const ALLOWED_FILE_TYPES =
|
export const ALLOWED_FILE_TYPES =
|
||||||
'image/*,' +
|
'image/*,' +
|
||||||
@ -50,18 +49,6 @@ export const ALLOWED_FILE_TYPES =
|
|||||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,' +
|
'application/vnd.openxmlformats-officedocument.presentationml.presentation, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,' +
|
||||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document,';
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document,';
|
||||||
|
|
||||||
export const ALLOWED_FILE_TYPES_FOR_TWILIO_WHATSAPP =
|
|
||||||
'image/png, image/jpeg,' +
|
|
||||||
'audio/mpeg, audio/opus, audio/ogg, audio/amr,' +
|
|
||||||
'video/mp4,' +
|
|
||||||
'application/pdf,';
|
|
||||||
// https://developers.line.biz/en/reference/messaging-api/#image-message, https://developers.line.biz/en/reference/messaging-api/#video-message
|
|
||||||
export const ALLOWED_FILE_TYPES_FOR_LINE = 'image/png, image/jpeg,video/mp4';
|
|
||||||
|
|
||||||
// https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/messaging-api#requirements
|
|
||||||
export const ALLOWED_FILE_TYPES_FOR_INSTAGRAM =
|
|
||||||
'image/png, image/jpeg, video/mp4, video/mov, video/webm';
|
|
||||||
|
|
||||||
export const CSAT_RATINGS = [
|
export const CSAT_RATINGS = [
|
||||||
{
|
{
|
||||||
key: 'disappointed',
|
key: 'disappointed',
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
"@breezystack/lamejs": "^1.2.7",
|
"@breezystack/lamejs": "^1.2.7",
|
||||||
"@chatwoot/ninja-keys": "1.2.3",
|
"@chatwoot/ninja-keys": "1.2.3",
|
||||||
"@chatwoot/prosemirror-schema": "1.2.1",
|
"@chatwoot/prosemirror-schema": "1.2.1",
|
||||||
"@chatwoot/utils": "^0.0.49",
|
"@chatwoot/utils": "^0.0.50",
|
||||||
"@formkit/core": "^1.6.7",
|
"@formkit/core": "^1.6.7",
|
||||||
"@formkit/vue": "^1.6.7",
|
"@formkit/vue": "^1.6.7",
|
||||||
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
|
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
|
||||||
|
|||||||
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@ -23,8 +23,8 @@ importers:
|
|||||||
specifier: 1.2.1
|
specifier: 1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
'@chatwoot/utils':
|
'@chatwoot/utils':
|
||||||
specifier: ^0.0.49
|
specifier: ^0.0.50
|
||||||
version: 0.0.49
|
version: 0.0.50
|
||||||
'@formkit/core':
|
'@formkit/core':
|
||||||
specifier: ^1.6.7
|
specifier: ^1.6.7
|
||||||
version: 1.6.7
|
version: 1.6.7
|
||||||
@ -406,8 +406,8 @@ packages:
|
|||||||
'@chatwoot/prosemirror-schema@1.2.1':
|
'@chatwoot/prosemirror-schema@1.2.1':
|
||||||
resolution: {integrity: sha512-UbiEvG5tgi1d0lMbkaqxgTh7vHfywEYKLQo1sxqp4Q7aLZh4QFtbLzJ2zyBtu4Nhipe+guFfEJdic7i43MP/XQ==}
|
resolution: {integrity: sha512-UbiEvG5tgi1d0lMbkaqxgTh7vHfywEYKLQo1sxqp4Q7aLZh4QFtbLzJ2zyBtu4Nhipe+guFfEJdic7i43MP/XQ==}
|
||||||
|
|
||||||
'@chatwoot/utils@0.0.49':
|
'@chatwoot/utils@0.0.50':
|
||||||
resolution: {integrity: sha512-Co68VzaFtctTNYKY6y4izBBATvk6/8ZVtkyEP5HL72uhFDA11LrY5pqSh04HMoFyfdIU+uVPimfI45HAeso1IA==}
|
resolution: {integrity: sha512-GGvB+ujt+8qnV6KKEM2IH9/JmbMpMMfrJ4C+SdPvd/WbhUEFvRof0D9fsU+444G8BUh2om7GM7mXOa3pEH+Vtw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
'@codemirror/commands@6.7.0':
|
'@codemirror/commands@6.7.0':
|
||||||
@ -5268,7 +5268,7 @@ snapshots:
|
|||||||
prosemirror-utils: 1.2.2(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)
|
prosemirror-utils: 1.2.2(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)
|
||||||
prosemirror-view: 1.34.1
|
prosemirror-view: 1.34.1
|
||||||
|
|
||||||
'@chatwoot/utils@0.0.49':
|
'@chatwoot/utils@0.0.50':
|
||||||
dependencies:
|
dependencies:
|
||||||
date-fns: 2.30.0
|
date-fns: 2.30.0
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user