mirror of
https://github.com/hexastack/hexabot
synced 2025-04-10 15:55:55 +00:00
fix: leave support for url in attachment payload (case for external urls)
This commit is contained in:
parent
d7cb39f9f4
commit
f399416553
@ -98,7 +98,7 @@ export default abstract class EventWrapper<
|
||||
*
|
||||
* @returns The current instance of the channel handler.
|
||||
*/
|
||||
getHandler(): ChannelHandler {
|
||||
getHandler(): C {
|
||||
return this._handler;
|
||||
}
|
||||
|
||||
@ -189,6 +189,16 @@ export default abstract class EventWrapper<
|
||||
this._profile = profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-Process messageevent
|
||||
*
|
||||
* Child class can perform operations such as storing files as attachments.
|
||||
*/
|
||||
preprocess() {
|
||||
// Nothing ...
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns event recipient id
|
||||
*
|
||||
|
@ -21,6 +21,7 @@ import { NextFunction, Request, Response } from 'express';
|
||||
import { Attachment } from '@/attachment/schemas/attachment.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { SubscriberCreateDto } from '@/chat/dto/subscriber.dto';
|
||||
import { AttachmentRef } from '@/chat/schemas/types/attachment';
|
||||
import {
|
||||
StdOutgoingEnvelope,
|
||||
StdOutgoingMessage,
|
||||
@ -234,22 +235,32 @@ export default abstract class ChannelHandler<
|
||||
* @param attachment The attachment ID or object to generate a signed URL for.
|
||||
* @return A signed URL string for downloading the specified attachment.
|
||||
*/
|
||||
public async getPublicUrl(attachment: string | Attachment) {
|
||||
const resource =
|
||||
typeof attachment === 'string'
|
||||
? await this.attachmentService.findOne(attachment)
|
||||
: attachment;
|
||||
public async getPublicUrl(attachment: AttachmentRef | Attachment) {
|
||||
if ('id' in attachment) {
|
||||
if (!attachment.id) {
|
||||
throw new TypeError(
|
||||
'Attachment ID is empty, unable to generate public URL.',
|
||||
);
|
||||
}
|
||||
|
||||
if (!resource) {
|
||||
throw new NotFoundException('Unable to find attachment');
|
||||
const resource = await this.attachmentService.findOne(attachment.id);
|
||||
|
||||
if (!resource) {
|
||||
throw new NotFoundException('Unable to find attachment');
|
||||
}
|
||||
|
||||
const token = this.jwtService.sign({ ...resource }, this.jwtSignOptions);
|
||||
const [name, _suffix] = this.getName().split('-');
|
||||
return buildURL(
|
||||
config.apiBaseUrl,
|
||||
`/webhook/${name}/download/${resource.name}?t=${encodeURIComponent(token)}`,
|
||||
);
|
||||
} else if ('url' in attachment && attachment.url) {
|
||||
// In case the url is external
|
||||
return attachment.url;
|
||||
} else {
|
||||
throw new TypeError('Unable to resolve the attachment public URL.');
|
||||
}
|
||||
|
||||
const token = this.jwtService.sign({ ...resource }, this.jwtSignOptions);
|
||||
const [name, _suffix] = this.getName().split('-');
|
||||
return buildURL(
|
||||
config.apiBaseUrl,
|
||||
`/webhook/${name}/download/${resource.name}?t=${encodeURIComponent(token)}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,14 +78,14 @@ export const urlButtonsMessage: StdOutgoingButtonsMessage = {
|
||||
};
|
||||
|
||||
const attachment: Attachment = {
|
||||
id: '1',
|
||||
id: '1'.repeat(24),
|
||||
name: 'attachment.jpg',
|
||||
type: 'image/jpeg',
|
||||
size: 3539,
|
||||
location: '39991e51-55c6-4a26-9176-b6ba04f180dc.jpg',
|
||||
channel: {
|
||||
['dimelo']: {
|
||||
id: 'attachment-id-dimelo',
|
||||
['any-channel']: {
|
||||
id: 'any-channel-attachment-id',
|
||||
},
|
||||
},
|
||||
createdAt: new Date(),
|
||||
|
@ -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.
|
||||
@ -111,6 +111,16 @@ export class SubscriberCreateDto {
|
||||
@IsNotEmpty()
|
||||
@IsChannelData()
|
||||
channel: SubscriberChannelData<ChannelName>;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Subscriber Avatar',
|
||||
type: String,
|
||||
default: null,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@IsObjectId({ message: 'Avatar Attachment ID must be a valid ObjectId' })
|
||||
avatar?: string | null = null;
|
||||
}
|
||||
|
||||
export class SubscriberUpdateDto extends PartialType(SubscriberCreateDto) {}
|
||||
|
@ -14,13 +14,24 @@ export enum FileType {
|
||||
unknown = 'unknown',
|
||||
}
|
||||
|
||||
export type AttachmentForeignKey = {
|
||||
id: string | null;
|
||||
/** @deprecated use "id" instead */
|
||||
url?: string;
|
||||
};
|
||||
/**
|
||||
* The `AttachmentRef` type defines two possible ways to reference an attachment:
|
||||
* 1. By `id`: This is used when the attachment is uploaded and stored in the Hexabot system.
|
||||
* The `id` field represents the unique identifier of the uploaded attachment in the system.
|
||||
* 2. By `url`: This is used when the attachment is externally hosted, especially when
|
||||
* the content is generated or retrieved by a plugin that consumes a third-party API.
|
||||
* In this case, the `url` field contains the direct link to the external resource.
|
||||
*/
|
||||
export type AttachmentRef =
|
||||
| {
|
||||
id: string | null;
|
||||
}
|
||||
| {
|
||||
/** To be used only for external URLs (plugins), for attachments use "id" instead */
|
||||
url: string;
|
||||
};
|
||||
|
||||
export interface AttachmentPayload {
|
||||
type: FileType;
|
||||
payload: AttachmentForeignKey;
|
||||
payload: AttachmentRef;
|
||||
}
|
||||
|
@ -411,7 +411,7 @@ export class BlockService extends BaseService<Block, BlockPopulate, BlockFull> {
|
||||
'url' in block.message.attachment.payload
|
||||
) {
|
||||
this.logger.error(
|
||||
'Attachment Model : `url` payload has been deprecated in favor of `id`',
|
||||
'Attachment Block : `url` payload has been deprecated in favor of `id`',
|
||||
block.id,
|
||||
block.message,
|
||||
);
|
||||
@ -521,9 +521,11 @@ export class BlockService extends BaseService<Block, BlockPopulate, BlockFull> {
|
||||
}
|
||||
} else if (blockMessage && 'attachment' in blockMessage) {
|
||||
const attachmentPayload = blockMessage.attachment.payload;
|
||||
if (!attachmentPayload.id) {
|
||||
if (!('id' in attachmentPayload)) {
|
||||
this.checkDeprecatedAttachmentUrl(block);
|
||||
throw new Error('Remote attachments are no longer supported!');
|
||||
throw new Error(
|
||||
'Remote attachments in blocks are no longer supported!',
|
||||
);
|
||||
}
|
||||
|
||||
const envelope: StdOutgoingEnvelope = {
|
||||
|
@ -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.
|
||||
@ -256,6 +256,8 @@ export class ChatService {
|
||||
|
||||
event.setSender(subscriber);
|
||||
|
||||
await event.preprocess();
|
||||
|
||||
// Trigger message received event
|
||||
this.eventEmitter.emit('hook:chatbot:received', event);
|
||||
|
||||
|
@ -22,7 +22,7 @@ import { MessageCreateDto } from '@/chat/dto/message.dto';
|
||||
import { SubscriberCreateDto } from '@/chat/dto/subscriber.dto';
|
||||
import { VIEW_MORE_PAYLOAD } from '@/chat/helpers/constants';
|
||||
import { Subscriber, SubscriberFull } from '@/chat/schemas/subscriber.schema';
|
||||
import { AttachmentForeignKey } from '@/chat/schemas/types/attachment';
|
||||
import { AttachmentRef } from '@/chat/schemas/types/attachment';
|
||||
import { Button, ButtonType } from '@/chat/schemas/types/button';
|
||||
import {
|
||||
AnyMessage,
|
||||
@ -155,7 +155,7 @@ export default abstract class BaseWebChannelHandler<
|
||||
type: Web.IncomingMessageType.file,
|
||||
data: {
|
||||
type: attachmentPayload.type,
|
||||
url: await this.getPublicUrl(attachmentPayload.payload.id),
|
||||
url: await this.getPublicUrl(attachmentPayload.payload),
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -994,7 +994,7 @@ export default abstract class BaseWebChannelHandler<
|
||||
type: Web.OutgoingMessageType.file,
|
||||
data: {
|
||||
type: message.attachment.type,
|
||||
url: await this.getPublicUrl(message.attachment.payload.id),
|
||||
url: await this.getPublicUrl(message.attachment.payload),
|
||||
},
|
||||
};
|
||||
if (message.quickReplies && message.quickReplies.length > 0) {
|
||||
@ -1034,11 +1034,11 @@ export default abstract class BaseWebChannelHandler<
|
||||
}
|
||||
|
||||
if (fields.image_url && item[fields.image_url]) {
|
||||
const attachmentPayload = item[fields.image_url]
|
||||
.payload as AttachmentForeignKey;
|
||||
if (attachmentPayload.id) {
|
||||
element.image_url = await this.getPublicUrl(attachmentPayload.id);
|
||||
}
|
||||
const attachmentRef =
|
||||
typeof item[fields.image_url] === 'string'
|
||||
? { url: item[fields.image_url] }
|
||||
: (item[fields.image_url].payload as AttachmentRef);
|
||||
element.image_url = await this.getPublicUrl(attachmentRef);
|
||||
}
|
||||
|
||||
buttons.forEach((button: Button, index) => {
|
||||
|
Loading…
Reference in New Issue
Block a user