mirror of
https://github.com/hexastack/hexabot
synced 2025-06-26 18:27:28 +00:00
fix: resolve file conflicts
This commit is contained in:
@@ -161,7 +161,6 @@ export class ChannelService {
|
||||
foreign_id: req.session.passport.user.id,
|
||||
},
|
||||
{
|
||||
id: req.session.passport.user.id,
|
||||
foreign_id: req.session.passport.user.id,
|
||||
first_name: req.session.passport.user.first_name || 'Anonymous',
|
||||
last_name: req.session.passport.user.last_name || 'Anonymous',
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
import { IsObjectId } from '@/utils/validation-rules/is-object-id';
|
||||
|
||||
import { CaptureVar } from '../schemas/types/capture-var';
|
||||
@@ -146,3 +147,7 @@ export class BlockUpdateDto extends PartialType(
|
||||
@IsOptional()
|
||||
trigger_channels?: string[];
|
||||
}
|
||||
|
||||
export type BlockDto = DtoConfig<{
|
||||
create: BlockCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -8,14 +8,16 @@
|
||||
|
||||
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsOptional,
|
||||
IsString,
|
||||
IsNumber,
|
||||
IsArray,
|
||||
} from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
|
||||
export class CategoryCreateDto {
|
||||
@ApiProperty({ description: 'Category label', type: String })
|
||||
@IsNotEmpty()
|
||||
@@ -39,3 +41,7 @@ export class CategoryCreateDto {
|
||||
}
|
||||
|
||||
export class CategoryUpdateDto extends PartialType(CategoryCreateDto) {}
|
||||
|
||||
export type CategoryDto = DtoConfig<{
|
||||
create: CategoryCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
import { ApiProperty, PartialType } from '@nestjs/swagger';
|
||||
import { IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
|
||||
export class ContextVarCreateDto {
|
||||
@ApiProperty({ description: 'Context var label', type: String })
|
||||
@IsNotEmpty()
|
||||
@@ -27,3 +29,7 @@ export class ContextVarCreateDto {
|
||||
}
|
||||
|
||||
export class ContextVarUpdateDto extends PartialType(ContextVarCreateDto) {}
|
||||
|
||||
export type ContextVarDto = DtoConfig<{
|
||||
create: ContextVarCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
import { IsObjectId } from '@/utils/validation-rules/is-object-id';
|
||||
|
||||
import { Context } from './../schemas/types/context';
|
||||
@@ -45,7 +46,7 @@ export class ConversationCreateDto {
|
||||
@IsObjectId({
|
||||
message: 'Current must be a valid objectId',
|
||||
})
|
||||
current: string;
|
||||
current?: string | null;
|
||||
|
||||
@ApiProperty({ description: 'next conversation', type: Array })
|
||||
@IsOptional()
|
||||
@@ -54,5 +55,9 @@ export class ConversationCreateDto {
|
||||
each: true,
|
||||
message: 'next must be a valid objectId',
|
||||
})
|
||||
next: string[];
|
||||
next?: string[];
|
||||
}
|
||||
|
||||
export type ConversationDto = DtoConfig<{
|
||||
create: ConversationCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -9,12 +9,14 @@
|
||||
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||
import {
|
||||
IsNotEmpty,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
Matches,
|
||||
IsObject,
|
||||
} from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
|
||||
export class LabelCreateDto {
|
||||
@ApiProperty({ description: 'Label title', type: String })
|
||||
@IsNotEmpty()
|
||||
@@ -39,3 +41,7 @@ export class LabelCreateDto {
|
||||
}
|
||||
|
||||
export class LabelUpdateDto extends PartialType(LabelCreateDto) {}
|
||||
|
||||
export type LabelDto = DtoConfig<{
|
||||
create: LabelCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
} from 'class-validator';
|
||||
|
||||
import { ChannelName } from '@/channel/types';
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
import { IsObjectId } from '@/utils/validation-rules/is-object-id';
|
||||
|
||||
import { SubscriberChannelData } from '../schemas/types/channel';
|
||||
@@ -36,7 +37,7 @@ export class SubscriberCreateDto {
|
||||
@ApiPropertyOptional({ description: 'Subscriber locale', type: String })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
locale: string;
|
||||
locale?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Subscriber timezone', type: Number })
|
||||
@IsOptional()
|
||||
@@ -51,17 +52,17 @@ export class SubscriberCreateDto {
|
||||
@ApiPropertyOptional({ description: 'Subscriber gender', type: String })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
gender: string;
|
||||
gender?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Subscriber country', type: String })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
country: string;
|
||||
country?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'Subscriber foreign id', type: String })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
foreign_id: string;
|
||||
foreign_id?: string;
|
||||
|
||||
@ApiProperty({ description: 'Subscriber labels', type: Array })
|
||||
@IsNotEmpty()
|
||||
@@ -114,3 +115,7 @@ export class SubscriberCreateDto {
|
||||
}
|
||||
|
||||
export class SubscriberUpdateDto extends PartialType(SubscriberCreateDto) {}
|
||||
|
||||
export type SubscriberDto = DtoConfig<{
|
||||
create: SubscriberCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -22,7 +22,7 @@ import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { BlockCreateDto, BlockUpdateDto } from '../dto/block.dto';
|
||||
import { BlockCreateDto, BlockDto, BlockUpdateDto } from '../dto/block.dto';
|
||||
import {
|
||||
Block,
|
||||
BLOCK_POPULATE,
|
||||
@@ -34,7 +34,8 @@ import {
|
||||
export class BlockRepository extends BaseRepository<
|
||||
Block,
|
||||
BlockPopulate,
|
||||
BlockFull
|
||||
BlockFull,
|
||||
BlockDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -14,11 +14,17 @@ import { Document, Model, Query } from 'mongoose';
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { CategoryDto } from '../dto/category.dto';
|
||||
import { Category } from '../schemas/category.schema';
|
||||
import { BlockService } from '../services/block.service';
|
||||
|
||||
@Injectable()
|
||||
export class CategoryRepository extends BaseRepository<Category> {
|
||||
export class CategoryRepository extends BaseRepository<
|
||||
Category,
|
||||
never,
|
||||
never,
|
||||
CategoryDto
|
||||
> {
|
||||
private readonly blockService: BlockService;
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -19,11 +19,17 @@ import { Document, Model, Query } from 'mongoose';
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { ContextVarDto } from '../dto/context-var.dto';
|
||||
import { ContextVar } from '../schemas/context-var.schema';
|
||||
import { BlockService } from '../services/block.service';
|
||||
|
||||
@Injectable()
|
||||
export class ContextVarRepository extends BaseRepository<ContextVar> {
|
||||
export class ContextVarRepository extends BaseRepository<
|
||||
ContextVar,
|
||||
never,
|
||||
never,
|
||||
ContextVarDto
|
||||
> {
|
||||
private readonly blockService: BlockService;
|
||||
|
||||
constructor(
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Model } from 'mongoose';
|
||||
|
||||
import { BaseRepository } from '@/utils/generics/base-repository';
|
||||
|
||||
import { ConversationDto } from '../dto/conversation.dto';
|
||||
import {
|
||||
Conversation,
|
||||
CONVERSATION_POPULATE,
|
||||
@@ -24,7 +25,8 @@ import {
|
||||
export class ConversationRepository extends BaseRepository<
|
||||
Conversation,
|
||||
ConversationPopulate,
|
||||
ConversationFull
|
||||
ConversationFull,
|
||||
ConversationDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Document, Model, Query } from 'mongoose';
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { LabelDto } from '../dto/label.dto';
|
||||
import {
|
||||
Label,
|
||||
LABEL_POPULATE,
|
||||
@@ -26,7 +27,8 @@ import {
|
||||
export class LabelRepository extends BaseRepository<
|
||||
Label,
|
||||
LabelPopulate,
|
||||
LabelFull
|
||||
LabelFull,
|
||||
LabelDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
import { BaseRepository } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { SubscriberUpdateDto } from '../dto/subscriber.dto';
|
||||
import { SubscriberDto, SubscriberUpdateDto } from '../dto/subscriber.dto';
|
||||
import {
|
||||
Subscriber,
|
||||
SUBSCRIBER_POPULATE,
|
||||
@@ -33,7 +33,8 @@ import {
|
||||
export class SubscriberRepository extends BaseRepository<
|
||||
Subscriber,
|
||||
SubscriberPopulate,
|
||||
SubscriberFull
|
||||
SubscriberFull,
|
||||
SubscriberDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -43,7 +43,7 @@ export class BlockStub extends BaseSchema {
|
||||
validate: isPatternList,
|
||||
default: [],
|
||||
})
|
||||
patterns?: Pattern[];
|
||||
patterns: Pattern[];
|
||||
|
||||
@Prop([
|
||||
{
|
||||
@@ -52,7 +52,7 @@ export class BlockStub extends BaseSchema {
|
||||
default: [],
|
||||
},
|
||||
])
|
||||
trigger_labels?: unknown;
|
||||
trigger_labels: unknown;
|
||||
|
||||
@Prop([
|
||||
{
|
||||
@@ -61,19 +61,19 @@ export class BlockStub extends BaseSchema {
|
||||
default: [],
|
||||
},
|
||||
])
|
||||
assign_labels?: unknown;
|
||||
assign_labels: unknown;
|
||||
|
||||
@Prop({
|
||||
type: Object,
|
||||
default: [],
|
||||
})
|
||||
trigger_channels?: string[];
|
||||
trigger_channels: string[];
|
||||
|
||||
@Prop({
|
||||
type: Object,
|
||||
default: {},
|
||||
})
|
||||
options?: BlockOptions;
|
||||
options: BlockOptions;
|
||||
|
||||
@Prop({
|
||||
type: Object,
|
||||
@@ -88,13 +88,13 @@ export class BlockStub extends BaseSchema {
|
||||
default: [],
|
||||
},
|
||||
])
|
||||
nextBlocks?: unknown;
|
||||
nextBlocks: unknown;
|
||||
|
||||
@Prop({
|
||||
type: MongooseSchema.Types.ObjectId,
|
||||
ref: 'Block',
|
||||
})
|
||||
attachedBlock?: unknown;
|
||||
attachedBlock: unknown;
|
||||
|
||||
@Prop({
|
||||
type: MongooseSchema.Types.ObjectId,
|
||||
@@ -106,14 +106,14 @@ export class BlockStub extends BaseSchema {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
})
|
||||
starts_conversation?: boolean;
|
||||
starts_conversation: boolean;
|
||||
|
||||
@Prop({
|
||||
type: Object,
|
||||
validate: isValidVarCapture,
|
||||
default: [],
|
||||
})
|
||||
capture_vars?: CaptureVar[];
|
||||
capture_vars: CaptureVar[];
|
||||
|
||||
@Prop({
|
||||
type: Object,
|
||||
@@ -125,22 +125,22 @@ export class BlockStub extends BaseSchema {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
})
|
||||
builtin?: boolean;
|
||||
builtin: boolean;
|
||||
}
|
||||
|
||||
@Schema({ timestamps: true })
|
||||
export class Block extends BlockStub {
|
||||
@Transform(({ obj }) => obj.trigger_labels?.map((elem) => elem.toString()))
|
||||
trigger_labels?: string[];
|
||||
@Transform(({ obj }) => obj.trigger_labels.map((elem) => elem.toString()))
|
||||
trigger_labels: string[];
|
||||
|
||||
@Transform(({ obj }) => obj.assign_labels?.map((elem) => elem.toString()))
|
||||
assign_labels?: string[];
|
||||
@Transform(({ obj }) => obj.assign_labels.map((elem) => elem.toString()))
|
||||
assign_labels: string[];
|
||||
|
||||
@Transform(({ obj }) => obj.nextBlocks?.map((elem) => elem.toString()))
|
||||
nextBlocks?: string[];
|
||||
@Transform(({ obj }) => obj.nextBlocks.map((elem) => elem.toString()))
|
||||
nextBlocks: string[];
|
||||
|
||||
@Transform(({ obj }) => obj.attachedBlock?.toString() || null)
|
||||
attachedBlock?: string;
|
||||
attachedBlock: string;
|
||||
|
||||
@Transform(({ obj }) => obj.category.toString())
|
||||
category: string | null;
|
||||
@@ -164,13 +164,13 @@ export class BlockFull extends BlockStub {
|
||||
nextBlocks: Block[];
|
||||
|
||||
@Type(() => Block)
|
||||
attachedBlock?: Block;
|
||||
attachedBlock: Block;
|
||||
|
||||
@Type(() => Category)
|
||||
category: Category;
|
||||
|
||||
@Type(() => Block)
|
||||
previousBlocks: Block[];
|
||||
previousBlocks?: Block[];
|
||||
|
||||
@Type(() => Block)
|
||||
attachedToBlock?: Block;
|
||||
|
||||
@@ -25,19 +25,19 @@ export class Category extends BaseSchema {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
})
|
||||
builtin?: boolean;
|
||||
builtin: boolean;
|
||||
|
||||
@Prop({
|
||||
type: Number,
|
||||
default: 100,
|
||||
})
|
||||
zoom?: number;
|
||||
zoom: number;
|
||||
|
||||
@Prop({
|
||||
type: [Number, Number],
|
||||
default: [0, 0],
|
||||
})
|
||||
offset?: [number, number];
|
||||
offset: [number, number];
|
||||
}
|
||||
|
||||
export const CategoryModel: ModelDefinition = LifecycleHookManager.attach({
|
||||
|
||||
@@ -38,7 +38,7 @@ export class ContextVar extends BaseSchema {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
})
|
||||
permanent?: boolean;
|
||||
permanent: boolean;
|
||||
}
|
||||
|
||||
export const ContextVarModel: ModelDefinition = LifecycleHookManager.attach({
|
||||
|
||||
@@ -51,19 +51,19 @@ class ConversationStub extends BaseSchema {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
})
|
||||
active?: boolean;
|
||||
active: boolean;
|
||||
|
||||
@Prop({
|
||||
type: Object,
|
||||
default: getDefaultConversationContext(),
|
||||
})
|
||||
context?: Context;
|
||||
context: Context;
|
||||
|
||||
@Prop({
|
||||
type: MongooseSchema.Types.ObjectId,
|
||||
ref: 'Block',
|
||||
})
|
||||
current?: unknown;
|
||||
current: unknown;
|
||||
|
||||
@Prop([
|
||||
{
|
||||
@@ -72,7 +72,7 @@ class ConversationStub extends BaseSchema {
|
||||
default: [],
|
||||
},
|
||||
])
|
||||
next?: unknown;
|
||||
next: unknown;
|
||||
}
|
||||
|
||||
@Schema({ timestamps: true })
|
||||
@@ -80,11 +80,11 @@ export class Conversation extends ConversationStub {
|
||||
@Transform(({ obj }) => obj.sender.toString())
|
||||
sender: string;
|
||||
|
||||
@Transform(({ obj }) => obj.current.toString())
|
||||
current?: string;
|
||||
@Transform(({ obj }) => (obj.current ? obj.current.toString() : null))
|
||||
current: string | null;
|
||||
|
||||
@Transform(({ obj }) => obj.next.map((elem) => elem.toString()))
|
||||
next?: string[];
|
||||
next: string[];
|
||||
}
|
||||
|
||||
@Schema({ timestamps: true })
|
||||
|
||||
@@ -43,13 +43,13 @@ export class LabelStub extends BaseSchema {
|
||||
@Prop({
|
||||
type: String,
|
||||
})
|
||||
description?: string;
|
||||
description: string;
|
||||
|
||||
@Prop({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
})
|
||||
builtin?: boolean;
|
||||
builtin: boolean;
|
||||
}
|
||||
|
||||
@Schema({ timestamps: true })
|
||||
|
||||
@@ -10,11 +10,17 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseSeeder } from '@/utils/generics/base-seeder';
|
||||
|
||||
import { CategoryDto } from '../dto/category.dto';
|
||||
import { CategoryRepository } from '../repositories/category.repository';
|
||||
import { Category } from '../schemas/category.schema';
|
||||
|
||||
@Injectable()
|
||||
export class CategorySeeder extends BaseSeeder<Category> {
|
||||
export class CategorySeeder extends BaseSeeder<
|
||||
Category,
|
||||
never,
|
||||
never,
|
||||
CategoryDto
|
||||
> {
|
||||
constructor(private readonly categoryRepository: CategoryRepository) {
|
||||
super(categoryRepository);
|
||||
}
|
||||
|
||||
@@ -10,11 +10,17 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseSeeder } from '@/utils/generics/base-seeder';
|
||||
|
||||
import { ContextVarDto } from '../dto/context-var.dto';
|
||||
import { ContextVarRepository } from '../repositories/context-var.repository';
|
||||
import { ContextVar } from '../schemas/context-var.schema';
|
||||
|
||||
@Injectable()
|
||||
export class ContextVarSeeder extends BaseSeeder<ContextVar> {
|
||||
export class ContextVarSeeder extends BaseSeeder<
|
||||
ContextVar,
|
||||
never,
|
||||
never,
|
||||
ContextVarDto
|
||||
> {
|
||||
constructor(private readonly contextVarRepository: ContextVarRepository) {
|
||||
super(contextVarRepository);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import { SettingService } from '@/setting/services/setting.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
import { getRandom } from '@/utils/helpers/safeRandom';
|
||||
|
||||
import { BlockDto } from '../dto/block.dto';
|
||||
import { BlockRepository } from '../repositories/block.repository';
|
||||
import { Block, BlockFull, BlockPopulate } from '../schemas/block.schema';
|
||||
import { Context } from '../schemas/types/context';
|
||||
@@ -35,7 +36,12 @@ import { Payload, StdQuickReply } from '../schemas/types/quick-reply';
|
||||
import { SubscriberContext } from '../schemas/types/subscriberContext';
|
||||
|
||||
@Injectable()
|
||||
export class BlockService extends BaseService<Block, BlockPopulate, BlockFull> {
|
||||
export class BlockService extends BaseService<
|
||||
Block,
|
||||
BlockPopulate,
|
||||
BlockFull,
|
||||
BlockDto
|
||||
> {
|
||||
constructor(
|
||||
readonly repository: BlockRepository,
|
||||
private readonly contentService: ContentService,
|
||||
|
||||
@@ -10,11 +10,17 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { CategoryDto } from '../dto/category.dto';
|
||||
import { CategoryRepository } from '../repositories/category.repository';
|
||||
import { Category } from '../schemas/category.schema';
|
||||
|
||||
@Injectable()
|
||||
export class CategoryService extends BaseService<Category> {
|
||||
export class CategoryService extends BaseService<
|
||||
Category,
|
||||
never,
|
||||
never,
|
||||
CategoryDto
|
||||
> {
|
||||
constructor(readonly repository: CategoryRepository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@@ -10,12 +10,18 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { ContextVarDto } from '../dto/context-var.dto';
|
||||
import { ContextVarRepository } from '../repositories/context-var.repository';
|
||||
import { Block, BlockFull } from '../schemas/block.schema';
|
||||
import { ContextVar } from '../schemas/context-var.schema';
|
||||
|
||||
@Injectable()
|
||||
export class ContextVarService extends BaseService<ContextVar> {
|
||||
export class ContextVarService extends BaseService<
|
||||
ContextVar,
|
||||
never,
|
||||
never,
|
||||
ContextVarDto
|
||||
> {
|
||||
constructor(readonly repository: ContextVarRepository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import EventWrapper from '@/channel/lib/EventWrapper';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { ConversationDto } from '../dto/conversation.dto';
|
||||
import { VIEW_MORE_PAYLOAD } from '../helpers/constants';
|
||||
import { ConversationRepository } from '../repositories/conversation.repository';
|
||||
import { Block, BlockFull } from '../schemas/block.schema';
|
||||
@@ -30,7 +31,8 @@ import { SubscriberService } from './subscriber.service';
|
||||
export class ConversationService extends BaseService<
|
||||
Conversation,
|
||||
ConversationPopulate,
|
||||
ConversationFull
|
||||
ConversationFull,
|
||||
ConversationDto
|
||||
> {
|
||||
constructor(
|
||||
readonly repository: ConversationRepository,
|
||||
|
||||
@@ -10,11 +10,17 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { LabelDto } from '../dto/label.dto';
|
||||
import { LabelRepository } from '../repositories/label.repository';
|
||||
import { Label, LabelFull, LabelPopulate } from '../schemas/label.schema';
|
||||
|
||||
@Injectable()
|
||||
export class LabelService extends BaseService<Label, LabelPopulate, LabelFull> {
|
||||
export class LabelService extends BaseService<
|
||||
Label,
|
||||
LabelPopulate,
|
||||
LabelFull,
|
||||
LabelDto
|
||||
> {
|
||||
constructor(readonly repository: LabelRepository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import { SocketRequest } from '@/websocket/utils/socket-request';
|
||||
import { SocketResponse } from '@/websocket/utils/socket-response';
|
||||
import { WebsocketGateway } from '@/websocket/websocket.gateway';
|
||||
|
||||
import { SubscriberUpdateDto } from '../dto/subscriber.dto';
|
||||
import { SubscriberDto, SubscriberUpdateDto } from '../dto/subscriber.dto';
|
||||
import { SubscriberRepository } from '../repositories/subscriber.repository';
|
||||
import {
|
||||
Subscriber,
|
||||
@@ -40,7 +40,8 @@ import {
|
||||
export class SubscriberService extends BaseService<
|
||||
Subscriber,
|
||||
SubscriberPopulate,
|
||||
SubscriberFull
|
||||
SubscriberFull,
|
||||
SubscriberDto
|
||||
> {
|
||||
private readonly gateway: WebsocketGateway;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||
import { IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
import { IsObjectId } from '@/utils/validation-rules/is-object-id';
|
||||
|
||||
export class ContentCreateDto {
|
||||
@@ -34,3 +35,7 @@ export class ContentCreateDto {
|
||||
}
|
||||
|
||||
export class ContentUpdateDto extends PartialType(ContentCreateDto) {}
|
||||
|
||||
export type ContentDto = DtoConfig<{
|
||||
create: ContentCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -9,16 +9,18 @@
|
||||
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||
import { Type } from 'class-transformer';
|
||||
import {
|
||||
IsString,
|
||||
IsArray,
|
||||
ValidateNested,
|
||||
IsOptional,
|
||||
IsEnum,
|
||||
Matches,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
Matches,
|
||||
Validate,
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
|
||||
import { ValidateRequiredFields } from '../validators/validate-required-fields.validator';
|
||||
|
||||
export class FieldType {
|
||||
@@ -55,3 +57,7 @@ export class ContentTypeCreateDto {
|
||||
}
|
||||
|
||||
export class ContentTypeUpdateDto extends PartialType(ContentTypeCreateDto) {}
|
||||
|
||||
export type ContentTypeDto = DtoConfig<{
|
||||
create: ContentTypeCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
ValidateIf,
|
||||
} from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
import { IsObjectId } from '@/utils/validation-rules/is-object-id';
|
||||
|
||||
import { MenuType } from '../schemas/types/menu';
|
||||
@@ -53,3 +54,7 @@ export class MenuCreateDto {
|
||||
}
|
||||
|
||||
export class MenuQueryDto extends PartialType(MenuCreateDto) {}
|
||||
|
||||
export type MenuDto = DtoConfig<{
|
||||
create: MenuCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -15,11 +15,17 @@ import { BlockService } from '@/chat/services/block.service';
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { ContentTypeDto } from '../dto/contentType.dto';
|
||||
import { ContentType } from '../schemas/content-type.schema';
|
||||
import { Content } from '../schemas/content.schema';
|
||||
|
||||
@Injectable()
|
||||
export class ContentTypeRepository extends BaseRepository<ContentType> {
|
||||
export class ContentTypeRepository extends BaseRepository<
|
||||
ContentType,
|
||||
never,
|
||||
never,
|
||||
ContentTypeDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(ContentType.name) readonly model: Model<ContentType>,
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
import { BaseRepository } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { ContentDto } from '../dto/content.dto';
|
||||
import {
|
||||
Content,
|
||||
CONTENT_POPULATE,
|
||||
@@ -32,7 +33,8 @@ import {
|
||||
export class ContentRepository extends BaseRepository<
|
||||
Content,
|
||||
ContentPopulate,
|
||||
ContentFull
|
||||
ContentFull,
|
||||
ContentDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Model } from 'mongoose';
|
||||
|
||||
import { BaseRepository } from '@/utils/generics/base-repository';
|
||||
|
||||
import { MenuDto } from '../dto/menu.dto';
|
||||
import {
|
||||
Menu,
|
||||
MENU_POPULATE,
|
||||
@@ -26,7 +27,8 @@ import { MenuType } from '../schemas/types/menu';
|
||||
export class MenuRepository extends BaseRepository<
|
||||
Menu,
|
||||
MenuPopulate,
|
||||
MenuFull
|
||||
MenuFull,
|
||||
MenuDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* 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 { Prop, Schema, SchemaFactory, ModelDefinition } from '@nestjs/mongoose';
|
||||
import { ModelDefinition, Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
import { BaseSchema } from '@/utils/generics/base-schema';
|
||||
@@ -39,7 +39,7 @@ export class ContentType extends BaseSchema {
|
||||
},
|
||||
],
|
||||
})
|
||||
fields?: {
|
||||
fields: {
|
||||
name: string;
|
||||
label: string;
|
||||
type: string;
|
||||
|
||||
@@ -41,7 +41,7 @@ export class ContentStub extends BaseSchema {
|
||||
* Either of not this content is active.
|
||||
*/
|
||||
@Prop({ type: Boolean, default: true })
|
||||
status?: boolean;
|
||||
status: boolean;
|
||||
|
||||
@Prop({ type: mongoose.Schema.Types.Mixed })
|
||||
dynamicFields: Record<string, any>;
|
||||
|
||||
@@ -10,11 +10,17 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { ContentTypeDto } from '../dto/contentType.dto';
|
||||
import { ContentTypeRepository } from '../repositories/content-type.repository';
|
||||
import { ContentType } from '../schemas/content-type.schema';
|
||||
|
||||
@Injectable()
|
||||
export class ContentTypeService extends BaseService<ContentType> {
|
||||
export class ContentTypeService extends BaseService<
|
||||
ContentType,
|
||||
never,
|
||||
never,
|
||||
ContentTypeDto
|
||||
> {
|
||||
constructor(readonly repository: ContentTypeRepository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { ContentDto } from '../dto/content.dto';
|
||||
import { ContentRepository } from '../repositories/content.repository';
|
||||
import {
|
||||
Content,
|
||||
@@ -30,7 +31,8 @@ import {
|
||||
export class ContentService extends BaseService<
|
||||
Content,
|
||||
ContentPopulate,
|
||||
ContentFull
|
||||
ContentFull,
|
||||
ContentDto
|
||||
> {
|
||||
constructor(
|
||||
readonly repository: ContentRepository,
|
||||
|
||||
@@ -20,13 +20,18 @@ import { MENU_CACHE_KEY } from '@/utils/constants/cache';
|
||||
import { Cacheable } from '@/utils/decorators/cacheable.decorator';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { MenuCreateDto } from '../dto/menu.dto';
|
||||
import { MenuCreateDto, MenuDto } from '../dto/menu.dto';
|
||||
import { MenuRepository } from '../repositories/menu.repository';
|
||||
import { Menu, MenuFull, MenuPopulate } from '../schemas/menu.schema';
|
||||
import { AnyMenu, MenuTree, MenuType } from '../schemas/types/menu';
|
||||
|
||||
@Injectable()
|
||||
export class MenuService extends BaseService<Menu, MenuPopulate, MenuFull> {
|
||||
export class MenuService extends BaseService<
|
||||
Menu,
|
||||
MenuPopulate,
|
||||
MenuFull,
|
||||
MenuDto
|
||||
> {
|
||||
private RootSymbol: symbol = Symbol('RootMenu');
|
||||
|
||||
constructor(
|
||||
|
||||
218
api/src/helper/lib/__test__/base-nlp-helper.spec.ts
Normal file
218
api/src/helper/lib/__test__/base-nlp-helper.spec.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { ObjectId } from 'bson';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
NlpEntity,
|
||||
NlpEntityDocument,
|
||||
NlpEntityFull,
|
||||
} from '@/nlp/schemas/nlp-entity.schema';
|
||||
import { NlpSampleFull } from '@/nlp/schemas/nlp-sample.schema';
|
||||
import {
|
||||
NlpValue,
|
||||
NlpValueDocument,
|
||||
NlpValueFull,
|
||||
} from '@/nlp/schemas/nlp-value.schema';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
|
||||
import { HelperService } from '../../helper.service';
|
||||
import { HelperName } from '../../types';
|
||||
import BaseNlpHelper from '../base-nlp-helper';
|
||||
|
||||
// Mock services
|
||||
const mockLoggerService = {
|
||||
log: jest.fn(),
|
||||
error: jest.fn(),
|
||||
} as unknown as LoggerService;
|
||||
|
||||
const mockSettingService = {
|
||||
get: jest.fn(),
|
||||
} as unknown as SettingService;
|
||||
|
||||
const mockHelperService = {
|
||||
doSomething: jest.fn(),
|
||||
} as unknown as HelperService;
|
||||
|
||||
// Concrete implementation for testing
|
||||
class TestNlpHelper extends BaseNlpHelper {
|
||||
getPath(): string {
|
||||
return __dirname;
|
||||
}
|
||||
|
||||
predict(text: string): Promise<any> {
|
||||
return Promise.resolve({ text });
|
||||
}
|
||||
}
|
||||
|
||||
describe('BaseNlpHelper', () => {
|
||||
let helper: TestNlpHelper;
|
||||
|
||||
beforeEach(() => {
|
||||
helper = new TestNlpHelper(
|
||||
'test-helper' as HelperName,
|
||||
mockSettingService,
|
||||
mockHelperService,
|
||||
mockLoggerService,
|
||||
);
|
||||
});
|
||||
|
||||
describe('updateEntity', () => {
|
||||
it('should return the updated entity', async () => {
|
||||
const entity: NlpEntity = { name: 'test-entity' } as NlpEntity;
|
||||
const result = await helper.updateEntity(entity);
|
||||
expect(result).toBe(entity);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addEntity', () => {
|
||||
it('should return a new UUID', async () => {
|
||||
const result = await helper.addEntity({} as NlpEntityDocument);
|
||||
expect(result).toMatch(
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteEntity', () => {
|
||||
it('should return the deleted entity ID', async () => {
|
||||
const entityId = 'entity-id';
|
||||
const result = await helper.deleteEntity(entityId);
|
||||
expect(result).toBe(entityId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateValue', () => {
|
||||
it('should return the updated value', async () => {
|
||||
const value: NlpValue = { value: 'test-value' } as NlpValue;
|
||||
const result = await helper.updateValue(value);
|
||||
expect(result).toBe(value);
|
||||
});
|
||||
});
|
||||
|
||||
describe('addValue', () => {
|
||||
it('should return a new UUID', async () => {
|
||||
const result = await helper.addValue({} as NlpValueDocument);
|
||||
expect(result).toMatch(
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteValue', () => {
|
||||
it('should return the deleted value', async () => {
|
||||
const value: NlpValueFull = { value: 'test-value' } as NlpValueFull;
|
||||
const result = await helper.deleteValue(value);
|
||||
expect(result).toBe(value);
|
||||
});
|
||||
});
|
||||
|
||||
describe('format', () => {
|
||||
it('should format the samples and entities into NLP training data', async () => {
|
||||
const entities: NlpEntityFull[] = [
|
||||
{ _id: 'entity1', name: 'intent' },
|
||||
{ _id: 'entity2', name: 'test-entity' },
|
||||
] as unknown as NlpEntityFull[];
|
||||
|
||||
const samples: NlpSampleFull[] = [
|
||||
{
|
||||
text: 'test-text',
|
||||
entities: [
|
||||
{ entity: 'entity1', value: 'intent1' },
|
||||
{ entity: 'entity2', value: 'value2', start: 0, end: 4 },
|
||||
],
|
||||
language: { code: 'en' },
|
||||
},
|
||||
] as unknown as NlpSampleFull[];
|
||||
|
||||
jest.spyOn(NlpEntity, 'getEntityMap').mockReturnValue({
|
||||
entity1: {
|
||||
id: new ObjectId().toString(),
|
||||
name: 'intent',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
builtin: false,
|
||||
lookups: [],
|
||||
},
|
||||
entity2: {
|
||||
id: new ObjectId().toString(),
|
||||
name: 'test-entity',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
builtin: false,
|
||||
lookups: [],
|
||||
},
|
||||
});
|
||||
jest.spyOn(NlpValue, 'getValueMap').mockReturnValue({
|
||||
intent1: {
|
||||
id: new ObjectId().toString(),
|
||||
value: 'test-intent',
|
||||
entity: 'entity1', // Add the required entity field
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
builtin: false,
|
||||
expressions: [],
|
||||
metadata: [],
|
||||
},
|
||||
value2: {
|
||||
id: new ObjectId().toString(),
|
||||
value: 'test-value',
|
||||
entity: 'entity2', // Add the required entity field
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
builtin: false,
|
||||
expressions: [],
|
||||
metadata: [],
|
||||
},
|
||||
});
|
||||
|
||||
const result = await helper.format(samples, entities);
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
text: 'test-text',
|
||||
intent: 'test-intent',
|
||||
entities: [
|
||||
{ entity: 'test-entity', value: 'test-value', start: 0, end: 4 },
|
||||
{ entity: 'language', value: 'en' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should throw an error if intent entity is missing', async () => {
|
||||
const entities: NlpEntityFull[] = [
|
||||
{ _id: 'entity2', name: 'test-entity' },
|
||||
] as unknown as NlpEntityFull[];
|
||||
|
||||
const samples: NlpSampleFull[] = [
|
||||
{
|
||||
text: 'test-text',
|
||||
entities: [{ entity: 'entity2', value: 'value2' }],
|
||||
language: { code: 'en' },
|
||||
},
|
||||
] as unknown as NlpSampleFull[];
|
||||
|
||||
jest.spyOn(NlpEntity, 'getEntityMap').mockReturnValue({
|
||||
entity2: {
|
||||
id: new ObjectId().toString(),
|
||||
name: 'test-entity',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
builtin: false,
|
||||
lookups: [],
|
||||
},
|
||||
});
|
||||
|
||||
await expect(helper.format(samples, entities)).rejects.toThrow(
|
||||
'Unable to find the `intent` nlp entity.',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
23
api/src/helper/lib/__test__/settings.ts
Normal file
23
api/src/helper/lib/__test__/settings.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { HelperSetting } from '@/helper/types';
|
||||
import { SettingType } from '@/setting/schemas/types';
|
||||
|
||||
export const TEST_HELPER_NAME = 'test-helper';
|
||||
|
||||
export const TEST_HELPER_NAMESPACE = 'test_helper';
|
||||
|
||||
export default [
|
||||
{
|
||||
group: TEST_HELPER_NAMESPACE,
|
||||
label: 'test',
|
||||
value: 'test',
|
||||
type: SettingType.text,
|
||||
},
|
||||
] as const satisfies HelperSetting<typeof TEST_HELPER_NAME>[];
|
||||
@@ -112,14 +112,57 @@ export default abstract class BaseNlpHelper<
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns training dataset in NLP provider compatible format
|
||||
* Returns training dataset in NLP provider compatible format.
|
||||
* Can be overridden in child classes for custom formatting logic.
|
||||
*
|
||||
* @param samples - Sample to train
|
||||
* @param entities - All available entities
|
||||
*
|
||||
* @returns The formatted NLP training set
|
||||
*/
|
||||
format?(samples: NlpSampleFull[], entities: NlpEntityFull[]): unknown;
|
||||
async format(samples: NlpSampleFull[], entities: NlpEntityFull[]) {
|
||||
const entityMap = NlpEntity.getEntityMap(entities);
|
||||
const valueMap = NlpValue.getValueMap(
|
||||
NlpValue.getValuesFromEntities(entities),
|
||||
);
|
||||
const examples = samples
|
||||
.filter((s) => s.entities.length > 0)
|
||||
.map((s) => {
|
||||
const intent = s.entities.find(
|
||||
(e) => entityMap[e.entity].name === 'intent',
|
||||
);
|
||||
if (!intent) {
|
||||
throw new Error('Unable to find the `intent` nlp entity.');
|
||||
}
|
||||
const sampleEntities = s.entities
|
||||
.filter((e) => entityMap[<string>e.entity].name !== 'intent')
|
||||
.map((e) => {
|
||||
const res = {
|
||||
entity: entityMap[<string>e.entity].name,
|
||||
value: valueMap[<string>e.value].value,
|
||||
};
|
||||
if ('start' in e && 'end' in e) {
|
||||
Object.assign(res, {
|
||||
start: e.start,
|
||||
end: e.end,
|
||||
});
|
||||
}
|
||||
return res;
|
||||
})
|
||||
.concat({
|
||||
entity: 'language',
|
||||
value: s.language!.code,
|
||||
});
|
||||
|
||||
return {
|
||||
text: s.text,
|
||||
intent: valueMap[intent.value].value,
|
||||
entities: sampleEntities,
|
||||
};
|
||||
});
|
||||
|
||||
return examples;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform training request
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
*/
|
||||
|
||||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import { IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
|
||||
export class LanguageCreateDto {
|
||||
@ApiProperty({ description: 'Language Title', type: String })
|
||||
@IsNotEmpty()
|
||||
@@ -25,10 +27,14 @@ export class LanguageCreateDto {
|
||||
@IsBoolean()
|
||||
isRTL: boolean;
|
||||
|
||||
@ApiProperty({ description: 'Is Default Language ?', type: Boolean })
|
||||
@ApiPropertyOptional({ description: 'Is Default Language ?', type: Boolean })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
isDefault?: boolean;
|
||||
}
|
||||
|
||||
export class LanguageUpdateDto extends PartialType(LanguageCreateDto) {}
|
||||
|
||||
export type LanguageDto = DtoConfig<{
|
||||
create: LanguageCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -14,10 +14,16 @@ import { Document, Model, Query } from 'mongoose';
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { LanguageDto } from '../dto/language.dto';
|
||||
import { Language } from '../schemas/language.schema';
|
||||
|
||||
@Injectable()
|
||||
export class LanguageRepository extends BaseRepository<Language> {
|
||||
export class LanguageRepository extends BaseRepository<
|
||||
Language,
|
||||
never,
|
||||
never,
|
||||
LanguageDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Language.name) readonly model: Model<Language>,
|
||||
|
||||
@@ -32,13 +32,13 @@ export class Language extends BaseSchema {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
})
|
||||
isDefault?: boolean;
|
||||
isDefault: boolean;
|
||||
|
||||
@Prop({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
})
|
||||
isRTL?: boolean;
|
||||
isRTL: boolean;
|
||||
}
|
||||
|
||||
export const LanguageModel: ModelDefinition = LifecycleHookManager.attach({
|
||||
|
||||
@@ -10,11 +10,17 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseSeeder } from '@/utils/generics/base-seeder';
|
||||
|
||||
import { LanguageDto } from '../dto/language.dto';
|
||||
import { LanguageRepository } from '../repositories/language.repository';
|
||||
import { Language } from '../schemas/language.schema';
|
||||
|
||||
@Injectable()
|
||||
export class LanguageSeeder extends BaseSeeder<Language> {
|
||||
export class LanguageSeeder extends BaseSeeder<
|
||||
Language,
|
||||
never,
|
||||
never,
|
||||
LanguageDto
|
||||
> {
|
||||
constructor(private readonly languageRepository: LanguageRepository) {
|
||||
super(languageRepository);
|
||||
}
|
||||
|
||||
@@ -11,9 +11,11 @@ import {
|
||||
Inject,
|
||||
Injectable,
|
||||
InternalServerErrorException,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { Cache } from 'cache-manager';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
DEFAULT_LANGUAGE_CACHE_KEY,
|
||||
LANGUAGES_CACHE_KEY,
|
||||
@@ -21,14 +23,21 @@ import {
|
||||
import { Cacheable } from '@/utils/decorators/cacheable.decorator';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { LanguageDto } from '../dto/language.dto';
|
||||
import { LanguageRepository } from '../repositories/language.repository';
|
||||
import { Language } from '../schemas/language.schema';
|
||||
|
||||
@Injectable()
|
||||
export class LanguageService extends BaseService<Language> {
|
||||
export class LanguageService extends BaseService<
|
||||
Language,
|
||||
never,
|
||||
never,
|
||||
LanguageDto
|
||||
> {
|
||||
constructor(
|
||||
readonly repository: LanguageRepository,
|
||||
@Inject(CACHE_MANAGER) private readonly cacheManager: Cache,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
super(repository);
|
||||
}
|
||||
@@ -72,6 +81,15 @@ export class LanguageService extends BaseService<Language> {
|
||||
* @returns A promise that resolves to the `Language` object.
|
||||
*/
|
||||
async getLanguageByCode(code: string) {
|
||||
return await this.findOne({ code });
|
||||
const language = await this.findOne({ code });
|
||||
|
||||
if (!language) {
|
||||
this.logger.warn(`Unable to Language by languageCode ${code}`);
|
||||
throw new NotFoundException(
|
||||
`Language with languageCode ${code} not found`,
|
||||
);
|
||||
}
|
||||
|
||||
return language;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +154,7 @@ describe('TranslationService', () => {
|
||||
},
|
||||
},
|
||||
options: {},
|
||||
attachedBlock: null,
|
||||
};
|
||||
|
||||
const mockedPlugin: any = {
|
||||
|
||||
@@ -111,6 +111,8 @@ describe('NlpEntityController', () => {
|
||||
values: nlpValueFixtures.filter(
|
||||
({ entity }) => parseInt(entity) === index,
|
||||
) as NlpEntityFull['values'],
|
||||
lookups: curr.lookups!,
|
||||
builtin: curr.builtin!,
|
||||
});
|
||||
return acc;
|
||||
},
|
||||
@@ -214,6 +216,8 @@ describe('NlpEntityController', () => {
|
||||
id: firstNameEntity!.id,
|
||||
createdAt: firstNameEntity!.createdAt,
|
||||
updatedAt: firstNameEntity!.updatedAt,
|
||||
lookups: firstNameEntity!.lookups,
|
||||
builtin: firstNameEntity!.builtin,
|
||||
};
|
||||
const result = await nlpEntityController.findOne(firstNameEntity!.id, [
|
||||
'values',
|
||||
|
||||
@@ -42,7 +42,7 @@ import { PopulatePipe } from '@/utils/pipes/populate.pipe';
|
||||
import { SearchFilterPipe } from '@/utils/pipes/search-filter.pipe';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { NlpSampleDto } from '../dto/nlp-sample.dto';
|
||||
import { NlpSampleDto, TNlpSampleDto } from '../dto/nlp-sample.dto';
|
||||
import {
|
||||
NlpSample,
|
||||
NlpSampleFull,
|
||||
@@ -60,7 +60,8 @@ export class NlpSampleController extends BaseController<
|
||||
NlpSample,
|
||||
NlpSampleStub,
|
||||
NlpSamplePopulate,
|
||||
NlpSampleFull
|
||||
NlpSampleFull,
|
||||
TNlpSampleDto
|
||||
> {
|
||||
constructor(
|
||||
private readonly nlpSampleService: NlpSampleService,
|
||||
@@ -91,7 +92,7 @@ export class NlpSampleController extends BaseController<
|
||||
);
|
||||
const entities = await this.nlpEntityService.findAllAndPopulate();
|
||||
const helper = await this.helperService.getDefaultNluHelper();
|
||||
const result = await helper.format?.(samples, entities);
|
||||
const result = await helper.format(samples, entities);
|
||||
|
||||
// Sending the JSON data as a file
|
||||
const buffer = Buffer.from(JSON.stringify(result));
|
||||
@@ -129,11 +130,6 @@ export class NlpSampleController extends BaseController<
|
||||
): Promise<NlpSampleFull> {
|
||||
const language = await this.languageService.getLanguageByCode(languageCode);
|
||||
|
||||
if (!language)
|
||||
throw new NotFoundException(
|
||||
`Language with code ${languageCode} not found`,
|
||||
);
|
||||
|
||||
const nlpSample = await this.nlpSampleService.create({
|
||||
...createNlpSampleDto,
|
||||
language: language.id,
|
||||
@@ -303,13 +299,6 @@ export class NlpSampleController extends BaseController<
|
||||
): Promise<NlpSampleFull> {
|
||||
const language = await this.languageService.getLanguageByCode(languageCode);
|
||||
|
||||
if (!language) {
|
||||
this.logger.warn(`Unable to Language by languageCode ${languageCode}`);
|
||||
throw new NotFoundException(
|
||||
`Language with languageCode ${languageCode} not found`,
|
||||
);
|
||||
}
|
||||
|
||||
const sample = await this.nlpSampleService.updateOne(id, {
|
||||
...sampleAttrs,
|
||||
language: language.id,
|
||||
|
||||
@@ -100,6 +100,9 @@ describe('NlpValueController', () => {
|
||||
entity: nlpEntityFixtures[
|
||||
parseInt(curr.entity)
|
||||
] as NlpValueFull['entity'],
|
||||
builtin: curr.builtin!,
|
||||
expressions: curr.expressions!,
|
||||
metadata: curr.metadata!,
|
||||
});
|
||||
return acc;
|
||||
},
|
||||
@@ -123,6 +126,9 @@ describe('NlpValueController', () => {
|
||||
const ValueWithEntities = {
|
||||
...curr,
|
||||
entity: nlpEntities[parseInt(curr.entity)].id,
|
||||
expressions: curr.expressions!,
|
||||
metadata: curr.metadata!,
|
||||
builtin: curr.builtin!,
|
||||
};
|
||||
acc.push(ValueWithEntities);
|
||||
return acc;
|
||||
|
||||
@@ -8,15 +8,17 @@
|
||||
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import {
|
||||
IsString,
|
||||
IsOptional,
|
||||
IsBoolean,
|
||||
IsArray,
|
||||
Matches,
|
||||
IsBoolean,
|
||||
IsIn,
|
||||
IsNotEmpty,
|
||||
IsOptional,
|
||||
IsString,
|
||||
Matches,
|
||||
} from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
|
||||
export type Lookup = 'keywords' | 'trait' | 'free-text';
|
||||
|
||||
export class NlpEntityCreateDto {
|
||||
@@ -46,3 +48,7 @@ export class NlpEntityCreateDto {
|
||||
@IsOptional()
|
||||
builtin?: boolean;
|
||||
}
|
||||
|
||||
export type NlpEntityDto = DtoConfig<{
|
||||
create: NlpEntityCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
import { IsObjectId } from '@/utils/validation-rules/is-object-id';
|
||||
|
||||
import { NlpSampleEntityValue, NlpSampleState } from '../schemas/types';
|
||||
@@ -40,7 +41,7 @@ export class NlpSampleCreateDto {
|
||||
@IsString()
|
||||
@IsIn(Object.values(NlpSampleState))
|
||||
@IsOptional()
|
||||
type?: NlpSampleState;
|
||||
type?: keyof typeof NlpSampleState;
|
||||
|
||||
@ApiProperty({ description: 'NLP sample language id', type: String })
|
||||
@IsString()
|
||||
@@ -63,3 +64,7 @@ export class NlpSampleDto extends NlpSampleCreateDto {
|
||||
}
|
||||
|
||||
export class NlpSampleUpdateDto extends PartialType(NlpSampleCreateDto) {}
|
||||
|
||||
export type TNlpSampleDto = DtoConfig<{
|
||||
create: NlpSampleCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -9,14 +9,15 @@
|
||||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
import {
|
||||
IsString,
|
||||
IsBoolean,
|
||||
IsArray,
|
||||
IsObject,
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
import { IsObjectId } from '@/utils/validation-rules/is-object-id';
|
||||
|
||||
export class NlpValueCreateDto {
|
||||
@@ -52,3 +53,7 @@ export class NlpValueCreateDto {
|
||||
}
|
||||
|
||||
export class NlpValueUpdateDto extends PartialType(NlpValueCreateDto) {}
|
||||
|
||||
export type NlpValueDto = DtoConfig<{
|
||||
create: NlpValueCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Document, Model, Query } from 'mongoose';
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { NlpEntityDto } from '../dto/nlp-entity.dto';
|
||||
import {
|
||||
NLP_ENTITY_POPULATE,
|
||||
NlpEntity,
|
||||
@@ -29,7 +30,8 @@ import { NlpValueRepository } from './nlp-value.repository';
|
||||
export class NlpEntityRepository extends BaseRepository<
|
||||
NlpEntity,
|
||||
NlpEntityPopulate,
|
||||
NlpEntityFull
|
||||
NlpEntityFull,
|
||||
NlpEntityDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -113,6 +113,9 @@ describe('NlpSampleEntityRepository', () => {
|
||||
const ValueWithEntities = {
|
||||
...curr,
|
||||
entity: nlpEntities[0].id,
|
||||
expressions: curr.expressions!,
|
||||
builtin: curr.builtin!,
|
||||
metadata: curr.metadata!,
|
||||
};
|
||||
acc.push(ValueWithEntities);
|
||||
return acc;
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Document, Model, Query } from 'mongoose';
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { TNlpSampleDto } from '../dto/nlp-sample.dto';
|
||||
import {
|
||||
NLP_SAMPLE_POPULATE,
|
||||
NlpSample,
|
||||
@@ -27,7 +28,8 @@ import { NlpSampleEntityRepository } from './nlp-sample-entity.repository';
|
||||
export class NlpSampleRepository extends BaseRepository<
|
||||
NlpSample,
|
||||
NlpSamplePopulate,
|
||||
NlpSampleFull
|
||||
NlpSampleFull,
|
||||
TNlpSampleDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -89,6 +89,9 @@ describe('NlpValueRepository', () => {
|
||||
entity: nlpEntityFixtures[
|
||||
parseInt(curr.entity)
|
||||
] as NlpValueFull['entity'],
|
||||
builtin: curr.builtin!,
|
||||
expressions: curr.expressions!,
|
||||
metadata: curr.metadata!,
|
||||
};
|
||||
acc.push(ValueWithEntities);
|
||||
return acc;
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Document, Model, Query } from 'mongoose';
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { NlpValueDto } from '../dto/nlp-value.dto';
|
||||
import {
|
||||
NLP_VALUE_POPULATE,
|
||||
NlpValue,
|
||||
@@ -28,7 +29,8 @@ import { NlpSampleEntityRepository } from './nlp-sample-entity.repository';
|
||||
export class NlpValueRepository extends BaseRepository<
|
||||
NlpValue,
|
||||
NlpValuePopulate,
|
||||
NlpValueFull
|
||||
NlpValueFull,
|
||||
NlpValueDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -44,7 +44,7 @@ export class NlpEntityStub extends BaseSchema {
|
||||
* Lookup strategy can contain : keywords, trait, free-text
|
||||
*/
|
||||
@Prop({ type: [String], default: ['keywords'] })
|
||||
lookups?: Lookup[];
|
||||
lookups: Lookup[];
|
||||
|
||||
/**
|
||||
* Description of the entity purpose.
|
||||
@@ -56,7 +56,7 @@ export class NlpEntityStub extends BaseSchema {
|
||||
* Either or not this entity a built-in (either fixtures or shipped along with the 3rd party ai).
|
||||
*/
|
||||
@Prop({ type: Boolean, default: false })
|
||||
builtin?: boolean;
|
||||
builtin: boolean;
|
||||
|
||||
/**
|
||||
* Returns a map object for entities
|
||||
|
||||
@@ -33,7 +33,7 @@ export class NlpSampleStub extends BaseSchema {
|
||||
* Either or not this sample was used for traning already.
|
||||
*/
|
||||
@Prop({ type: Boolean, default: false })
|
||||
trained?: boolean;
|
||||
trained: boolean;
|
||||
|
||||
/**
|
||||
* From where this sample was provided.
|
||||
@@ -43,7 +43,7 @@ export class NlpSampleStub extends BaseSchema {
|
||||
enum: Object.values(NlpSampleState),
|
||||
default: NlpSampleState.train,
|
||||
})
|
||||
type?: keyof typeof NlpSampleState;
|
||||
type: keyof typeof NlpSampleState;
|
||||
|
||||
/**
|
||||
* The language of the sample.
|
||||
|
||||
@@ -38,19 +38,19 @@ export class NlpValueStub extends BaseSchema {
|
||||
* An array of synonyms or equivalent words that fits this value.
|
||||
*/
|
||||
@Prop({ type: [String], default: [] })
|
||||
expressions?: string[];
|
||||
expressions: string[];
|
||||
|
||||
/**
|
||||
* Metadata are additional data that can be associated to this values, most of the time, the metadata contains system values or ids (e.g: value: "coffee", metadata: "item_11") .
|
||||
*/
|
||||
@Prop({ type: JSON, default: {} })
|
||||
metadata?: Record<string, any>;
|
||||
metadata: Record<string, any>;
|
||||
|
||||
/**
|
||||
* Either or not this value a built-in (either fixtures or shipped along with the 3rd party ai).
|
||||
*/
|
||||
@Prop({ type: Boolean, default: false })
|
||||
builtin?: boolean;
|
||||
builtin: boolean;
|
||||
|
||||
/**
|
||||
* The entity to which this value belongs to.
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseSeeder } from '@/utils/generics/base-seeder';
|
||||
|
||||
import { NlpEntityDto } from '../dto/nlp-entity.dto';
|
||||
import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
|
||||
import {
|
||||
NlpEntity,
|
||||
@@ -21,7 +22,8 @@ import {
|
||||
export class NlpEntitySeeder extends BaseSeeder<
|
||||
NlpEntity,
|
||||
NlpEntityPopulate,
|
||||
NlpEntityFull
|
||||
NlpEntityFull,
|
||||
NlpEntityDto
|
||||
> {
|
||||
constructor(nlpEntityRepository: NlpEntityRepository) {
|
||||
super(nlpEntityRepository);
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseSchema } from '@/utils/generics/base-schema';
|
||||
import { BaseSeeder } from '@/utils/generics/base-seeder';
|
||||
|
||||
import { NlpValueCreateDto, NlpValueDto } from '../dto/nlp-value.dto';
|
||||
import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
|
||||
import { NlpValueRepository } from '../repositories/nlp-value.repository';
|
||||
import {
|
||||
@@ -23,7 +23,8 @@ import {
|
||||
export class NlpValueSeeder extends BaseSeeder<
|
||||
NlpValue,
|
||||
NlpValuePopulate,
|
||||
NlpValueFull
|
||||
NlpValueFull,
|
||||
NlpValueDto
|
||||
> {
|
||||
constructor(
|
||||
nlpValueRepository: NlpValueRepository,
|
||||
@@ -32,7 +33,7 @@ export class NlpValueSeeder extends BaseSeeder<
|
||||
super(nlpValueRepository);
|
||||
}
|
||||
|
||||
async seed(models: Omit<NlpValue, keyof BaseSchema>[]): Promise<boolean> {
|
||||
async seed(models: NlpValueCreateDto[]): Promise<boolean> {
|
||||
if (await this.isEmpty()) {
|
||||
const entities = await this.nlpEntityRepository.findAll();
|
||||
const modelDtos = models.map((v) => ({
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { Lookup } from '../dto/nlp-entity.dto';
|
||||
import { Lookup, NlpEntityDto } from '../dto/nlp-entity.dto';
|
||||
import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
|
||||
import {
|
||||
NlpEntity,
|
||||
@@ -25,7 +25,8 @@ import { NlpValueService } from './nlp-value.service';
|
||||
export class NlpEntityService extends BaseService<
|
||||
NlpEntity,
|
||||
NlpEntityPopulate,
|
||||
NlpEntityFull
|
||||
NlpEntityFull,
|
||||
NlpEntityDto
|
||||
> {
|
||||
constructor(
|
||||
readonly repository: NlpEntityRepository,
|
||||
|
||||
@@ -133,6 +133,9 @@ describe('NlpSampleEntityService', () => {
|
||||
const ValueWithEntities = {
|
||||
...curr,
|
||||
entity: nlpEntities[0].id,
|
||||
expressions: curr.expressions!,
|
||||
builtin: curr.builtin!,
|
||||
metadata: curr.metadata!,
|
||||
};
|
||||
acc.push(ValueWithEntities);
|
||||
return acc;
|
||||
|
||||
@@ -21,7 +21,7 @@ import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
import { THydratedDocument } from '@/utils/types/filter.types';
|
||||
|
||||
import { NlpSampleCreateDto } from '../dto/nlp-sample.dto';
|
||||
import { NlpSampleCreateDto, TNlpSampleDto } from '../dto/nlp-sample.dto';
|
||||
import { NlpSampleRepository } from '../repositories/nlp-sample.repository';
|
||||
import {
|
||||
NlpSample,
|
||||
@@ -37,7 +37,8 @@ import { NlpSampleEntityService } from './nlp-sample-entity.service';
|
||||
export class NlpSampleService extends BaseService<
|
||||
NlpSample,
|
||||
NlpSamplePopulate,
|
||||
NlpSampleFull
|
||||
NlpSampleFull,
|
||||
TNlpSampleDto
|
||||
> {
|
||||
constructor(
|
||||
readonly repository: NlpSampleRepository,
|
||||
|
||||
@@ -97,6 +97,9 @@ describe('NlpValueService', () => {
|
||||
entity: nlpEntityFixtures[
|
||||
parseInt(curr.entity)
|
||||
] as NlpValueFull['entity'],
|
||||
expressions: curr.expressions!,
|
||||
metadata: curr.metadata!,
|
||||
builtin: curr.builtin!,
|
||||
};
|
||||
acc.push(ValueWithEntities);
|
||||
return acc;
|
||||
|
||||
@@ -11,7 +11,11 @@ import { forwardRef, Inject, Injectable } from '@nestjs/common';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { NlpValueCreateDto, NlpValueUpdateDto } from '../dto/nlp-value.dto';
|
||||
import {
|
||||
NlpValueCreateDto,
|
||||
NlpValueDto,
|
||||
NlpValueUpdateDto,
|
||||
} from '../dto/nlp-value.dto';
|
||||
import { NlpValueRepository } from '../repositories/nlp-value.repository';
|
||||
import { NlpEntity } from '../schemas/nlp-entity.schema';
|
||||
import {
|
||||
@@ -27,7 +31,8 @@ import { NlpEntityService } from './nlp-entity.service';
|
||||
export class NlpValueService extends BaseService<
|
||||
NlpValue,
|
||||
NlpValuePopulate,
|
||||
NlpValueFull
|
||||
NlpValueFull,
|
||||
NlpValueDto
|
||||
> {
|
||||
constructor(
|
||||
readonly repository: NlpValueRepository,
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
*/
|
||||
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsEnum, IsNotEmpty, IsString, IsOptional } from 'class-validator';
|
||||
import { IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
import { IsObjectId } from '@/utils/validation-rules/is-object-id';
|
||||
|
||||
import { Action } from '../types/action.type';
|
||||
@@ -40,3 +41,7 @@ export class PermissionCreateDto {
|
||||
@IsOptional()
|
||||
relation?: TRelation;
|
||||
}
|
||||
|
||||
export type PermissionDto = DtoConfig<{
|
||||
create: PermissionCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger';
|
||||
import { IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
|
||||
export class RoleCreateDto {
|
||||
@ApiProperty({ description: 'Name of the role', type: String })
|
||||
@IsNotEmpty()
|
||||
@@ -26,3 +28,7 @@ export class RoleCreateDto {
|
||||
}
|
||||
|
||||
export class RoleUpdateDto extends PartialType(RoleCreateDto) {}
|
||||
|
||||
export type RoleDto = DtoConfig<{
|
||||
create: RoleCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
IsString,
|
||||
} from 'class-validator';
|
||||
|
||||
import { DtoConfig } from '@/utils/types/dto.types';
|
||||
import { IsObjectId } from '@/utils/validation-rules/is-object-id';
|
||||
|
||||
export class UserCreateDto {
|
||||
@@ -61,12 +62,21 @@ export class UserCreateDto {
|
||||
@IsString()
|
||||
@IsObjectId({ message: 'Avatar must be a valid ObjectId' })
|
||||
avatar: string | null = null;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'User state',
|
||||
type: Boolean,
|
||||
})
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
state?: boolean;
|
||||
}
|
||||
|
||||
export class UserEditProfileDto extends OmitType(PartialType(UserCreateDto), [
|
||||
'username',
|
||||
'roles',
|
||||
'avatar',
|
||||
'state',
|
||||
]) {
|
||||
@ApiPropertyOptional({ description: 'User language', type: String })
|
||||
@IsOptional()
|
||||
@@ -98,3 +108,7 @@ export class UserResetPasswordDto extends PickType(UserCreateDto, [
|
||||
]) {}
|
||||
|
||||
export class UserRequestResetDto extends PickType(UserCreateDto, ['email']) {}
|
||||
|
||||
export type UserDto = DtoConfig<{
|
||||
create: UserCreateDto;
|
||||
}>;
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Model } from 'mongoose';
|
||||
|
||||
import { BaseRepository } from '@/utils/generics/base-repository';
|
||||
|
||||
import { PermissionDto } from '../dto/permission.dto';
|
||||
import {
|
||||
Permission,
|
||||
PERMISSION_POPULATE,
|
||||
@@ -24,7 +25,8 @@ import {
|
||||
export class PermissionRepository extends BaseRepository<
|
||||
Permission,
|
||||
PermissionPopulate,
|
||||
PermissionFull
|
||||
PermissionFull,
|
||||
PermissionDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -13,6 +13,7 @@ import { Model } from 'mongoose';
|
||||
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
|
||||
import { RoleDto } from '../dto/role.dto';
|
||||
import { Permission } from '../schemas/permission.schema';
|
||||
import {
|
||||
Role,
|
||||
@@ -25,7 +26,8 @@ import {
|
||||
export class RoleRepository extends BaseRepository<
|
||||
Role,
|
||||
RolePopulate,
|
||||
RoleFull
|
||||
RoleFull,
|
||||
RoleDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
import { BaseRepository } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { UserEditProfileDto } from '../dto/user.dto';
|
||||
import { UserDto, UserEditProfileDto } from '../dto/user.dto';
|
||||
import {
|
||||
User,
|
||||
USER_POPULATE,
|
||||
@@ -34,7 +34,8 @@ import { hash } from '../utilities/bcryptjs';
|
||||
export class UserRepository extends BaseRepository<
|
||||
User,
|
||||
UserPopulate,
|
||||
UserFull
|
||||
UserFull,
|
||||
UserDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
} from '@/utils/types/filter.types';
|
||||
|
||||
import { Action } from '../types/action.type';
|
||||
import { TRelation } from '../types/index.type';
|
||||
|
||||
import { Model } from './model.schema';
|
||||
import { Role } from './role.schema';
|
||||
@@ -41,7 +42,7 @@ export class PermissionStub extends BaseSchema {
|
||||
type: String,
|
||||
default: 'role',
|
||||
})
|
||||
relation?: string;
|
||||
relation: TRelation;
|
||||
}
|
||||
|
||||
@Schema({ timestamps: true })
|
||||
|
||||
@@ -31,7 +31,7 @@ export class RoleStub extends BaseSchema {
|
||||
name: string;
|
||||
|
||||
@Prop({ type: Boolean, default: true })
|
||||
active?: boolean;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
@Schema({ timestamps: true })
|
||||
|
||||
@@ -50,6 +50,16 @@ export class UserStub extends BaseSchema {
|
||||
})
|
||||
password: string;
|
||||
|
||||
@Prop([{ type: MongooseSchema.Types.ObjectId, ref: 'Role' }])
|
||||
roles: unknown;
|
||||
|
||||
@Prop({
|
||||
type: MongooseSchema.Types.ObjectId,
|
||||
ref: 'Attachment',
|
||||
default: null,
|
||||
})
|
||||
avatar: unknown;
|
||||
|
||||
@Prop({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -83,16 +93,6 @@ export class UserStub extends BaseSchema {
|
||||
})
|
||||
resetCount?: number;
|
||||
|
||||
@Prop([{ type: MongooseSchema.Types.ObjectId, ref: 'Role' }])
|
||||
roles: unknown;
|
||||
|
||||
@Prop({
|
||||
type: MongooseSchema.Types.ObjectId,
|
||||
ref: 'Attachment',
|
||||
default: null,
|
||||
})
|
||||
avatar: unknown;
|
||||
|
||||
@Prop({
|
||||
type: String,
|
||||
default: null,
|
||||
|
||||
@@ -10,6 +10,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseSeeder } from '@/utils/generics/base-seeder';
|
||||
|
||||
import { PermissionDto } from '../dto/permission.dto';
|
||||
import { PermissionRepository } from '../repositories/permission.repository';
|
||||
import {
|
||||
Permission,
|
||||
@@ -21,7 +22,8 @@ import {
|
||||
export class PermissionSeeder extends BaseSeeder<
|
||||
Permission,
|
||||
PermissionPopulate,
|
||||
PermissionFull
|
||||
PermissionFull,
|
||||
PermissionDto
|
||||
> {
|
||||
constructor(private readonly permissionRepository: PermissionRepository) {
|
||||
super(permissionRepository);
|
||||
|
||||
@@ -10,11 +10,17 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseSeeder } from '@/utils/generics/base-seeder';
|
||||
|
||||
import { RoleDto } from '../dto/role.dto';
|
||||
import { RoleRepository } from '../repositories/role.repository';
|
||||
import { Role, RoleFull, RolePopulate } from '../schemas/role.schema';
|
||||
|
||||
@Injectable()
|
||||
export class RoleSeeder extends BaseSeeder<Role, RolePopulate, RoleFull> {
|
||||
export class RoleSeeder extends BaseSeeder<
|
||||
Role,
|
||||
RolePopulate,
|
||||
RoleFull,
|
||||
RoleDto
|
||||
> {
|
||||
constructor(private readonly roleRepository: RoleRepository) {
|
||||
super(roleRepository);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { PERMISSION_CACHE_KEY } from '@/utils/constants/cache';
|
||||
import { Cacheable } from '@/utils/decorators/cacheable.decorator';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { PermissionDto } from '../dto/permission.dto';
|
||||
import { PermissionRepository } from '../repositories/permission.repository';
|
||||
import {
|
||||
Permission,
|
||||
@@ -27,7 +28,8 @@ import { PermissionsTree } from '../types/permission.type';
|
||||
export class PermissionService extends BaseService<
|
||||
Permission,
|
||||
PermissionPopulate,
|
||||
PermissionFull
|
||||
PermissionFull,
|
||||
PermissionDto
|
||||
> {
|
||||
constructor(
|
||||
readonly repository: PermissionRepository,
|
||||
|
||||
@@ -10,11 +10,17 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { RoleDto } from '../dto/role.dto';
|
||||
import { RoleRepository } from '../repositories/role.repository';
|
||||
import { Role, RoleFull, RolePopulate } from '../schemas/role.schema';
|
||||
|
||||
@Injectable()
|
||||
export class RoleService extends BaseService<Role, RolePopulate, RoleFull> {
|
||||
export class RoleService extends BaseService<
|
||||
Role,
|
||||
RolePopulate,
|
||||
RoleFull,
|
||||
RoleDto
|
||||
> {
|
||||
constructor(readonly repository: RoleRepository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@@ -10,11 +10,17 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { UserDto } from '../dto/user.dto';
|
||||
import { UserRepository } from '../repositories/user.repository';
|
||||
import { User, UserFull, UserPopulate } from '../schemas/user.schema';
|
||||
|
||||
@Injectable()
|
||||
export class UserService extends BaseService<User, UserPopulate, UserFull> {
|
||||
export class UserService extends BaseService<
|
||||
User,
|
||||
UserPopulate,
|
||||
UserFull,
|
||||
UserDto
|
||||
> {
|
||||
constructor(readonly repository: UserRepository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { NotFoundException } from '@nestjs/common';
|
||||
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { DtoConfig } from '../types/dto.types';
|
||||
import { TValidateProps } from '../types/filter.types';
|
||||
|
||||
import { BaseSchema } from './base-schema';
|
||||
@@ -20,8 +21,9 @@ export abstract class BaseController<
|
||||
TStub = never,
|
||||
P extends string = never,
|
||||
TFull extends Omit<T, P> = never,
|
||||
Dto extends DtoConfig = object,
|
||||
> {
|
||||
constructor(protected readonly service: BaseService<T, P, TFull>) {}
|
||||
constructor(protected readonly service: BaseService<T, P, TFull, Dto>) {}
|
||||
|
||||
/**
|
||||
* Checks if the given populate fields are allowed based on the allowed fields list.
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { PageQueryDto, QuerySortDto } from '../pagination/pagination-query.dto';
|
||||
import { DtoAction, DtoConfig, DtoInfer } from '../types/dto.types';
|
||||
|
||||
import { BaseSchema } from './base-schema';
|
||||
import { LifecycleHookManager } from './lifecycle-hook-manager';
|
||||
@@ -70,7 +71,8 @@ export abstract class BaseRepository<
|
||||
T extends FlattenMaps<unknown>,
|
||||
P extends string = never,
|
||||
TFull extends Omit<T, P> = never,
|
||||
U = Omit<T, keyof BaseSchema>,
|
||||
Dto extends DtoConfig = object,
|
||||
U extends Omit<T, keyof BaseSchema> = Omit<T, keyof BaseSchema>,
|
||||
D = Document<T>,
|
||||
> {
|
||||
private readonly transformOpts = { excludePrefixes: ['_', 'password'] };
|
||||
@@ -454,7 +456,7 @@ export abstract class BaseRepository<
|
||||
return await this.model.countDocuments(criteria).exec();
|
||||
}
|
||||
|
||||
async create(dto: U): Promise<T> {
|
||||
async create(dto: DtoInfer<DtoAction.Create, Dto, U>): Promise<T> {
|
||||
const doc = await this.model.create(dto);
|
||||
|
||||
return plainToClass(
|
||||
@@ -464,7 +466,9 @@ export abstract class BaseRepository<
|
||||
);
|
||||
}
|
||||
|
||||
async createMany(dtoArray: U[]): Promise<T[]> {
|
||||
async createMany(
|
||||
dtoArray: DtoInfer<DtoAction.Create, Dto, U>[],
|
||||
): Promise<T[]> {
|
||||
const docs = await this.model.create(dtoArray);
|
||||
|
||||
return docs.map((doc) =>
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
import { FlattenMaps } from 'mongoose';
|
||||
|
||||
import { DtoAction, DtoConfig, DtoInfer } from '../types/dto.types';
|
||||
|
||||
import { BaseRepository } from './base-repository';
|
||||
import { BaseSchema } from './base-schema';
|
||||
|
||||
@@ -15,8 +17,12 @@ export abstract class BaseSeeder<
|
||||
T extends FlattenMaps<unknown>,
|
||||
P extends string = never,
|
||||
TFull extends Omit<T, P> = never,
|
||||
Dto extends DtoConfig = object,
|
||||
U extends Omit<T, keyof BaseSchema> = Omit<T, keyof BaseSchema>,
|
||||
> {
|
||||
constructor(protected readonly repository: BaseRepository<T, P, TFull>) {}
|
||||
constructor(
|
||||
protected readonly repository: BaseRepository<T, P, TFull, Dto>,
|
||||
) {}
|
||||
|
||||
async findAll(): Promise<T[]> {
|
||||
return await this.repository.findAll();
|
||||
@@ -27,7 +33,7 @@ export abstract class BaseSeeder<
|
||||
return count === 0;
|
||||
}
|
||||
|
||||
async seed(models: Omit<T, keyof BaseSchema>[]): Promise<boolean> {
|
||||
async seed(models: DtoInfer<DtoAction.Create, Dto, U>[]): Promise<boolean> {
|
||||
if (await this.isEmpty()) {
|
||||
await this.repository.createMany(models);
|
||||
return true;
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ProjectionType, QueryOptions } from 'mongoose';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
import { PageQueryDto, QuerySortDto } from '../pagination/pagination-query.dto';
|
||||
import { DtoAction, DtoConfig, DtoInfer } from '../types/dto.types';
|
||||
|
||||
import { BaseRepository } from './base-repository';
|
||||
import { BaseSchema } from './base-schema';
|
||||
@@ -22,8 +23,12 @@ export abstract class BaseService<
|
||||
T extends BaseSchema,
|
||||
P extends string = never,
|
||||
TFull extends Omit<T, P> = never,
|
||||
Dto extends DtoConfig = object,
|
||||
U extends Omit<T, keyof BaseSchema> = Omit<T, keyof BaseSchema>,
|
||||
> {
|
||||
constructor(protected readonly repository: BaseRepository<T, P, TFull>) {}
|
||||
constructor(
|
||||
protected readonly repository: BaseRepository<T, P, TFull, Dto>,
|
||||
) {}
|
||||
|
||||
getRepository() {
|
||||
return this.repository;
|
||||
@@ -140,7 +145,7 @@ export abstract class BaseService<
|
||||
return await this.repository.count(criteria);
|
||||
}
|
||||
|
||||
async create<D extends Omit<T, keyof BaseSchema>>(dto: D): Promise<T> {
|
||||
async create(dto: DtoInfer<DtoAction.Create, Dto, U>): Promise<T> {
|
||||
try {
|
||||
return await this.repository.create(dto);
|
||||
} catch (error) {
|
||||
@@ -153,9 +158,9 @@ export abstract class BaseService<
|
||||
}
|
||||
}
|
||||
|
||||
async findOneOrCreate<D extends Omit<T, keyof BaseSchema>>(
|
||||
async findOneOrCreate(
|
||||
criteria: string | TFilterQuery<T>,
|
||||
dto: D,
|
||||
dto: DtoInfer<DtoAction.Create, Dto, U>,
|
||||
): Promise<T> {
|
||||
const result = await this.findOne(criteria);
|
||||
if (!result) {
|
||||
@@ -164,24 +169,21 @@ export abstract class BaseService<
|
||||
return result;
|
||||
}
|
||||
|
||||
async createMany<D extends Omit<T, keyof BaseSchema>>(
|
||||
dtoArray: D[],
|
||||
async createMany(
|
||||
dtoArray: DtoInfer<DtoAction.Create, Dto, U>[],
|
||||
): Promise<T[]> {
|
||||
return await this.repository.createMany(dtoArray);
|
||||
}
|
||||
|
||||
async updateOne<D extends Partial<Omit<T, keyof BaseSchema>>>(
|
||||
async updateOne(
|
||||
criteria: string | TFilterQuery<T>,
|
||||
dto: D,
|
||||
options?: QueryOptions<D> | null,
|
||||
dto: Partial<U>,
|
||||
options?: QueryOptions<Partial<U>> | null,
|
||||
): Promise<T | null> {
|
||||
return await this.repository.updateOne(criteria, dto, options);
|
||||
}
|
||||
|
||||
async updateMany<D extends Partial<Omit<T, keyof BaseSchema>>>(
|
||||
filter: TFilterQuery<T>,
|
||||
dto: D,
|
||||
) {
|
||||
async updateMany(filter: TFilterQuery<T>, dto: Partial<U>) {
|
||||
return await this.repository.updateMany(filter, dto);
|
||||
}
|
||||
|
||||
|
||||
37
api/src/utils/test/fixtures/block.ts
vendored
37
api/src/utils/test/fixtures/block.ts
vendored
@@ -16,13 +16,26 @@ import { ButtonType } from '@/chat/schemas/types/button';
|
||||
import { QuickReplyType } from '@/chat/schemas/types/quick-reply';
|
||||
|
||||
import { getFixturesWithDefaultValues } from '../defaultValues';
|
||||
import { TFixturesDefaultValues } from '../types';
|
||||
import { FixturesTypeBuilder } from '../types';
|
||||
|
||||
export const blocks: BlockCreateDto[] = [
|
||||
type TBlockFixtures = FixturesTypeBuilder<Block, BlockCreateDto>;
|
||||
|
||||
export const blockDefaultValues: TBlockFixtures['defaultValues'] = {
|
||||
options: {},
|
||||
nextBlocks: [],
|
||||
capture_vars: [],
|
||||
assign_labels: [],
|
||||
trigger_labels: [],
|
||||
trigger_channels: [],
|
||||
builtin: false,
|
||||
starts_conversation: false,
|
||||
attachedBlock: null,
|
||||
};
|
||||
|
||||
export const blocks: TBlockFixtures['values'][] = [
|
||||
{
|
||||
name: 'hasNextBlocks',
|
||||
patterns: ['Hi'],
|
||||
trigger_channels: [],
|
||||
category: null,
|
||||
options: {
|
||||
typing: 0,
|
||||
@@ -41,7 +54,6 @@ export const blocks: BlockCreateDto[] = [
|
||||
{
|
||||
name: 'hasPreviousBlocks',
|
||||
patterns: ['colors'],
|
||||
trigger_channels: [],
|
||||
category: null,
|
||||
options: {
|
||||
typing: 0,
|
||||
@@ -79,7 +91,6 @@ export const blocks: BlockCreateDto[] = [
|
||||
{
|
||||
name: 'buttons',
|
||||
patterns: ['about'],
|
||||
trigger_channels: [],
|
||||
category: null,
|
||||
options: {
|
||||
typing: 0,
|
||||
@@ -117,7 +128,6 @@ export const blocks: BlockCreateDto[] = [
|
||||
{
|
||||
name: 'attachment',
|
||||
patterns: ['image'],
|
||||
trigger_channels: [],
|
||||
category: null,
|
||||
options: {
|
||||
typing: 0,
|
||||
@@ -144,7 +154,6 @@ export const blocks: BlockCreateDto[] = [
|
||||
{
|
||||
name: 'test',
|
||||
patterns: ['yes'],
|
||||
trigger_channels: [],
|
||||
category: null,
|
||||
//to be verified
|
||||
options: {
|
||||
@@ -163,17 +172,9 @@ export const blocks: BlockCreateDto[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const blockDefaultValues: TFixturesDefaultValues<Block> = {
|
||||
options: {},
|
||||
builtin: false,
|
||||
nextBlocks: [],
|
||||
capture_vars: [],
|
||||
assign_labels: [],
|
||||
trigger_labels: [],
|
||||
starts_conversation: false,
|
||||
};
|
||||
|
||||
export const blockFixtures = getFixturesWithDefaultValues<Block>({
|
||||
export const blockFixtures = getFixturesWithDefaultValues<
|
||||
TBlockFixtures['values']
|
||||
>({
|
||||
fixtures: blocks,
|
||||
defaultValues: blockDefaultValues,
|
||||
});
|
||||
|
||||
29
api/src/utils/test/fixtures/category.ts
vendored
29
api/src/utils/test/fixtures/category.ts
vendored
@@ -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.
|
||||
@@ -9,12 +9,23 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
import { CategoryCreateDto } from '@/chat/dto/category.dto';
|
||||
import { CategoryModel, Category } from '@/chat/schemas/category.schema';
|
||||
import { Category, CategoryModel } from '@/chat/schemas/category.schema';
|
||||
|
||||
import { getFixturesWithDefaultValues } from '../defaultValues';
|
||||
import { TFixturesDefaultValues } from '../types';
|
||||
import { FixturesTypeBuilder } from '../types';
|
||||
|
||||
export const categories: CategoryCreateDto[] = [
|
||||
export type TCategoryFixtures = FixturesTypeBuilder<
|
||||
Category,
|
||||
CategoryCreateDto
|
||||
>;
|
||||
|
||||
export const categoryDefaultValues: TCategoryFixtures['defaultValues'] = {
|
||||
builtin: false,
|
||||
zoom: 100,
|
||||
offset: [0, 0],
|
||||
};
|
||||
|
||||
export const categories: TCategoryFixtures['values'][] = [
|
||||
{
|
||||
label: 'test category 1',
|
||||
},
|
||||
@@ -23,13 +34,9 @@ export const categories: CategoryCreateDto[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const categoryDefaultValues: TFixturesDefaultValues<Category> = {
|
||||
builtin: false,
|
||||
zoom: 100,
|
||||
offset: [0, 0],
|
||||
};
|
||||
|
||||
export const categoryFixtures = getFixturesWithDefaultValues<Category>({
|
||||
export const categoryFixtures = getFixturesWithDefaultValues<
|
||||
TCategoryFixtures['values']
|
||||
>({
|
||||
fixtures: categories,
|
||||
defaultValues: categoryDefaultValues,
|
||||
});
|
||||
|
||||
23
api/src/utils/test/fixtures/content.ts
vendored
23
api/src/utils/test/fixtures/content.ts
vendored
@@ -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.
|
||||
@@ -12,12 +12,18 @@ import { ContentCreateDto } from '@/cms/dto/content.dto';
|
||||
import { Content, ContentModel } from '@/cms/schemas/content.schema';
|
||||
|
||||
import { getFixturesWithDefaultValues } from '../defaultValues';
|
||||
import { TFixturesDefaultValues } from '../types';
|
||||
import { FixturesTypeBuilder } from '../types';
|
||||
|
||||
import { installAttachmentFixtures } from './attachment';
|
||||
import { installContentTypeFixtures } from './contenttype';
|
||||
|
||||
const contents: ContentCreateDto[] = [
|
||||
type TContentFixtures = FixturesTypeBuilder<Content, ContentCreateDto>;
|
||||
|
||||
export const contentDefaultValues: TContentFixtures['defaultValues'] = {
|
||||
status: true,
|
||||
};
|
||||
|
||||
const contents: TContentFixtures['values'][] = [
|
||||
{
|
||||
title: 'Jean',
|
||||
dynamicFields: {
|
||||
@@ -131,14 +137,11 @@ const contents: ContentCreateDto[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const categoryDefaultValues: TFixturesDefaultValues<Content> = {
|
||||
status: true,
|
||||
createdAt: undefined,
|
||||
};
|
||||
|
||||
export const contentFixtures = getFixturesWithDefaultValues<Content>({
|
||||
export const contentFixtures = getFixturesWithDefaultValues<
|
||||
TContentFixtures['values']
|
||||
>({
|
||||
fixtures: contents,
|
||||
defaultValues: categoryDefaultValues,
|
||||
defaultValues: contentDefaultValues,
|
||||
});
|
||||
|
||||
export const installContentFixtures = async () => {
|
||||
|
||||
45
api/src/utils/test/fixtures/contenttype.ts
vendored
45
api/src/utils/test/fixtures/contenttype.ts
vendored
@@ -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.
|
||||
@@ -15,9 +15,29 @@ import {
|
||||
} from '@/cms/schemas/content-type.schema';
|
||||
|
||||
import { getFixturesWithDefaultValues } from '../defaultValues';
|
||||
import { TFixturesDefaultValues } from '../types';
|
||||
import { FixturesTypeBuilder } from '../types';
|
||||
|
||||
const contentTypes: ContentTypeCreateDto[] = [
|
||||
type TContentTypeFixtures = FixturesTypeBuilder<
|
||||
ContentType,
|
||||
ContentTypeCreateDto
|
||||
>;
|
||||
|
||||
export const contentTypeDefaultValues: TContentTypeFixtures['defaultValues'] = {
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
type: 'checkbox',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const contentTypes: TContentTypeFixtures['values'][] = [
|
||||
{
|
||||
name: 'Product',
|
||||
fields: [
|
||||
@@ -100,22 +120,9 @@ const contentTypes: ContentTypeCreateDto[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const contentTypeDefaultValues: TFixturesDefaultValues<ContentType> = {
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Status',
|
||||
type: 'checkbox',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const contentTypeFixtures = getFixturesWithDefaultValues<ContentType>({
|
||||
export const contentTypeFixtures = getFixturesWithDefaultValues<
|
||||
TContentTypeFixtures['values']
|
||||
>({
|
||||
fixtures: contentTypes,
|
||||
defaultValues: contentTypeDefaultValues,
|
||||
});
|
||||
|
||||
20
api/src/utils/test/fixtures/contextvar.ts
vendored
20
api/src/utils/test/fixtures/contextvar.ts
vendored
@@ -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.
|
||||
@@ -9,25 +9,33 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
import { ContextVarCreateDto } from '@/chat/dto/context-var.dto';
|
||||
import { ContextVarModel, ContextVar } from '@/chat/schemas/context-var.schema';
|
||||
import { ContextVar, ContextVarModel } from '@/chat/schemas/context-var.schema';
|
||||
|
||||
import { getFixturesWithDefaultValues } from '../defaultValues';
|
||||
import { FixturesTypeBuilder } from '../types';
|
||||
|
||||
const contextVars: ContextVarCreateDto[] = [
|
||||
type TContentVarFixtures = FixturesTypeBuilder<ContextVar, ContextVarCreateDto>;
|
||||
|
||||
export const contentVarDefaultValues: TContentVarFixtures['defaultValues'] = {
|
||||
permanent: false,
|
||||
};
|
||||
|
||||
const contextVars: TContentVarFixtures['values'][] = [
|
||||
{
|
||||
label: 'test context var 1',
|
||||
name: 'test1',
|
||||
permanent: false,
|
||||
},
|
||||
{
|
||||
label: 'test context var 2',
|
||||
name: 'test2',
|
||||
permanent: false,
|
||||
},
|
||||
];
|
||||
|
||||
export const contextVarFixtures = getFixturesWithDefaultValues<ContextVar>({
|
||||
export const contextVarFixtures = getFixturesWithDefaultValues<
|
||||
TContentVarFixtures['values']
|
||||
>({
|
||||
fixtures: contextVars,
|
||||
defaultValues: contentVarDefaultValues,
|
||||
});
|
||||
|
||||
export const installContextVarFixtures = async () => {
|
||||
|
||||
21
api/src/utils/test/fixtures/conversation.ts
vendored
21
api/src/utils/test/fixtures/conversation.ts
vendored
@@ -9,10 +9,7 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
import { ConversationCreateDto } from '@/chat/dto/conversation.dto';
|
||||
import {
|
||||
Conversation,
|
||||
ConversationModel,
|
||||
} from '@/chat/schemas/conversation.schema';
|
||||
import { ConversationModel } from '@/chat/schemas/conversation.schema';
|
||||
|
||||
import { getFixturesWithDefaultValues } from '../defaultValues';
|
||||
import { TFixturesDefaultValues } from '../types';
|
||||
@@ -116,14 +113,16 @@ const conversations: ConversationCreateDto[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const conversationDefaultValues: TFixturesDefaultValues<Conversation> = {
|
||||
active: false,
|
||||
};
|
||||
export const conversationDefaultValues: TFixturesDefaultValues<ConversationCreateDto> =
|
||||
{
|
||||
active: false,
|
||||
};
|
||||
|
||||
export const conversationFixtures = getFixturesWithDefaultValues<Conversation>({
|
||||
fixtures: conversations,
|
||||
defaultValues: conversationDefaultValues,
|
||||
});
|
||||
export const conversationFixtures =
|
||||
getFixturesWithDefaultValues<ConversationCreateDto>({
|
||||
fixtures: conversations,
|
||||
defaultValues: conversationDefaultValues,
|
||||
});
|
||||
|
||||
export const installConversationTypeFixtures = async () => {
|
||||
const subscribers = await installSubscriberFixtures();
|
||||
|
||||
22
api/src/utils/test/fixtures/label.ts
vendored
22
api/src/utils/test/fixtures/label.ts
vendored
@@ -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.
|
||||
@@ -12,9 +12,15 @@ import { LabelCreateDto } from '@/chat/dto/label.dto';
|
||||
import { Label, LabelModel } from '@/chat/schemas/label.schema';
|
||||
|
||||
import { getFixturesWithDefaultValues } from '../defaultValues';
|
||||
import { TFixturesDefaultValues } from '../types';
|
||||
import { FixturesTypeBuilder } from '../types';
|
||||
|
||||
export const labels: LabelCreateDto[] = [
|
||||
type TLabelFixtures = FixturesTypeBuilder<Label, LabelCreateDto>;
|
||||
|
||||
export const contentLabelDefaultValues: TLabelFixtures['defaultValues'] = {
|
||||
builtin: false,
|
||||
};
|
||||
|
||||
export const labels: TLabelFixtures['values'][] = [
|
||||
{
|
||||
description: 'test description 1',
|
||||
label_id: {
|
||||
@@ -39,13 +45,11 @@ export const labels: LabelCreateDto[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const labelDefaultValues: TFixturesDefaultValues<Label> = {
|
||||
builtin: false,
|
||||
};
|
||||
|
||||
export const labelFixtures = getFixturesWithDefaultValues<Label>({
|
||||
export const labelFixtures = getFixturesWithDefaultValues<
|
||||
TLabelFixtures['values']
|
||||
>({
|
||||
fixtures: labels,
|
||||
defaultValues: labelDefaultValues,
|
||||
defaultValues: contentLabelDefaultValues,
|
||||
});
|
||||
|
||||
export const installLabelFixtures = async () => {
|
||||
|
||||
22
api/src/utils/test/fixtures/nlpsample.ts
vendored
22
api/src/utils/test/fixtures/nlpsample.ts
vendored
@@ -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.
|
||||
@@ -13,11 +13,18 @@ import { NlpSample, NlpSampleModel } from '@/nlp/schemas/nlp-sample.schema';
|
||||
import { NlpSampleState } from '@/nlp/schemas/types';
|
||||
|
||||
import { getFixturesWithDefaultValues } from '../defaultValues';
|
||||
import { TFixturesDefaultValues } from '../types';
|
||||
import { FixturesTypeBuilder } from '../types';
|
||||
|
||||
import { installLanguageFixtures } from './language';
|
||||
|
||||
const nlpSamples: NlpSampleCreateDto[] = [
|
||||
type TNlpSampleFixtures = FixturesTypeBuilder<NlpSample, NlpSampleCreateDto>;
|
||||
|
||||
export const nlpSampleDefaultValues: TNlpSampleFixtures['defaultValues'] = {
|
||||
type: NlpSampleState.train,
|
||||
trained: false,
|
||||
};
|
||||
|
||||
const nlpSamples: TNlpSampleFixtures['values'][] = [
|
||||
{
|
||||
text: 'yess',
|
||||
language: '0',
|
||||
@@ -38,12 +45,9 @@ const nlpSamples: NlpSampleCreateDto[] = [
|
||||
},
|
||||
];
|
||||
|
||||
export const nlpSampleDefaultValues: TFixturesDefaultValues<NlpSample> = {
|
||||
type: NlpSampleState.train,
|
||||
trained: false,
|
||||
};
|
||||
|
||||
export const nlpSampleFixtures = getFixturesWithDefaultValues<NlpSample>({
|
||||
export const nlpSampleFixtures = getFixturesWithDefaultValues<
|
||||
TNlpSampleFixtures['values']
|
||||
>({
|
||||
fixtures: nlpSamples,
|
||||
defaultValues: nlpSampleDefaultValues,
|
||||
});
|
||||
|
||||
34
api/src/utils/test/fixtures/subscriber.ts
vendored
34
api/src/utils/test/fixtures/subscriber.ts
vendored
@@ -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.
|
||||
@@ -12,12 +12,23 @@ import { SubscriberCreateDto } from '@/chat/dto/subscriber.dto';
|
||||
import { Subscriber, SubscriberModel } from '@/chat/schemas/subscriber.schema';
|
||||
|
||||
import { getFixturesWithDefaultValues } from '../defaultValues';
|
||||
import { TFixturesDefaultValues } from '../types';
|
||||
import { FixturesTypeBuilder } from '../types';
|
||||
|
||||
import { installLabelFixtures } from './label';
|
||||
import { installUserFixtures } from './user';
|
||||
|
||||
const subscribers: SubscriberCreateDto[] = [
|
||||
type TSubscriberFixtures = FixturesTypeBuilder<Subscriber, SubscriberCreateDto>;
|
||||
|
||||
export const subscriberDefaultValues: TSubscriberFixtures['defaultValues'] = {
|
||||
timezone: 0,
|
||||
assignedTo: null,
|
||||
assignedAt: null,
|
||||
lastvisit: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
||||
retainedFrom: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
||||
avatar: null,
|
||||
};
|
||||
|
||||
const subscribers: TSubscriberFixtures['values'][] = [
|
||||
{
|
||||
foreign_id: 'foreign-id-messenger',
|
||||
first_name: 'Jhon',
|
||||
@@ -30,7 +41,6 @@ const subscribers: SubscriberCreateDto[] = [
|
||||
name: 'messenger-channel',
|
||||
},
|
||||
labels: [],
|
||||
assignedAt: null,
|
||||
lastvisit: new Date('2020-01-01T20:40:03.249Z'),
|
||||
retainedFrom: new Date('2020-01-01T20:40:03.249Z'),
|
||||
},
|
||||
@@ -46,7 +56,6 @@ const subscribers: SubscriberCreateDto[] = [
|
||||
name: 'web-channel',
|
||||
},
|
||||
labels: [],
|
||||
assignedAt: null,
|
||||
lastvisit: new Date('2021-01-01T20:40:03.249Z'),
|
||||
retainedFrom: new Date('2021-01-02T20:40:03.249Z'),
|
||||
},
|
||||
@@ -62,7 +71,6 @@ const subscribers: SubscriberCreateDto[] = [
|
||||
name: 'web-channel',
|
||||
},
|
||||
labels: [],
|
||||
assignedAt: null,
|
||||
lastvisit: new Date('2022-01-01T20:40:03.249Z'),
|
||||
retainedFrom: new Date('2022-01-02T20:40:03.249Z'),
|
||||
},
|
||||
@@ -78,22 +86,14 @@ const subscribers: SubscriberCreateDto[] = [
|
||||
name: 'web-channel',
|
||||
},
|
||||
labels: [],
|
||||
assignedAt: null,
|
||||
lastvisit: new Date('2024-01-01T20:40:03.249Z'),
|
||||
retainedFrom: new Date('2024-01-02T20:40:03.249Z'),
|
||||
},
|
||||
];
|
||||
|
||||
export const subscriberDefaultValues: TFixturesDefaultValues<Subscriber> = {
|
||||
timezone: 0,
|
||||
assignedTo: null,
|
||||
assignedAt: null,
|
||||
lastvisit: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
||||
retainedFrom: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
||||
avatar: null,
|
||||
};
|
||||
|
||||
export const subscriberFixtures = getFixturesWithDefaultValues<Subscriber>({
|
||||
export const subscriberFixtures = getFixturesWithDefaultValues<
|
||||
TSubscriberFixtures['values']
|
||||
>({
|
||||
fixtures: subscribers,
|
||||
defaultValues: subscriberDefaultValues,
|
||||
});
|
||||
|
||||
@@ -95,6 +95,7 @@ export const baseBlockInstance = {
|
||||
category: undefined,
|
||||
previousBlocks: [],
|
||||
trigger_channels: [],
|
||||
nextBlocks: [],
|
||||
...modelInstance,
|
||||
};
|
||||
|
||||
@@ -103,7 +104,8 @@ export const blockEmpty = {
|
||||
name: 'Empty',
|
||||
patterns: [],
|
||||
message: [''],
|
||||
} as unknown as BlockFull;
|
||||
nextBlocks: [],
|
||||
};
|
||||
|
||||
// Translation Data
|
||||
export const textResult = ['Hi back !'];
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import { BaseSchema } from '../generics/base-schema';
|
||||
|
||||
type TOptionalPropertyOf<T> = Exclude<
|
||||
export type TOptionalPropertyOf<T> = Exclude<
|
||||
{
|
||||
[K in keyof T]: T extends Record<K, T[K]> ? never : K;
|
||||
}[keyof T],
|
||||
@@ -23,3 +23,25 @@ export type TFixtures<T> = Omit<T, keyof BaseSchema> & {
|
||||
export type TFixturesDefaultValues<T, S = TFixtures<T>> = {
|
||||
[key in TOptionalPropertyOf<S>]?: S[key];
|
||||
} & { createdAt?: BaseSchema['createdAt'] };
|
||||
|
||||
export type TOptionalPropertyFrom<O extends object, O1 extends object> = Pick<
|
||||
O1,
|
||||
Exclude<keyof O1, keyof O>
|
||||
> &
|
||||
Pick<O, Exclude<keyof O, keyof O1>>;
|
||||
|
||||
export type OptionalProperties<T, K extends keyof T> = Omit<
|
||||
T,
|
||||
K | keyof BaseSchema
|
||||
> &
|
||||
Partial<Pick<T, K>>;
|
||||
|
||||
export type FixturesTypeBuilder<
|
||||
S extends object,
|
||||
D extends object,
|
||||
DO = TFixturesDefaultValues<D>,
|
||||
U = Partial<TFixtures<TOptionalPropertyFrom<D, S>>>,
|
||||
> = {
|
||||
defaultValues: DO & U;
|
||||
values: OptionalProperties<S, keyof S & keyof (DO & U)>;
|
||||
};
|
||||
|
||||
24
api/src/utils/types/dto.types.ts
Normal file
24
api/src/utils/types/dto.types.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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).
|
||||
*/
|
||||
|
||||
export enum DtoAction {
|
||||
Create = 'create',
|
||||
Read = 'read',
|
||||
Update = 'update',
|
||||
Delete = 'delete',
|
||||
}
|
||||
|
||||
export type DtoConfig<
|
||||
C extends Partial<Record<DtoAction, object>> = Partial<
|
||||
Record<DtoAction, object>
|
||||
>,
|
||||
> = C;
|
||||
|
||||
export type DtoInfer<K extends keyof Dto, Dto, I> = Dto[K] extends object
|
||||
? Dto[K]
|
||||
: I;
|
||||
Reference in New Issue
Block a user