fix: channels data type inference

This commit is contained in:
abdou6666 2024-12-09 18:17:28 +01:00
parent 62e59069dd
commit 3c7abc2261
8 changed files with 77 additions and 21 deletions

View File

@ -41,6 +41,7 @@ import {
MessagePopulate,
MessageStub,
} from '../schemas/message.schema';
import { Subscriber } from '../schemas/subscriber.schema';
import {
AnyMessage,
OutgoingMessage,
@ -137,7 +138,9 @@ export class MessageController extends BaseController<
);
}
if (!this.channelService.findChannel(subscriber?.channel.name)) {
const channelData = Subscriber.getChannelData(subscriber);
if (!this.channelService.findChannel(channelData.name)) {
throw new BadRequestException(`Subscriber channel not found`);
}
@ -146,7 +149,7 @@ export class MessageController extends BaseController<
message: messageDto.message as StdOutgoingTextMessage,
};
const channelHandler = this.channelService.getChannelHandler(
subscriber.channel.name,
channelData.name,
);
const event = new GenericEventWrapper(channelHandler, {
senderId: subscriber.foreign_id,

View File

@ -9,16 +9,17 @@
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
import {
IsArray,
IsDate,
IsNotEmpty,
IsNumber,
IsString,
IsOptional,
IsDate,
IsString,
} from 'class-validator';
import { ChannelName } from '@/channel/types';
import { IsObjectId } from '@/utils/validation-rules/is-object-id';
import { ChannelData } from '../schemas/types/channel';
import { SubscriberChannel } from '../schemas/types/channel';
import { IsChannelData } from '../validation-rules/is-channel-data';
export class SubscriberCreateDto {
@ -85,7 +86,7 @@ export class SubscriberCreateDto {
})
@IsOptional()
@IsDate()
assignedAt: Date | null;
assignedAt?: Date | null;
@ApiPropertyOptional({
description: 'Subscriber last visit',
@ -93,7 +94,7 @@ export class SubscriberCreateDto {
})
@IsOptional()
@IsDate()
lastvisit: Date;
lastvisit?: Date;
@ApiPropertyOptional({
description: 'Subscriber retained from',
@ -101,7 +102,7 @@ export class SubscriberCreateDto {
})
@IsOptional()
@IsDate()
retainedFrom: Date;
retainedFrom?: Date;
@ApiProperty({
description: 'Subscriber channel',
@ -109,7 +110,7 @@ export class SubscriberCreateDto {
})
@IsNotEmpty()
@IsChannelData()
channel: ChannelData;
channel: SubscriberChannel<ChannelName>;
}
export class SubscriberUpdateDto extends PartialType(SubscriberCreateDto) {}

13
api/src/chat/index.d.ts vendored Normal file
View File

@ -0,0 +1,13 @@
/*
* Copyright © 2024 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.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/
import { ChannelName } from '@/channel/types';
declare global {
interface SubscriberChannelDict extends Record<ChannelName | string, any> {}
}

View File

@ -11,6 +11,7 @@ import { Transform, Type } from 'class-transformer';
import { Schema as MongooseSchema } from 'mongoose';
import { Attachment } from '@/attachment/schemas/attachment.schema';
import { ChannelName } from '@/channel/types';
import { User } from '@/user/schemas/user.schema';
import { BaseSchema } from '@/utils/generics/base-schema';
import { LifecycleHookManager } from '@/utils/generics/lifecycle-hook-manager';
@ -20,7 +21,7 @@ import {
} from '@/utils/types/filter.types';
import { Label } from './label.schema';
import { ChannelData } from './types/channel';
import { SubscriberChannel } from './types/channel';
import { SubscriberContext } from './types/subscriberContext';
@Schema({ timestamps: true })
@ -102,7 +103,7 @@ export class SubscriberStub extends BaseSchema {
@Prop({
type: Object,
})
channel: ChannelData;
channel: SubscriberChannel;
@Prop({
type: MongooseSchema.Types.ObjectId,
@ -116,6 +117,13 @@ export class SubscriberStub extends BaseSchema {
default: { vars: {} },
})
context?: SubscriberContext;
static getChannelData<
C extends ChannelName,
S extends SubscriberStub = Subscriber,
>(subscriber: S) {
return subscriber.channel as unknown as SubscriberChannel<C>;
}
}
@Schema({ timestamps: true })

View File

@ -8,10 +8,13 @@
import { ChannelName } from '@/channel/types';
interface BaseChannelData {
name: ChannelName; // channel name
isSocket?: boolean;
type?: any; //TODO: type has to be checked
}
export type ChannelData = BaseChannelData;
export type SubscriberChannel<
C extends ChannelName = null,
K extends keyof SubscriberChannelDict[C] = keyof SubscriberChannelDict[C],
> = C extends null
? { name: ChannelName }
: {
[P in keyof SubscriberChannelDict[C]]: SubscriberChannelDict[C][K];
} & {
name: C;
};

View File

@ -12,6 +12,11 @@ import CONSOLE_CHANNEL_SETTINGS, {
declare global {
interface Settings extends SettingTree<typeof CONSOLE_CHANNEL_SETTINGS> {}
interface SubscriberChannelDict {
[CONSOLE_CHANNEL_NAME]: {
name: typeof CONSOLE_CHANNEL_NAME;
};
}
}
declare module '@nestjs/event-emitter' {

View File

@ -59,7 +59,7 @@ import { SocketRequest } from '@/websocket/utils/socket-request';
import { SocketResponse } from '@/websocket/utils/socket-response';
import { WebsocketGateway } from '@/websocket/websocket.gateway';
import { WEB_CHANNEL_NAMESPACE } from './settings';
import { WEB_CHANNEL_NAME, WEB_CHANNEL_NAMESPACE } from './settings';
import { Web } from './types';
import WebEventWrapper from './wrapper';
@ -1185,7 +1185,9 @@ export default abstract class BaseWebChannelHandler<
type: StdEventType,
content: any,
): void {
if (subscriber.channel.isSocket) {
const channelData =
Subscriber.getChannelData<typeof WEB_CHANNEL_NAME>(subscriber);
if (channelData.isSocket) {
this.websocketGateway.broadcast(subscriber, type, content);
} else {
// Do nothing, messages will be retrieved via polling
@ -1278,6 +1280,17 @@ export default abstract class BaseWebChannelHandler<
* @returns The web's response, otherwise an error
*/
async getUserData(event: WebEventWrapper): Promise<SubscriberCreateDto> {
return event.getSender() as SubscriberCreateDto;
const sender = event.getSender();
const {
id: _id,
createdAt: _createdAt,
updatedAt: _updatedAt,
...rest
} = sender;
const subscriber: SubscriberCreateDto = {
...rest,
channel: Subscriber.getChannelData(sender),
};
return subscriber;
}
}

View File

@ -7,11 +7,21 @@
*/
import DEFAULT_WEB_CHANNEL_SETTINGS, {
WEB_CHANNEL_NAME,
WEB_CHANNEL_NAMESPACE,
} from './settings';
declare global {
interface Settings extends SettingTree<typeof DEFAULT_WEB_CHANNEL_SETTINGS> {}
interface SubscriberChannelDict {
[WEB_CHANNEL_NAME]: {
name: typeof WEB_CHANNEL_NAME;
isSocket: boolean;
ipAddress: string;
agent: string;
};
}
}
declare module '@nestjs/event-emitter' {