diff --git a/api/src/attachment/controllers/attachment.controller.ts b/api/src/attachment/controllers/attachment.controller.ts index ef118204..11a88868 100644 --- a/api/src/attachment/controllers/attachment.controller.ts +++ b/api/src/attachment/controllers/attachment.controller.ts @@ -143,7 +143,7 @@ export class AttachmentController extends BaseController { ); } - const attachments = []; + const attachments: Attachment[] = []; for (const file of files.file) { const attachment = await this.attachmentService.store(file, { name: file.originalname, @@ -153,7 +153,10 @@ export class AttachmentController extends BaseController { createdBy: userId, createdByRef: 'User', }); - attachments.push(attachment); + + if (attachment) { + attachments.push(attachment); + } } return attachments; diff --git a/api/src/attachment/dto/attachment.dto.ts b/api/src/attachment/dto/attachment.dto.ts index 6c3c982f..14bdca30 100644 --- a/api/src/attachment/dto/attachment.dto.ts +++ b/api/src/attachment/dto/attachment.dto.ts @@ -132,5 +132,6 @@ export class AttachmentContextParamDto { }) @IsString() @IsIn(Object.values(AttachmentContext)) - context?: TAttachmentContext; + @IsNotEmpty() + context: TAttachmentContext; } diff --git a/api/src/attachment/services/attachment.service.ts b/api/src/attachment/services/attachment.service.ts index 1d4ac708..b81e84b6 100644 --- a/api/src/attachment/services/attachment.service.ts +++ b/api/src/attachment/services/attachment.service.ts @@ -181,10 +181,10 @@ export class AttachmentService extends BaseService { async store( file: Buffer | Stream | Readable | Express.Multer.File, metadata: AttachmentMetadataDto, - ): Promise { + ): Promise { if (this.getStoragePlugin()) { const storedDto = await this.getStoragePlugin()?.store?.(file, metadata); - return storedDto ? await this.create(storedDto) : undefined; + return storedDto ? await this.create(storedDto) : null; } else { const rootDir = this.getRootDirByContext(metadata.context); const uniqueFilename = generateUniqueFilename(metadata.name); diff --git a/api/src/channel/lib/EventWrapper.ts b/api/src/channel/lib/EventWrapper.ts index 03c37a8f..73b4d121 100644 --- a/api/src/channel/lib/EventWrapper.ts +++ b/api/src/channel/lib/EventWrapper.ts @@ -8,7 +8,6 @@ import { Attachment } from '@/attachment/schemas/attachment.schema'; import { Subscriber } from '@/chat/schemas/subscriber.schema'; -import { AttachmentPayload } from '@/chat/schemas/types/attachment'; import { SubscriberChannelData } from '@/chat/schemas/types/channel'; import { IncomingMessageType, @@ -78,7 +77,6 @@ export default abstract class EventWrapper< messageType: this.getMessageType(), payload: this.getPayload(), message: this.getMessage(), - attachments: this.getAttachments(), deliveredMessages: this.getDeliveredMessages(), watermark: this.getWatermark(), }, @@ -205,7 +203,15 @@ export default abstract class EventWrapper< this._adapter.eventType === StdEventType.message && this._adapter.messageType === IncomingMessageType.attachments ) { - await this._handler.persistMessageAttachments(this); + await this._handler.persistMessageAttachments( + this as EventWrapper< + any, + any, + ChannelName, + ChannelHandler, + Record + >, + ); } } @@ -263,13 +269,6 @@ export default abstract class EventWrapper< return ''; } - /** - * Returns the list of received attachments - * - * @returns Received attachments message - */ - abstract getAttachments(): AttachmentPayload[]; - /** * Returns the list of delivered messages * @@ -393,14 +392,6 @@ export class GenericEventWrapper extends EventWrapper< throw new Error('Unknown incoming message type'); } - /** - * @returns A list of received attachments - * @deprecated - This method is deprecated - */ - getAttachments(): AttachmentPayload[] { - return []; - } - /** * Returns the delivered messages ids * diff --git a/api/src/chat/services/chat.service.ts b/api/src/chat/services/chat.service.ts index 672bccd7..67c27774 100644 --- a/api/src/chat/services/chat.service.ts +++ b/api/src/chat/services/chat.service.ts @@ -256,6 +256,10 @@ export class ChatService { this.eventEmitter.emit('hook:stats:entry', 'new_users', 'New users'); subscriberData.channel = event.getChannelData(); subscriber = await this.subscriberService.create(subscriberData); + + if (!subscriber) { + throw new Error('Unable to create a new subscriber'); + } } else { // Already existing user profile // Exec lastvisit hook @@ -288,18 +292,22 @@ export class ChatService { avatar: avatar.id, }, ); + + if (!subscriber) { + throw new Error('Unable to update the subscriber avatar'); + } } } } catch (err) { this.logger.error( - `Unable to retrieve avatar for subscriber ${subscriber.id}`, + `Unable to retrieve avatar for subscriber ${event.getSenderForeignId()}`, err, ); } } // Set the subscriber object - event.setSender(subscriber); + event.setSender(subscriber!); // Preprocess the event (persist attachments, ...) if (event.preprocess) { @@ -309,7 +317,7 @@ export class ChatService { // Trigger message received event this.eventEmitter.emit('hook:chatbot:received', event); - if (subscriber.assignedTo) { + if (subscriber?.assignedTo) { this.logger.debug('Conversation taken over', subscriber.assignedTo); return; } diff --git a/api/src/chat/services/conversation.service.ts b/api/src/chat/services/conversation.service.ts index 118f367f..5e8ce422 100644 --- a/api/src/chat/services/conversation.service.ts +++ b/api/src/chat/services/conversation.service.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -149,17 +149,6 @@ export class ConversationService extends BaseService< lat: parseFloat(coordinates.lat.toString()), lon: parseFloat(coordinates.lon.toString()), }; - } else if (msgType === 'attachments') { - // @TODO : deprecated in favor of geolocation msgType - const attachments = event.getAttachments(); - // @ts-expect-error deprecated - if (attachments.length === 1 && attachments[0].type === 'location') { - // @ts-expect-error deprecated - const coord = attachments[0].payload.coordinates; - convo.context.user_location = { lat: 0, lon: 0 }; - convo.context.user_location.lat = parseFloat(coord.lat); - convo.context.user_location.lon = parseFloat(coord.long); - } } // Deal with load more in the case of a list display diff --git a/api/src/extensions/channels/web/base-web-channel.ts b/api/src/extensions/channels/web/base-web-channel.ts index 8f165677..851ce843 100644 --- a/api/src/extensions/channels/web/base-web-channel.ts +++ b/api/src/extensions/channels/web/base-web-channel.ts @@ -604,6 +604,11 @@ export default abstract class BaseWebChannelHandler< try { const { type, data } = req.body as Web.IncomingMessage; + if (!req.session?.web?.profile?.id) { + this.logger.debug('Web Channel Handler : No session'); + return null; + } + // Check if any file is provided if (type !== 'file' || !('file' in data) || !data.file) { this.logger.debug('Web Channel Handler : No files provided'); @@ -622,7 +627,7 @@ export default abstract class BaseWebChannelHandler< type: data.type, context: 'message_attachment', createdByRef: 'Subscriber', - createdBy: req.session.web.profile?.id, + createdBy: req.session?.web?.profile?.id, }); } catch (err) { this.logger.error( @@ -677,7 +682,7 @@ export default abstract class BaseWebChannelHandler< const file = await multerUpload; // Check if any file is provided - if (!req.file) { + if (!file) { this.logger.debug('Web Channel Handler : No files provided'); return null; } diff --git a/api/src/extensions/channels/web/wrapper.ts b/api/src/extensions/channels/web/wrapper.ts index 094ee5ae..e576c7d6 100644 --- a/api/src/extensions/channels/web/wrapper.ts +++ b/api/src/extensions/channels/web/wrapper.ts @@ -9,7 +9,6 @@ import { Attachment } from '@/attachment/schemas/attachment.schema'; import EventWrapper from '@/channel/lib/EventWrapper'; import { ChannelName } from '@/channel/types'; -import { AttachmentPayload } from '@/chat/schemas/types/attachment'; import { IncomingMessageType, PayloadType, @@ -296,17 +295,6 @@ export default class WebEventWrapper< } } - /** - * Return the list of recieved attachments - * - * @deprecated - * @returns Received attachments message - */ - getAttachments(): AttachmentPayload[] { - const message = this.getMessage() as any; - return 'attachment' in message ? [].concat(message.attachment) : []; - } - /** * Return the delivered messages ids * diff --git a/api/src/migration/migrations/1735836154221-v-2-2-0.migration.ts b/api/src/migration/migrations/1735836154221-v-2-2-0.migration.ts index a92ef24c..4c14bb40 100644 --- a/api/src/migration/migrations/1735836154221-v-2-2-0.migration.ts +++ b/api/src/migration/migrations/1735836154221-v-2-2-0.migration.ts @@ -38,11 +38,11 @@ const getAdminUser = async () => { const UserModel = mongoose.model(User.name, userSchema); const adminRole = await RoleModel.findOne({ name: 'admin' }); - const user = await UserModel.findOne({ roles: [adminRole._id] }).sort({ + const user = await UserModel.findOne({ roles: [adminRole!._id] }).sort({ createdAt: 'asc', }); - return user; + return user!; }; /** @@ -638,7 +638,7 @@ const migrateAndPopulateAttachmentMessages = async ({ if ('attachment_id' in msg.message.attachment.payload) { // Add extra attrs await attachmentService.updateOne( - msg.message.attachment.payload.attachment_id, + msg.message.attachment.payload.attachment_id as string, { createdByRef: msg.sender ? 'Subscriber' : 'User', createdBy: msg.sender ? msg.sender : adminUser.id, @@ -679,6 +679,8 @@ const migrateAndPopulateAttachmentMessages = async ({ if (attachment) { await updateAttachmentId(msg._id, attachment.id); + } else { + logger.warn(`Unable to store attachment for message ${msg._id}`); } } } else { diff --git a/api/src/utils/test/fixtures/attachment.ts b/api/src/utils/test/fixtures/attachment.ts index 2bef61c7..2bb0469e 100644 --- a/api/src/utils/test/fixtures/attachment.ts +++ b/api/src/utils/test/fixtures/attachment.ts @@ -24,7 +24,7 @@ export const attachmentFixtures: AttachmentCreateDto[] = [ }, context: 'content_attachment', createdByRef: 'User', - createdBy: null, + createdBy: '9'.repeat(24), }, { name: 'store2.jpg', @@ -38,7 +38,7 @@ export const attachmentFixtures: AttachmentCreateDto[] = [ }, context: 'content_attachment', createdByRef: 'User', - createdBy: null, + createdBy: '9'.repeat(24), }, ];