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:
@@ -30,6 +30,34 @@ Theses are just some examples of the hidden costs that are not so apparent from
|
||||
|
||||
* Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes.
|
||||
|
||||
|
||||
#### **How can i create my first contribution ?**
|
||||
|
||||
- **Find an Issue:**
|
||||
Start by finding an issue to work on. You can either create a new GitHub issue or pick one that has been assigned to you.
|
||||
|
||||
- **Create a Branch:**
|
||||
Create a new branch for your work. Use a descriptive name that reflects the issue or feature you're addressing (e.g., fix/login-bug or add/feature-x).
|
||||
|
||||
- **Make Changes:**
|
||||
Write or fix the code in your branch. Ensure your changes align with the project's coding standards and guidelines.
|
||||
|
||||
- **Push Changes:**
|
||||
Once your changes are ready, push your branch to GitHub.
|
||||
|
||||
- **Open a Pull Request (PR):**
|
||||
Create a pull request (PR) from your branch. Include a clear and concise description of your changes, explaining what the PR does and why it’s needed. Make sure to reference the related issue (e.g., "Fixes #123").
|
||||
Note: At least two reviewers are required to approve the PR before it can be merged.
|
||||
|
||||
- **Review Process:**
|
||||
Team members will review your code, provide feedback, and suggest improvements. Be open to constructive criticism and ready to iterate on your work.
|
||||
|
||||
- **Address Feedback:**
|
||||
Make any necessary changes based on the feedback. Once you’ve addressed the comments, tag the reviewers to let them know your updates are ready for another review.
|
||||
|
||||
- **Merge:**
|
||||
Once your PR is approved by at least two reviewers, it will be merged into the main project. Congratulations, your code is now part of the project!
|
||||
|
||||
#### **Do you have questions about the source code?**
|
||||
|
||||
* Ask any question about how to use Hexabot in our [Discord Channel](https://discord.gg/rNb9t2MFkG).
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
botstatsFixtures,
|
||||
installBotStatsFixtures,
|
||||
@@ -19,6 +16,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { BotStatsRepository } from '../repositories/bot-stats.repository';
|
||||
import { BotStatsModel, BotStatsType } from '../schemas/bot-stats.schema';
|
||||
@@ -30,25 +28,18 @@ describe('BotStatsController', () => {
|
||||
let botStatsController: BotStatsController;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [BotStatsController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installBotStatsFixtures),
|
||||
MongooseModule.forFeature([BotStatsModel]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
BotStatsService,
|
||||
BotStatsRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
botStatsController = module.get<BotStatsController>(BotStatsController);
|
||||
providers: [BotStatsService, BotStatsRepository],
|
||||
});
|
||||
[botStatsController] = await getMocks([BotStatsController]);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule, getModelToken } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { getModelToken, MongooseModule } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
botstatsFixtures,
|
||||
installBotStatsFixtures,
|
||||
@@ -20,6 +17,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import {
|
||||
BotStats,
|
||||
@@ -34,20 +32,20 @@ describe('BotStatsRepository', () => {
|
||||
let botStatsModel: Model<BotStats>;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installBotStatsFixtures),
|
||||
MongooseModule.forFeature([BotStatsModel]),
|
||||
],
|
||||
providers: [LoggerService, BotStatsRepository, EventEmitter2],
|
||||
}).compile();
|
||||
botStatsRepository = module.get<BotStatsRepository>(BotStatsRepository);
|
||||
botStatsModel = module.get<Model<BotStats>>(getModelToken('BotStats'));
|
||||
providers: [BotStatsRepository],
|
||||
});
|
||||
[botStatsRepository, botStatsModel] = await getMocks([
|
||||
BotStatsRepository,
|
||||
getModelToken(BotStats.name),
|
||||
]);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
@@ -17,11 +16,8 @@ import { BotStats, BotStatsType } from '../schemas/bot-stats.schema';
|
||||
|
||||
@Injectable()
|
||||
export class BotStatsRepository extends BaseRepository<BotStats> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(BotStats.name) readonly model: Model<BotStats>,
|
||||
) {
|
||||
super(eventEmitter, model, BotStats);
|
||||
constructor(@InjectModel(BotStats.name) readonly model: Model<BotStats>) {
|
||||
super(model, BotStats);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
botstatsFixtures,
|
||||
installBotStatsFixtures,
|
||||
@@ -19,6 +16,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { BotStatsRepository } from '../repositories/bot-stats.repository';
|
||||
import { BotStatsModel, BotStatsType } from '../schemas/bot-stats.schema';
|
||||
@@ -29,24 +27,17 @@ describe('BotStatsService', () => {
|
||||
let botStatsService: BotStatsService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installBotStatsFixtures),
|
||||
MongooseModule.forFeature([BotStatsModel]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
BotStatsService,
|
||||
BotStatsRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
botStatsService = module.get<BotStatsService>(BotStatsService);
|
||||
providers: [BotStatsService, BotStatsRepository],
|
||||
});
|
||||
[botStatsService] = await getMocks([BotStatsService]);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2, OnEvent } from '@nestjs/event-emitter';
|
||||
import { OnEvent } from '@nestjs/event-emitter';
|
||||
|
||||
import { Subscriber } from '@/chat/schemas/subscriber.schema';
|
||||
import { config } from '@/config';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { BotStatsRepository } from '../repositories/bot-stats.repository';
|
||||
@@ -19,11 +18,7 @@ import { BotStats, BotStatsType } from '../schemas/bot-stats.schema';
|
||||
|
||||
@Injectable()
|
||||
export class BotStatsService extends BaseService<BotStats> {
|
||||
constructor(
|
||||
readonly repository: BotStatsRepository,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
constructor(readonly repository: BotStatsRepository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@@ -98,8 +93,9 @@ export class BotStatsService extends BaseService<BotStats> {
|
||||
) {
|
||||
this.eventEmitter.emit(
|
||||
'hook:stats:entry',
|
||||
'retention',
|
||||
BotStatsType.retention,
|
||||
'Retentioned users',
|
||||
subscriber,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -111,7 +107,11 @@ export class BotStatsService extends BaseService<BotStats> {
|
||||
* @param name - The name or identifier of the statistics entry (e.g., a specific feature or component being tracked).
|
||||
*/
|
||||
@OnEvent('hook:stats:entry')
|
||||
async handleStatEntry(type: BotStatsType, name: string): Promise<void> {
|
||||
async handleStatEntry(
|
||||
type: BotStatsType,
|
||||
name: string,
|
||||
_subscriber: Subscriber,
|
||||
): Promise<void> {
|
||||
const day = new Date();
|
||||
day.setMilliseconds(0);
|
||||
day.setSeconds(0);
|
||||
|
||||
@@ -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,15 +13,11 @@ import { Request } from 'express';
|
||||
import { Session as ExpressSession } from 'express-session';
|
||||
|
||||
import { AppService } from './app.service';
|
||||
import { LoggerService } from './logger/logger.service';
|
||||
import { Roles } from './utils/decorators/roles.decorator';
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
constructor(
|
||||
private readonly appService: AppService,
|
||||
private readonly logger: LoggerService,
|
||||
) {}
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Roles('public')
|
||||
@Get()
|
||||
|
||||
@@ -35,6 +35,7 @@ import { ChannelModule } from './channel/channel.module';
|
||||
import { ChatModule } from './chat/chat.module';
|
||||
import { CmsModule } from './cms/cms.module';
|
||||
import { config } from './config';
|
||||
import { ExtensionModule } from './extension/extension.module';
|
||||
import extraModules from './extra';
|
||||
import { HelperModule } from './helper/helper.module';
|
||||
import { I18nModule } from './i18n/i18n.module';
|
||||
@@ -152,6 +153,7 @@ const i18nOptions: I18nOptions = {
|
||||
max: config.cache.max,
|
||||
}),
|
||||
MigrationModule,
|
||||
ExtensionModule,
|
||||
...extraModules,
|
||||
],
|
||||
controllers: [AppController],
|
||||
|
||||
@@ -11,9 +11,7 @@ import fs from 'fs';
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { BadRequestException } from '@nestjs/common/exceptions';
|
||||
import { NotFoundException } from '@nestjs/common/exceptions/not-found.exception';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { Request } from 'express';
|
||||
|
||||
import LocalStorageHelper from '@/extensions/helpers/local-storage/index.helper';
|
||||
@@ -40,6 +38,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { attachment, attachmentFile } from '../mocks/attachment.mock';
|
||||
import { AttachmentRepository } from '../repositories/attachment.repository';
|
||||
@@ -59,10 +58,9 @@ describe('AttachmentController', () => {
|
||||
let attachmentToDelete: Attachment;
|
||||
let helperService: HelperService;
|
||||
let settingService: SettingService;
|
||||
let loggerService: LoggerService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks, resolveMocks } = await buildTestingMocks({
|
||||
controllers: [AttachmentController],
|
||||
imports: [
|
||||
rootMongooseTestModule(async () => {
|
||||
@@ -84,8 +82,6 @@ describe('AttachmentController', () => {
|
||||
SettingRepository,
|
||||
ModelService,
|
||||
ModelRepository,
|
||||
LoggerService,
|
||||
EventEmitter2,
|
||||
SettingSeeder,
|
||||
SettingService,
|
||||
HelperService,
|
||||
@@ -98,18 +94,20 @@ describe('AttachmentController', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
attachmentController =
|
||||
module.get<AttachmentController>(AttachmentController);
|
||||
attachmentService = module.get<AttachmentService>(AttachmentService);
|
||||
});
|
||||
[attachmentController, attachmentService, helperService, settingService] =
|
||||
await getMocks([
|
||||
AttachmentController,
|
||||
AttachmentService,
|
||||
HelperService,
|
||||
SettingService,
|
||||
]);
|
||||
const [loggerService] = await resolveMocks([LoggerService]);
|
||||
|
||||
attachmentToDelete = (await attachmentService.findOne({
|
||||
name: 'store1.jpg',
|
||||
}))!;
|
||||
|
||||
helperService = module.get<HelperService>(HelperService);
|
||||
settingService = module.get<SettingService>(SettingService);
|
||||
loggerService = await module.resolve<LoggerService>(LoggerService);
|
||||
|
||||
helperService.register(
|
||||
new LocalStorageHelper(settingService, helperService, loggerService),
|
||||
);
|
||||
|
||||
@@ -30,7 +30,6 @@ import { diskStorage, memoryStorage } from 'multer';
|
||||
|
||||
import { config } from '@/config';
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { Roles } from '@/utils/decorators/roles.decorator';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
@@ -52,10 +51,7 @@ import { AttachmentAccess, AttachmentCreatedByRef } from '../types';
|
||||
@Controller('attachment')
|
||||
@UseGuards(AttachmentGuard)
|
||||
export class AttachmentController extends BaseController<Attachment> {
|
||||
constructor(
|
||||
private readonly attachmentService: AttachmentService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
constructor(private readonly attachmentService: AttachmentService) {
|
||||
super(attachmentService);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
*/
|
||||
|
||||
import { BadRequestException, ExecutionContext } from '@nestjs/common';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { Model } from '@/user/schemas/model.schema';
|
||||
import { Permission } from '@/user/schemas/permission.schema';
|
||||
import { ModelService } from '@/user/services/model.service';
|
||||
import { PermissionService } from '@/user/services/permission.service';
|
||||
import { Action } from '@/user/types/action.type';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { attachment } from '../mocks/attachment.mock';
|
||||
import { Attachment } from '../schemas/attachment.schema';
|
||||
@@ -29,7 +29,7 @@ describe('AttachmentGuard', () => {
|
||||
let attachmentService: AttachmentService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
providers: [
|
||||
AttachmentGuard,
|
||||
{
|
||||
@@ -45,12 +45,15 @@ describe('AttachmentGuard', () => {
|
||||
useValue: { findOne: jest.fn() },
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
});
|
||||
|
||||
guard = module.get<AttachmentGuard>(AttachmentGuard);
|
||||
permissionService = module.get<PermissionService>(PermissionService);
|
||||
modelService = module.get<ModelService>(ModelService);
|
||||
attachmentService = module.get<AttachmentService>(AttachmentService);
|
||||
[guard, permissionService, modelService, attachmentService] =
|
||||
await getMocks([
|
||||
AttachmentGuard,
|
||||
PermissionService,
|
||||
ModelService,
|
||||
AttachmentService,
|
||||
]);
|
||||
});
|
||||
|
||||
describe('canActivate', () => {
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
@@ -17,10 +16,7 @@ import { Attachment } from '../schemas/attachment.schema';
|
||||
|
||||
@Injectable()
|
||||
export class AttachmentRepository extends BaseRepository<Attachment, never> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Attachment.name) readonly model: Model<Attachment>,
|
||||
) {
|
||||
super(eventEmitter, model, Attachment);
|
||||
constructor(@InjectModel(Attachment.name) readonly model: Model<Attachment>) {
|
||||
super(model, Attachment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import { Injectable, Optional, StreamableFile } from '@nestjs/common';
|
||||
|
||||
import { HelperService } from '@/helper/helper.service';
|
||||
import { HelperType } from '@/helper/types';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
import { AttachmentMetadataDto } from '../dto/attachment.dto';
|
||||
@@ -23,7 +22,6 @@ import { Attachment } from '../schemas/attachment.schema';
|
||||
export class AttachmentService extends BaseService<Attachment> {
|
||||
constructor(
|
||||
readonly repository: AttachmentRepository,
|
||||
private readonly logger: LoggerService,
|
||||
@Optional() private readonly helperService: HelperService,
|
||||
) {
|
||||
super(repository);
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { NotFoundException } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
@@ -22,7 +20,6 @@ import { LanguageRepository } from '@/i18n/repositories/language.repository';
|
||||
import { LanguageModel } from '@/i18n/schemas/language.schema';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LanguageService } from '@/i18n/services/language.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { PluginService } from '@/plugins/plugins.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import { InvitationRepository } from '@/user/repositories/invitation.repository';
|
||||
@@ -46,6 +43,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { BlockCreateDto, BlockUpdateDto } from '../dto/block.dto';
|
||||
import { BlockRepository } from '../repositories/block.repository';
|
||||
@@ -53,6 +51,7 @@ import { CategoryRepository } from '../repositories/category.repository';
|
||||
import { LabelRepository } from '../repositories/label.repository';
|
||||
import { Block, BlockModel } from '../schemas/block.schema';
|
||||
import { LabelModel } from '../schemas/label.schema';
|
||||
import { PayloadType } from '../schemas/types/button';
|
||||
import { BlockService } from '../services/block.service';
|
||||
import { CategoryService } from '../services/category.service';
|
||||
import { LabelService } from '../services/label.service';
|
||||
@@ -79,7 +78,7 @@ describe('BlockController', () => {
|
||||
];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [BlockController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installBlockFixtures),
|
||||
@@ -117,7 +116,6 @@ describe('BlockController', () => {
|
||||
PermissionService,
|
||||
LanguageService,
|
||||
PluginService,
|
||||
LoggerService,
|
||||
{
|
||||
provide: I18nService,
|
||||
useValue: {
|
||||
@@ -133,7 +131,6 @@ describe('BlockController', () => {
|
||||
getSettings: jest.fn(() => ({})),
|
||||
},
|
||||
},
|
||||
EventEmitter2,
|
||||
{
|
||||
provide: CACHE_MANAGER,
|
||||
useValue: {
|
||||
@@ -143,10 +140,12 @@ describe('BlockController', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
blockController = module.get<BlockController>(BlockController);
|
||||
blockService = module.get<BlockService>(BlockService);
|
||||
categoryService = module.get<CategoryService>(CategoryService);
|
||||
});
|
||||
[blockController, blockService, categoryService] = await getMocks([
|
||||
BlockController,
|
||||
BlockService,
|
||||
CategoryService,
|
||||
]);
|
||||
category = (await categoryService.findOne({ label: 'default' }))!;
|
||||
block = (await blockService.findOne({ name: 'first' }))!;
|
||||
blockToDelete = (await blockService.findOne({ name: 'buttons' }))!;
|
||||
@@ -336,4 +335,56 @@ describe('BlockController', () => {
|
||||
).rejects.toThrow(getUpdateOneError(Block.name, blockToDelete.id));
|
||||
});
|
||||
});
|
||||
|
||||
it('should update block trigger to postback menu', async () => {
|
||||
jest.spyOn(blockService, 'updateOne');
|
||||
const updateBlock: BlockUpdateDto = {
|
||||
patterns: [
|
||||
{
|
||||
label: 'postback123',
|
||||
value: 'postback123',
|
||||
type: PayloadType.menu,
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = await blockController.updateOne(block.id, updateBlock);
|
||||
expect(blockService.updateOne).toHaveBeenCalledWith(block.id, updateBlock);
|
||||
|
||||
expect(
|
||||
result.patterns.find(
|
||||
(pattern) =>
|
||||
typeof pattern === 'object' &&
|
||||
'type' in pattern &&
|
||||
pattern.type === PayloadType.menu &&
|
||||
pattern,
|
||||
),
|
||||
).toBeDefined();
|
||||
expect(result.patterns).toEqual(updateBlock.patterns);
|
||||
});
|
||||
|
||||
it('should update the block trigger with a content payloadType payload', async () => {
|
||||
jest.spyOn(blockService, 'updateOne');
|
||||
const updateBlock: BlockUpdateDto = {
|
||||
patterns: [
|
||||
{
|
||||
label: 'Content label',
|
||||
value: 'Content value',
|
||||
type: PayloadType.content,
|
||||
},
|
||||
],
|
||||
};
|
||||
const result = await blockController.updateOne(block.id, updateBlock);
|
||||
expect(blockService.updateOne).toHaveBeenCalledWith(block.id, updateBlock);
|
||||
|
||||
expect(
|
||||
result.patterns.find(
|
||||
(pattern) =>
|
||||
typeof pattern === 'object' &&
|
||||
'type' in pattern &&
|
||||
pattern.type === PayloadType.content &&
|
||||
pattern,
|
||||
),
|
||||
).toBeDefined();
|
||||
expect(result.patterns).toEqual(updateBlock.patterns);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseBlockPlugin } from '@/plugins/base-block-plugin';
|
||||
import { PluginService } from '@/plugins/plugins.service';
|
||||
import { PluginName, PluginType } from '@/plugins/types';
|
||||
@@ -57,7 +56,6 @@ export class BlockController extends BaseController<
|
||||
> {
|
||||
constructor(
|
||||
private readonly blockService: BlockService,
|
||||
private readonly logger: LoggerService,
|
||||
private readonly categoryService: CategoryService,
|
||||
private readonly labelService: LabelService,
|
||||
private readonly userService: UserService,
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
*/
|
||||
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
@@ -18,7 +16,6 @@ import { ContentRepository } from '@/cms/repositories/content.repository';
|
||||
import { ContentModel } from '@/cms/schemas/content.schema';
|
||||
import { ContentService } from '@/cms/services/content.service';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { PluginService } from '@/plugins/plugins.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import {
|
||||
@@ -31,6 +28,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { CategoryCreateDto, CategoryUpdateDto } from '../dto/category.dto';
|
||||
import { BlockRepository } from '../repositories/block.repository';
|
||||
@@ -50,7 +48,7 @@ describe('CategoryController', () => {
|
||||
let categoryToDelete: Category;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [CategoryController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installCategoryFixtures),
|
||||
@@ -75,7 +73,6 @@ describe('CategoryController', () => {
|
||||
provide: PluginService,
|
||||
useValue: {},
|
||||
},
|
||||
LoggerService,
|
||||
{
|
||||
provide: I18nService,
|
||||
useValue: {
|
||||
@@ -97,11 +94,12 @@ describe('CategoryController', () => {
|
||||
findOne: jest.fn(),
|
||||
},
|
||||
},
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
categoryService = module.get<CategoryService>(CategoryService);
|
||||
categoryController = module.get<CategoryController>(CategoryController);
|
||||
});
|
||||
[categoryService, categoryController] = await getMocks([
|
||||
CategoryService,
|
||||
CategoryController,
|
||||
]);
|
||||
category = (await categoryService.findOne({
|
||||
label: 'test category 1',
|
||||
})) as Category;
|
||||
@@ -111,6 +109,7 @@ describe('CategoryController', () => {
|
||||
});
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
describe('findPage', () => {
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
@@ -38,10 +37,7 @@ import { CategoryService } from '../services/category.service';
|
||||
@UseInterceptors(CsrfInterceptor)
|
||||
@Controller('category')
|
||||
export class CategoryController extends BaseController<Category> {
|
||||
constructor(
|
||||
private readonly categoryService: CategoryService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
constructor(private readonly categoryService: CategoryService) {
|
||||
super(categoryService);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -7,11 +7,8 @@
|
||||
*/
|
||||
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { getUpdateOneError } from '@/utils/test/errors/messages';
|
||||
import {
|
||||
contextVarFixtures,
|
||||
@@ -23,6 +20,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import {
|
||||
ContextVarCreateDto,
|
||||
@@ -41,22 +39,18 @@ describe('ContextVarController', () => {
|
||||
let contextVarToDelete: ContextVar;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [ContextVarController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installContextVarFixtures),
|
||||
MongooseModule.forFeature([ContextVarModel]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
ContextVarService,
|
||||
ContextVarRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
contextVarController =
|
||||
module.get<ContextVarController>(ContextVarController);
|
||||
contextVarService = module.get<ContextVarService>(ContextVarService);
|
||||
providers: [ContextVarService, ContextVarRepository],
|
||||
});
|
||||
[contextVarController, contextVarService] = await getMocks([
|
||||
ContextVarController,
|
||||
ContextVarService,
|
||||
]);
|
||||
contextVar = (await contextVarService.findOne({
|
||||
label: 'test context var 1',
|
||||
}))!;
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
@@ -41,10 +40,7 @@ import { ContextVarService } from '../services/context-var.service';
|
||||
@UseInterceptors(CsrfInterceptor)
|
||||
@Controller('contextvar')
|
||||
export class ContextVarController extends BaseController<ContextVar> {
|
||||
constructor(
|
||||
private readonly contextVarService: ContextVarService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
constructor(private readonly contextVarService: ContextVarService) {
|
||||
super(contextVarService);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,14 +7,11 @@
|
||||
*/
|
||||
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { InvitationRepository } from '@/user/repositories/invitation.repository';
|
||||
import { RoleRepository } from '@/user/repositories/role.repository';
|
||||
import { UserRepository } from '@/user/repositories/user.repository';
|
||||
@@ -35,6 +32,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { LabelCreateDto, LabelUpdateDto } from '../dto/label.dto';
|
||||
import { LabelRepository } from '../repositories/label.repository';
|
||||
@@ -55,7 +53,7 @@ describe('LabelController', () => {
|
||||
let subscriberService: SubscriberService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [LabelController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installSubscriberFixtures),
|
||||
@@ -70,7 +68,6 @@ describe('LabelController', () => {
|
||||
]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
LabelController,
|
||||
LabelService,
|
||||
LabelRepository,
|
||||
@@ -81,14 +78,15 @@ describe('LabelController', () => {
|
||||
InvitationRepository,
|
||||
SubscriberService,
|
||||
SubscriberRepository,
|
||||
EventEmitter2,
|
||||
AttachmentService,
|
||||
AttachmentRepository,
|
||||
],
|
||||
}).compile();
|
||||
labelService = module.get<LabelService>(LabelService);
|
||||
subscriberService = module.get<SubscriberService>(SubscriberService);
|
||||
labelController = module.get<LabelController>(LabelController);
|
||||
});
|
||||
[labelService, subscriberService, labelController] = await getMocks([
|
||||
LabelService,
|
||||
SubscriberService,
|
||||
LabelController,
|
||||
]);
|
||||
label = (await labelService.findOne({ name: 'TEST_TITLE_1' })) as Label;
|
||||
labelToDelete = (await labelService.findOne({
|
||||
name: 'TEST_TITLE_2',
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
@@ -49,10 +48,7 @@ export class LabelController extends BaseController<
|
||||
LabelPopulate,
|
||||
LabelFull
|
||||
> {
|
||||
constructor(
|
||||
private readonly labelService: LabelService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
constructor(private readonly labelService: LabelService) {
|
||||
super(labelService);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -7,9 +7,7 @@
|
||||
*/
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
@@ -19,7 +17,6 @@ import { MenuRepository } from '@/cms/repositories/menu.repository';
|
||||
import { MenuModel } from '@/cms/schemas/menu.schema';
|
||||
import { MenuService } from '@/cms/services/menu.service';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { NlpService } from '@/nlp/services/nlp.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import { InvitationRepository } from '@/user/repositories/invitation.repository';
|
||||
@@ -40,6 +37,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { MessageRepository } from '../repositories/message.repository';
|
||||
import { SubscriberRepository } from '../repositories/subscriber.repository';
|
||||
@@ -64,7 +62,7 @@ describe('MessageController', () => {
|
||||
let allSubscribers: Subscriber[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [MessageController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installMessageFixtures),
|
||||
@@ -116,7 +114,6 @@ describe('MessageController', () => {
|
||||
getSettings: jest.fn(() => ({})),
|
||||
},
|
||||
},
|
||||
EventEmitter2,
|
||||
{
|
||||
provide: CACHE_MANAGER,
|
||||
useValue: {
|
||||
@@ -125,13 +122,15 @@ describe('MessageController', () => {
|
||||
set: jest.fn(),
|
||||
},
|
||||
},
|
||||
LoggerService,
|
||||
],
|
||||
}).compile();
|
||||
messageService = module.get<MessageService>(MessageService);
|
||||
userService = module.get<UserService>(UserService);
|
||||
subscriberService = module.get<SubscriberService>(SubscriberService);
|
||||
messageController = module.get<MessageController>(MessageController);
|
||||
});
|
||||
[messageService, userService, subscriberService, messageController] =
|
||||
await getMocks([
|
||||
MessageService,
|
||||
UserService,
|
||||
SubscriberService,
|
||||
MessageController,
|
||||
]);
|
||||
message = (await messageService.findOne({ mid: 'mid-1' }))!;
|
||||
sender = (await subscriberService.findOne(message.sender!))!;
|
||||
recipient = (await subscriberService.findOne(message.recipient!))!;
|
||||
|
||||
@@ -18,14 +18,12 @@ import {
|
||||
Req,
|
||||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
import { Request } from 'express'; // Import the Express request and response types
|
||||
|
||||
import { ChannelService } from '@/channel/channel.service';
|
||||
import { GenericEventWrapper } from '@/channel/lib/EventWrapper';
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { BaseSchema } from '@/utils/generics/base-schema';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
@@ -65,8 +63,6 @@ export class MessageController extends BaseController<
|
||||
private readonly messageService: MessageService,
|
||||
private readonly subscriberService: SubscriberService,
|
||||
private readonly channelService: ChannelService,
|
||||
private readonly logger: LoggerService,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
) {
|
||||
super(messageService);
|
||||
}
|
||||
@@ -168,7 +164,7 @@ export class MessageController extends BaseController<
|
||||
read: false,
|
||||
delivery: false,
|
||||
};
|
||||
this.eventEmitter.emit('hook:chatbot:sent', sentMessage);
|
||||
this.eventEmitter.emit('hook:chatbot:sent', sentMessage, event);
|
||||
return {
|
||||
success: true,
|
||||
};
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { InvitationRepository } from '@/user/repositories/invitation.repository';
|
||||
import { RoleRepository } from '@/user/repositories/role.repository';
|
||||
import { UserRepository } from '@/user/repositories/user.repository';
|
||||
@@ -32,6 +29,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
import { SocketEventDispatcherService } from '@/websocket/services/socket-event-dispatcher.service';
|
||||
import { WebsocketGateway } from '@/websocket/websocket.gateway';
|
||||
|
||||
@@ -56,7 +54,7 @@ describe('SubscriberController', () => {
|
||||
let allUsers: User[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [SubscriberController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installSubscriberFixtures),
|
||||
@@ -71,7 +69,6 @@ describe('SubscriberController', () => {
|
||||
]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
SubscriberRepository,
|
||||
SubscriberService,
|
||||
LabelService,
|
||||
@@ -83,17 +80,17 @@ describe('SubscriberController', () => {
|
||||
RoleService,
|
||||
RoleRepository,
|
||||
InvitationRepository,
|
||||
EventEmitter2,
|
||||
AttachmentService,
|
||||
AttachmentRepository,
|
||||
],
|
||||
}).compile();
|
||||
subscriberService = module.get<SubscriberService>(SubscriberService);
|
||||
labelService = module.get<LabelService>(LabelService);
|
||||
userService = module.get<UserService>(UserService);
|
||||
|
||||
subscriberController =
|
||||
module.get<SubscriberController>(SubscriberController);
|
||||
});
|
||||
[subscriberService, labelService, userService, subscriberController] =
|
||||
await getMocks([
|
||||
SubscriberService,
|
||||
LabelService,
|
||||
UserService,
|
||||
SubscriberController,
|
||||
]);
|
||||
subscriber = (await subscriberService.findOne({
|
||||
first_name: 'Jhon',
|
||||
}))!;
|
||||
|
||||
@@ -21,7 +21,6 @@ import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { generateInitialsAvatar } from '@/utils/helpers/avatar';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
@@ -50,7 +49,6 @@ export class SubscriberController extends BaseController<
|
||||
constructor(
|
||||
private readonly subscriberService: SubscriberService,
|
||||
private readonly attachmentService: AttachmentService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
super(subscriberService);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule, getModelToken } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
import {
|
||||
@@ -19,6 +17,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { Block, BlockModel } from '../schemas/block.schema';
|
||||
import { Category, CategoryModel } from '../schemas/category.schema';
|
||||
@@ -39,16 +38,18 @@ describe('BlockRepository', () => {
|
||||
let blockValidIds: string[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installBlockFixtures),
|
||||
MongooseModule.forFeature([BlockModel, CategoryModel, LabelModel]),
|
||||
],
|
||||
providers: [BlockRepository, CategoryRepository, EventEmitter2],
|
||||
}).compile();
|
||||
blockRepository = module.get<BlockRepository>(BlockRepository);
|
||||
categoryRepository = module.get<CategoryRepository>(CategoryRepository);
|
||||
blockModel = module.get<Model<Block>>(getModelToken('Block'));
|
||||
providers: [BlockRepository, CategoryRepository],
|
||||
});
|
||||
[blockRepository, categoryRepository, blockModel] = await getMocks([
|
||||
BlockRepository,
|
||||
CategoryRepository,
|
||||
getModelToken(Block.name),
|
||||
]);
|
||||
validIds = ['64abc1234def567890fedcba', '64abc1234def567890fedcbc'];
|
||||
validCategory = '64def5678abc123490fedcba';
|
||||
|
||||
|
||||
@@ -6,8 +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 { Injectable, Optional } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import {
|
||||
Document,
|
||||
@@ -18,7 +17,6 @@ import {
|
||||
UpdateWithAggregationPipeline,
|
||||
} from 'mongoose';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
@@ -37,12 +35,8 @@ export class BlockRepository extends BaseRepository<
|
||||
BlockFull,
|
||||
BlockDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Block.name) readonly model: Model<Block>,
|
||||
@Optional() private readonly logger?: LoggerService,
|
||||
) {
|
||||
super(eventEmitter, model, Block, BLOCK_POPULATE, BlockFull);
|
||||
constructor(@InjectModel(Block.name) readonly model: Model<Block>) {
|
||||
super(model, Block, BLOCK_POPULATE, BlockFull);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { ForbiddenException, Injectable, Optional } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Document, Model, Query } from 'mongoose';
|
||||
|
||||
@@ -28,11 +27,10 @@ export class CategoryRepository extends BaseRepository<
|
||||
private readonly blockService: BlockService;
|
||||
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Category.name) readonly model: Model<Category>,
|
||||
@Optional() blockService?: BlockService,
|
||||
) {
|
||||
super(eventEmitter, model, Category);
|
||||
super(model, Category);
|
||||
this.blockService = blockService!;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,7 +12,6 @@ import {
|
||||
NotFoundException,
|
||||
Optional,
|
||||
} from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Document, Model, Query } from 'mongoose';
|
||||
|
||||
@@ -33,11 +32,10 @@ export class ContextVarRepository extends BaseRepository<
|
||||
private readonly blockService: BlockService;
|
||||
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(ContextVar.name) readonly model: Model<ContextVar>,
|
||||
@Optional() blockService?: BlockService,
|
||||
) {
|
||||
super(eventEmitter, model, ContextVar);
|
||||
super(model, ContextVar);
|
||||
if (blockService) this.blockService = blockService;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
@@ -29,16 +28,9 @@ export class ConversationRepository extends BaseRepository<
|
||||
ConversationDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Conversation.name) readonly model: Model<Conversation>,
|
||||
) {
|
||||
super(
|
||||
eventEmitter,
|
||||
model,
|
||||
Conversation,
|
||||
CONVERSATION_POPULATE,
|
||||
ConversationFull,
|
||||
);
|
||||
super(model, Conversation, CONVERSATION_POPULATE, ConversationFull);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,12 +6,9 @@
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule, getModelToken } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { labelFixtures } from '@/utils/test/fixtures/label';
|
||||
import { installSubscriberFixtures } from '@/utils/test/fixtures/subscriber';
|
||||
import { getPageQuery } from '@/utils/test/pagination';
|
||||
@@ -20,6 +17,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { Label, LabelFull, LabelModel } from '../schemas/label.schema';
|
||||
import { Subscriber, SubscriberModel } from '../schemas/subscriber.schema';
|
||||
@@ -34,22 +32,18 @@ describe('LabelRepository', () => {
|
||||
let users: Subscriber[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installSubscriberFixtures),
|
||||
MongooseModule.forFeature([LabelModel, SubscriberModel]),
|
||||
],
|
||||
providers: [
|
||||
LabelRepository,
|
||||
SubscriberRepository,
|
||||
EventEmitter2,
|
||||
LoggerService,
|
||||
],
|
||||
}).compile();
|
||||
labelRepository = module.get<LabelRepository>(LabelRepository);
|
||||
subscriberRepository =
|
||||
module.get<SubscriberRepository>(SubscriberRepository);
|
||||
labelModel = module.get<Model<Label>>(getModelToken('Label'));
|
||||
providers: [LabelRepository, SubscriberRepository],
|
||||
});
|
||||
[labelRepository, subscriberRepository, labelModel] = await getMocks([
|
||||
LabelRepository,
|
||||
SubscriberRepository,
|
||||
getModelToken(Label.name),
|
||||
]);
|
||||
users = await subscriberRepository.findAll();
|
||||
});
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Document, Model, Query } from 'mongoose';
|
||||
|
||||
@@ -30,11 +29,8 @@ export class LabelRepository extends BaseRepository<
|
||||
LabelFull,
|
||||
LabelDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Label.name) readonly model: Model<Label>,
|
||||
) {
|
||||
super(eventEmitter, model, Label, LABEL_POPULATE, LabelFull);
|
||||
constructor(@InjectModel(Label.name) readonly model: Model<Label>) {
|
||||
super(model, Label, LABEL_POPULATE, LabelFull);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule, getModelToken } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
import { UserRepository } from '@/user/repositories/user.repository';
|
||||
@@ -22,6 +20,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { Message, MessageModel } from '../schemas/message.schema';
|
||||
import { SubscriberModel } from '../schemas/subscriber.schema';
|
||||
@@ -37,23 +36,20 @@ describe('MessageRepository', () => {
|
||||
let messageModel: Model<Message>;
|
||||
|
||||
beforeAll(async () => {
|
||||
const testModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installMessageFixtures),
|
||||
MongooseModule.forFeature([MessageModel, SubscriberModel, UserModel]),
|
||||
],
|
||||
providers: [
|
||||
providers: [MessageRepository, SubscriberRepository, UserRepository],
|
||||
});
|
||||
[messageRepository, userRepository, subscriberRepository, messageModel] =
|
||||
await getMocks([
|
||||
MessageRepository,
|
||||
SubscriberRepository,
|
||||
UserRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
messageRepository = testModule.get<MessageRepository>(MessageRepository);
|
||||
userRepository = testModule.get<UserRepository>(UserRepository);
|
||||
subscriberRepository =
|
||||
testModule.get<SubscriberRepository>(SubscriberRepository);
|
||||
messageModel = testModule.get<Model<Message>>(getModelToken('Message'));
|
||||
SubscriberRepository,
|
||||
getModelToken(Message.name),
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
@@ -28,12 +27,8 @@ export class MessageRepository extends BaseRepository<
|
||||
MessagePopulate,
|
||||
MessageFull
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Message.name) readonly model: Model<AnyMessage>,
|
||||
) {
|
||||
constructor(@InjectModel(Message.name) readonly model: Model<AnyMessage>) {
|
||||
super(
|
||||
eventEmitter,
|
||||
model,
|
||||
Message as new () => AnyMessage,
|
||||
MESSAGE_POPULATE,
|
||||
|
||||
@@ -6,9 +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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule, getModelToken } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
@@ -17,7 +15,6 @@ import {
|
||||
AttachmentModel,
|
||||
} from '@/attachment/schemas/attachment.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { UserRepository } from '@/user/repositories/user.repository';
|
||||
import { User, UserModel } from '@/user/schemas/user.schema';
|
||||
import {
|
||||
@@ -30,6 +27,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { Label, LabelModel } from '../schemas/label.schema';
|
||||
import {
|
||||
@@ -52,10 +50,9 @@ describe('SubscriberRepository', () => {
|
||||
let allSubscribers: Subscriber[];
|
||||
let allAttachments: Attachment[];
|
||||
let subscribersWithPopulatedFields: SubscriberFull[];
|
||||
let eventEmitter: EventEmitter2;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installSubscriberFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -69,21 +66,24 @@ describe('SubscriberRepository', () => {
|
||||
SubscriberRepository,
|
||||
LabelRepository,
|
||||
UserRepository,
|
||||
EventEmitter2,
|
||||
LoggerService,
|
||||
AttachmentService,
|
||||
AttachmentRepository,
|
||||
],
|
||||
}).compile();
|
||||
subscriberRepository =
|
||||
module.get<SubscriberRepository>(SubscriberRepository);
|
||||
labelRepository = module.get<LabelRepository>(LabelRepository);
|
||||
userRepository = module.get<UserRepository>(UserRepository);
|
||||
attachmentRepository =
|
||||
module.get<AttachmentRepository>(AttachmentRepository);
|
||||
subscriberModel = module.get<Model<Subscriber>>(
|
||||
getModelToken('Subscriber'),
|
||||
);
|
||||
});
|
||||
[
|
||||
subscriberRepository,
|
||||
labelRepository,
|
||||
userRepository,
|
||||
attachmentRepository,
|
||||
subscriberModel,
|
||||
] = await getMocks([
|
||||
SubscriberRepository,
|
||||
LabelRepository,
|
||||
UserRepository,
|
||||
AttachmentRepository,
|
||||
getModelToken(Subscriber.name),
|
||||
]);
|
||||
|
||||
allLabels = await labelRepository.findAll();
|
||||
allSubscribers = await subscriberRepository.findAll();
|
||||
allUsers = await userRepository.findAll();
|
||||
@@ -95,7 +95,6 @@ describe('SubscriberRepository', () => {
|
||||
allUsers.find(({ id }) => subscriber.assignedTo === id) || null,
|
||||
avatar: allAttachments.find(({ id }) => subscriber.avatar === id) || null,
|
||||
}));
|
||||
eventEmitter = module.get<EventEmitter2>(EventEmitter2);
|
||||
});
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
@@ -171,16 +170,16 @@ describe('SubscriberRepository', () => {
|
||||
jest
|
||||
.spyOn(subscriberRepository, 'findOne')
|
||||
.mockResolvedValue(oldSubscriber);
|
||||
jest.spyOn(eventEmitter, 'emit');
|
||||
jest.spyOn(subscriberRepository.eventEmitter, 'emit');
|
||||
|
||||
await subscriberRepository.updateOne(oldSubscriber.id, updates);
|
||||
|
||||
expect(eventEmitter.emit).toHaveBeenCalledWith(
|
||||
expect(subscriberRepository.eventEmitter.emit).toHaveBeenCalledWith(
|
||||
'hook:subscriber:assign',
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
);
|
||||
expect(eventEmitter.emit).toHaveBeenCalledWith(
|
||||
expect(subscriberRepository.eventEmitter.emit).toHaveBeenCalledWith(
|
||||
'hook:analytics:passation',
|
||||
expect.anything(),
|
||||
true, // Because assignedTo has changed
|
||||
@@ -198,16 +197,16 @@ describe('SubscriberRepository', () => {
|
||||
jest
|
||||
.spyOn(subscriberRepository, 'findOne')
|
||||
.mockResolvedValue(oldSubscriber);
|
||||
jest.spyOn(eventEmitter, 'emit');
|
||||
jest.spyOn(subscriberRepository.eventEmitter, 'emit');
|
||||
|
||||
await subscriberRepository.updateOne(oldSubscriber.id, updates);
|
||||
|
||||
expect(eventEmitter.emit).not.toHaveBeenCalledWith(
|
||||
expect(subscriberRepository.eventEmitter.emit).not.toHaveBeenCalledWith(
|
||||
'hook:subscriber:assign',
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
);
|
||||
expect(eventEmitter.emit).not.toHaveBeenCalledWith(
|
||||
expect(subscriberRepository.eventEmitter.emit).not.toHaveBeenCalledWith(
|
||||
'hook:analytics:passation',
|
||||
expect.anything(),
|
||||
expect.anything(),
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import {
|
||||
Document,
|
||||
@@ -17,6 +16,7 @@ import {
|
||||
UpdateWithAggregationPipeline,
|
||||
} from 'mongoose';
|
||||
|
||||
import { BotStatsType } from '@/analytics/schemas/bot-stats.schema';
|
||||
import { BaseRepository } from '@/utils/generics/base-repository';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
@@ -36,11 +36,8 @@ export class SubscriberRepository extends BaseRepository<
|
||||
SubscriberFull,
|
||||
SubscriberDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Subscriber.name) readonly model: Model<Subscriber>,
|
||||
) {
|
||||
super(eventEmitter, model, Subscriber, SUBSCRIBER_POPULATE, SubscriberFull);
|
||||
constructor(@InjectModel(Subscriber.name) readonly model: Model<Subscriber>) {
|
||||
super(model, Subscriber, SUBSCRIBER_POPULATE, SubscriberFull);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +48,7 @@ export class SubscriberRepository extends BaseRepository<
|
||||
async postCreate(created: SubscriberDocument): Promise<void> {
|
||||
this.eventEmitter.emit(
|
||||
'hook:stats:entry',
|
||||
'new_users',
|
||||
BotStatsType.new_users,
|
||||
'New users',
|
||||
created,
|
||||
);
|
||||
|
||||
@@ -41,4 +41,6 @@ export enum PayloadType {
|
||||
quick_reply = 'quick_reply',
|
||||
button = 'button',
|
||||
outcome = 'outcome',
|
||||
menu = 'menu',
|
||||
content = 'content',
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
*/
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
@@ -33,7 +31,6 @@ import { LanguageRepository } from '@/i18n/repositories/language.repository';
|
||||
import { LanguageModel } from '@/i18n/schemas/language.schema';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LanguageService } from '@/i18n/services/language.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { PluginService } from '@/plugins/plugins.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import {
|
||||
@@ -56,6 +53,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { BlockRepository } from '../repositories/block.repository';
|
||||
import { Block, BlockModel } from '../schemas/block.schema';
|
||||
@@ -79,7 +77,7 @@ describe('BlockService', () => {
|
||||
let contentTypeService: ContentTypeService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(async () => {
|
||||
await installContentFixtures();
|
||||
@@ -112,7 +110,6 @@ describe('BlockService', () => {
|
||||
provide: PluginService,
|
||||
useValue: {},
|
||||
},
|
||||
LoggerService,
|
||||
{
|
||||
provide: I18nService,
|
||||
useValue: {
|
||||
@@ -132,7 +129,6 @@ describe('BlockService', () => {
|
||||
})),
|
||||
},
|
||||
},
|
||||
EventEmitter2,
|
||||
{
|
||||
provide: CACHE_MANAGER,
|
||||
useValue: {
|
||||
@@ -142,12 +138,20 @@ describe('BlockService', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
blockService = module.get<BlockService>(BlockService);
|
||||
contentService = module.get<ContentService>(ContentService);
|
||||
contentTypeService = module.get<ContentTypeService>(ContentTypeService);
|
||||
categoryRepository = module.get<CategoryRepository>(CategoryRepository);
|
||||
blockRepository = module.get<BlockRepository>(BlockRepository);
|
||||
});
|
||||
[
|
||||
blockService,
|
||||
contentService,
|
||||
contentTypeService,
|
||||
categoryRepository,
|
||||
blockRepository,
|
||||
] = await getMocks([
|
||||
BlockService,
|
||||
ContentService,
|
||||
ContentTypeService,
|
||||
CategoryRepository,
|
||||
BlockRepository,
|
||||
]);
|
||||
category = (await categoryRepository.findOne({ label: 'default' }))!;
|
||||
hasPreviousBlocks = (await blockRepository.findOne({
|
||||
name: 'hasPreviousBlocks',
|
||||
|
||||
@@ -16,7 +16,6 @@ import { CONSOLE_CHANNEL_NAME } from '@/extensions/channels/console/settings';
|
||||
import { NLU } from '@/helper/types';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LanguageService } from '@/i18n/services/language.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { PluginService } from '@/plugins/plugins.service';
|
||||
import { PluginType } from '@/plugins/types';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
@@ -52,7 +51,6 @@ export class BlockService extends BaseService<
|
||||
private readonly contentService: ContentService,
|
||||
private readonly settingService: SettingService,
|
||||
private readonly pluginService: PluginService,
|
||||
private readonly logger: LoggerService,
|
||||
protected readonly i18n: I18nService,
|
||||
protected readonly languageService: LanguageService,
|
||||
) {
|
||||
|
||||
@@ -10,7 +10,6 @@ import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
@@ -34,7 +33,6 @@ import { LanguageRepository } from '@/i18n/repositories/language.repository';
|
||||
import { LanguageModel } from '@/i18n/schemas/language.schema';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LanguageService } from '@/i18n/services/language.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { PluginService } from '@/plugins/plugins.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import { installBlockFixtures } from '@/utils/test/fixtures/block';
|
||||
@@ -44,6 +42,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
import { SocketEventDispatcherService } from '@/websocket/services/socket-event-dispatcher.service';
|
||||
import { WebsocketGateway } from '@/websocket/websocket.gateway';
|
||||
|
||||
@@ -81,7 +80,7 @@ describe('BlockService', () => {
|
||||
let eventEmitter: EventEmitter2;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(async () => {
|
||||
await installSubscriberFixtures();
|
||||
@@ -105,7 +104,6 @@ describe('BlockService', () => {
|
||||
JwtModule,
|
||||
],
|
||||
providers: [
|
||||
EventEmitter2,
|
||||
BlockRepository,
|
||||
CategoryRepository,
|
||||
WebsocketGateway,
|
||||
@@ -141,7 +139,6 @@ describe('BlockService', () => {
|
||||
provide: PluginService,
|
||||
useValue: {},
|
||||
},
|
||||
LoggerService,
|
||||
{
|
||||
provide: I18nService,
|
||||
useValue: {
|
||||
@@ -168,12 +165,15 @@ describe('BlockService', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
subscriberService = module.get<SubscriberService>(SubscriberService);
|
||||
botService = module.get<BotService>(BotService);
|
||||
blockService = module.get<BlockService>(BlockService);
|
||||
eventEmitter = module.get<EventEmitter2>(EventEmitter2);
|
||||
handler = module.get<WebChannelHandler>(WebChannelHandler);
|
||||
});
|
||||
[subscriberService, botService, blockService, eventEmitter, handler] =
|
||||
await getMocks([
|
||||
SubscriberService,
|
||||
BotService,
|
||||
BlockService,
|
||||
EventEmitter2,
|
||||
WebChannelHandler,
|
||||
]);
|
||||
});
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
@@ -243,8 +243,8 @@ describe('BlockService', () => {
|
||||
await botService.startConversation(event, block);
|
||||
expect(hasBotSpoken).toEqual(true);
|
||||
expect(triggeredEvents).toEqual([
|
||||
['popular', 'hasNextBlocks'],
|
||||
['new_conversations', 'New conversations'],
|
||||
['popular', 'hasNextBlocks', webSubscriber],
|
||||
['new_conversations', 'New conversations', webSubscriber],
|
||||
]);
|
||||
clearMock.mockClear();
|
||||
});
|
||||
@@ -301,7 +301,7 @@ describe('BlockService', () => {
|
||||
const captured = await botService.processConversationMessage(event);
|
||||
expect(captured).toBe(true);
|
||||
expect(triggeredEvents).toEqual([
|
||||
['existing_conversations', 'Existing conversations'],
|
||||
['existing_conversations', 'Existing conversations', webSubscriber],
|
||||
]);
|
||||
clearMock.mockClear();
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
|
||||
import { BotStatsType } from '@/analytics/schemas/bot-stats.schema';
|
||||
import EventWrapper from '@/channel/lib/EventWrapper';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
@@ -65,8 +66,18 @@ export class BotService {
|
||||
.getHandler()
|
||||
.sendMessage(event, envelope, options, context);
|
||||
|
||||
this.eventEmitter.emit('hook:stats:entry', 'outgoing', 'Outgoing');
|
||||
this.eventEmitter.emit('hook:stats:entry', 'all_messages', 'All Messages');
|
||||
this.eventEmitter.emit(
|
||||
'hook:stats:entry',
|
||||
BotStatsType.outgoing,
|
||||
'Outgoing',
|
||||
recipient,
|
||||
);
|
||||
this.eventEmitter.emit(
|
||||
'hook:stats:entry',
|
||||
BotStatsType.all_messages,
|
||||
'All Messages',
|
||||
recipient,
|
||||
);
|
||||
|
||||
// Trigger sent message event
|
||||
const sentMessage: MessageCreateDto = {
|
||||
@@ -165,7 +176,7 @@ export class BotService {
|
||||
return await this.triggerBlock(event, convo, attachedBlock, fallback);
|
||||
} catch (err) {
|
||||
this.logger.error('Unable to retrieve attached block', err);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo, true);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo);
|
||||
}
|
||||
} else if (
|
||||
Array.isArray(block.nextBlocks) &&
|
||||
@@ -200,6 +211,7 @@ export class BotService {
|
||||
'Block outcome did not match any of the next blocks',
|
||||
convo,
|
||||
);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo);
|
||||
}
|
||||
} else {
|
||||
// Conversation continues : Go forward to next blocks
|
||||
@@ -217,11 +229,11 @@ export class BotService {
|
||||
} else {
|
||||
// We need to end the conversation in this case
|
||||
this.logger.debug('No attached/next blocks to execute ...');
|
||||
this.eventEmitter.emit('hook:conversation:end', convo, false);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo);
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error('Unable to process/send message.', err);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo, true);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,7 +304,12 @@ export class BotService {
|
||||
|
||||
if (next) {
|
||||
// Increment stats about popular blocks
|
||||
this.eventEmitter.emit('hook:stats:entry', 'popular', next.name);
|
||||
this.eventEmitter.emit(
|
||||
'hook:stats:entry',
|
||||
BotStatsType.popular,
|
||||
next.name,
|
||||
convo.sender,
|
||||
);
|
||||
// Go next!
|
||||
this.logger.debug('Respond to nested conversion! Go next ', next.id);
|
||||
try {
|
||||
@@ -308,19 +325,19 @@ export class BotService {
|
||||
await this.triggerBlock(event, updatedConversation, next, fallback);
|
||||
} catch (err) {
|
||||
this.logger.error('Unable to store context data!', err);
|
||||
return this.eventEmitter.emit('hook:conversation:end', convo, true);
|
||||
return this.eventEmitter.emit('hook:conversation:end', convo);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
// Conversation is still active, but there's no matching block to call next
|
||||
// We'll end the conversation but this message is probably lost in time and space.
|
||||
this.logger.debug('No matching block found to call next ', convo.id);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo, false);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo);
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error('Unable to populate the next blocks!', err);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo, true);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
@@ -351,8 +368,9 @@ export class BotService {
|
||||
|
||||
this.eventEmitter.emit(
|
||||
'hook:stats:entry',
|
||||
'existing_conversations',
|
||||
BotStatsType.existing_conversations,
|
||||
'Existing conversations',
|
||||
subscriber,
|
||||
);
|
||||
this.logger.debug('Conversation has been captured! Responding ...');
|
||||
return await this.handleIncomingMessage(conversation, event);
|
||||
@@ -372,10 +390,15 @@ export class BotService {
|
||||
* @param block - Starting block
|
||||
*/
|
||||
async startConversation(event: EventWrapper<any, any>, block: BlockFull) {
|
||||
// Increment popular stats
|
||||
this.eventEmitter.emit('hook:stats:entry', 'popular', block.name);
|
||||
// Launching a new conversation
|
||||
const subscriber = event.getSender();
|
||||
// Increment popular stats
|
||||
this.eventEmitter.emit(
|
||||
'hook:stats:entry',
|
||||
BotStatsType.popular,
|
||||
block.name,
|
||||
subscriber,
|
||||
);
|
||||
|
||||
try {
|
||||
const convo = await this.conversationService.create({
|
||||
@@ -383,8 +406,9 @@ export class BotService {
|
||||
});
|
||||
this.eventEmitter.emit(
|
||||
'hook:stats:entry',
|
||||
'new_conversations',
|
||||
BotStatsType.new_conversations,
|
||||
'New conversations',
|
||||
subscriber,
|
||||
);
|
||||
|
||||
try {
|
||||
@@ -404,7 +428,7 @@ export class BotService {
|
||||
return this.triggerBlock(event, updatedConversation, block, false);
|
||||
} catch (err) {
|
||||
this.logger.error('Unable to store context data!', err);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo, true);
|
||||
this.eventEmitter.emit('hook:conversation:end', convo);
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error('Unable to start a new conversation with ', err);
|
||||
|
||||
@@ -11,6 +11,7 @@ import { EventEmitter2, OnEvent } from '@nestjs/event-emitter';
|
||||
import mime from 'mime';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { BotStatsType } from '@/analytics/schemas/bot-stats.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import {
|
||||
AttachmentAccess,
|
||||
@@ -96,7 +97,10 @@ export class ChatService {
|
||||
* @param sentMessage - The message that has been sent
|
||||
*/
|
||||
@OnEvent('hook:chatbot:sent')
|
||||
async handleSentMessage(sentMessage: MessageCreateDto) {
|
||||
async handleSentMessage(
|
||||
sentMessage: MessageCreateDto,
|
||||
_event: EventWrapper<any, any>,
|
||||
) {
|
||||
if (sentMessage.mid) {
|
||||
try {
|
||||
const message = await this.messageService.findOneOrCreate(
|
||||
@@ -146,11 +150,17 @@ export class ChatService {
|
||||
}
|
||||
|
||||
this.websocketGateway.broadcastMessageReceived(populatedMsg, subscriber);
|
||||
this.eventEmitter.emit('hook:stats:entry', 'incoming', 'Incoming');
|
||||
this.eventEmitter.emit(
|
||||
'hook:stats:entry',
|
||||
'all_messages',
|
||||
BotStatsType.incoming,
|
||||
'Incoming',
|
||||
subscriber,
|
||||
);
|
||||
this.eventEmitter.emit(
|
||||
'hook:stats:entry',
|
||||
BotStatsType.all_messages,
|
||||
'All Messages',
|
||||
subscriber,
|
||||
);
|
||||
} catch (err) {
|
||||
this.logger.error('Unable to log received message.', err, event);
|
||||
@@ -244,8 +254,8 @@ export class ChatService {
|
||||
read: false,
|
||||
};
|
||||
|
||||
this.eventEmitter.emit('hook:chatbot:sent', sentMessage);
|
||||
this.eventEmitter.emit('hook:stats:entry', 'echo', 'Echo');
|
||||
this.eventEmitter.emit('hook:chatbot:sent', sentMessage, event);
|
||||
this.eventEmitter.emit('hook:stats:entry', 'echo', 'Echo', recipient);
|
||||
} catch (err) {
|
||||
this.logger.error('Unable to log echo message', err, event);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
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';
|
||||
@@ -36,7 +35,6 @@ export class ConversationService extends BaseService<
|
||||
> {
|
||||
constructor(
|
||||
readonly repository: ConversationRepository,
|
||||
private readonly logger: LoggerService,
|
||||
private readonly contextVarService: ContextVarService,
|
||||
private readonly subscriberService: SubscriberService,
|
||||
) {
|
||||
|
||||
@@ -6,14 +6,11 @@
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
installLabelFixtures,
|
||||
labelFixtures,
|
||||
@@ -24,6 +21,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { LabelRepository } from '../repositories/label.repository';
|
||||
import { Label, LabelFull, LabelModel } from '../schemas/label.schema';
|
||||
@@ -42,7 +40,7 @@ describe('LabelService', () => {
|
||||
let labelsWithUsers: LabelFull[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installLabelFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -52,20 +50,19 @@ describe('LabelService', () => {
|
||||
]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
LabelService,
|
||||
LabelRepository,
|
||||
SubscriberService,
|
||||
AttachmentService,
|
||||
AttachmentRepository,
|
||||
SubscriberRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
labelService = module.get<LabelService>(LabelService);
|
||||
labelRepository = module.get<LabelRepository>(LabelRepository);
|
||||
subscriberRepository =
|
||||
module.get<SubscriberRepository>(SubscriberRepository);
|
||||
});
|
||||
[labelService, labelRepository, subscriberRepository] = await getMocks([
|
||||
LabelService,
|
||||
LabelRepository,
|
||||
SubscriberRepository,
|
||||
]);
|
||||
allSubscribers = await subscriberRepository.findAll();
|
||||
allLabels = await labelRepository.findAll();
|
||||
labelsWithUsers = allLabels.map((label) => ({
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { InvitationRepository } from '@/user/repositories/invitation.repository';
|
||||
import { RoleRepository } from '@/user/repositories/role.repository';
|
||||
import { UserRepository } from '@/user/repositories/user.repository';
|
||||
@@ -33,6 +30,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { MessageRepository } from '../repositories/message.repository';
|
||||
import { Message, MessageModel } from '../schemas/message.schema';
|
||||
@@ -57,7 +55,7 @@ describe('MessageService', () => {
|
||||
let user: User;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installMessageFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -71,7 +69,6 @@ describe('MessageService', () => {
|
||||
]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
AttachmentService,
|
||||
AttachmentRepository,
|
||||
UserService,
|
||||
@@ -83,14 +80,15 @@ describe('MessageService', () => {
|
||||
SubscriberRepository,
|
||||
MessageService,
|
||||
MessageRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
messageService = module.get<MessageService>(MessageService);
|
||||
messageRepository = module.get<MessageRepository>(MessageRepository);
|
||||
subscriberRepository =
|
||||
module.get<SubscriberRepository>(SubscriberRepository);
|
||||
userRepository = module.get<UserRepository>(UserRepository);
|
||||
});
|
||||
[messageService, messageRepository, subscriberRepository, userRepository] =
|
||||
await getMocks([
|
||||
MessageService,
|
||||
MessageRepository,
|
||||
SubscriberRepository,
|
||||
UserRepository,
|
||||
]);
|
||||
allSubscribers = await subscriberRepository.findAll();
|
||||
allUsers = await userRepository.findAll();
|
||||
allMessages = await messageRepository.findAll();
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
Optional,
|
||||
} from '@nestjs/common';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
import {
|
||||
SocketGet,
|
||||
@@ -36,17 +35,13 @@ export class MessageService extends BaseService<
|
||||
MessagePopulate,
|
||||
MessageFull
|
||||
> {
|
||||
private readonly logger: LoggerService;
|
||||
|
||||
private readonly gateway: WebsocketGateway;
|
||||
|
||||
constructor(
|
||||
private readonly messageRepository: MessageRepository,
|
||||
@Optional() logger?: LoggerService,
|
||||
@Optional() gateway?: WebsocketGateway,
|
||||
) {
|
||||
super(messageRepository);
|
||||
if (logger) this.logger = logger;
|
||||
if (gateway) this.gateway = gateway;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { InvitationRepository } from '@/user/repositories/invitation.repository';
|
||||
import { RoleRepository } from '@/user/repositories/role.repository';
|
||||
import { UserRepository } from '@/user/repositories/user.repository';
|
||||
@@ -30,6 +27,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { LabelRepository } from '../repositories/label.repository';
|
||||
import { SubscriberRepository } from '../repositories/subscriber.repository';
|
||||
@@ -49,7 +47,7 @@ describe('SubscriberService', () => {
|
||||
let allUsers: User[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installSubscriberFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -72,17 +70,17 @@ describe('SubscriberService', () => {
|
||||
RoleService,
|
||||
RoleRepository,
|
||||
InvitationRepository,
|
||||
LoggerService,
|
||||
EventEmitter2,
|
||||
AttachmentService,
|
||||
AttachmentRepository,
|
||||
],
|
||||
}).compile();
|
||||
labelRepository = module.get<LabelRepository>(LabelRepository);
|
||||
userRepository = module.get<UserRepository>(UserRepository);
|
||||
subscriberService = module.get<SubscriberService>(SubscriberService);
|
||||
subscriberRepository =
|
||||
module.get<SubscriberRepository>(SubscriberRepository);
|
||||
});
|
||||
[labelRepository, userRepository, subscriberService, subscriberRepository] =
|
||||
await getMocks([
|
||||
LabelRepository,
|
||||
UserRepository,
|
||||
SubscriberService,
|
||||
SubscriberRepository,
|
||||
]);
|
||||
allSubscribers = await subscriberRepository.findAll();
|
||||
allLabels = await labelRepository.findAll();
|
||||
allUsers = await userRepository.findAll();
|
||||
|
||||
@@ -15,7 +15,6 @@ import { OnEvent } from '@nestjs/event-emitter';
|
||||
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { config } from '@/config';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
import {
|
||||
SocketGet,
|
||||
@@ -48,7 +47,6 @@ export class SubscriberService extends BaseService<
|
||||
|
||||
constructor(
|
||||
readonly repository: SubscriberRepository,
|
||||
private readonly logger: LoggerService,
|
||||
protected attachmentService: AttachmentService,
|
||||
@Optional() gateway?: WebsocketGateway,
|
||||
) {
|
||||
|
||||
@@ -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.
|
||||
@@ -7,15 +7,12 @@
|
||||
*/
|
||||
|
||||
import { NotFoundException } from '@nestjs/common/exceptions';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { BlockService } from '@/chat/services/block.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { NOT_FOUND_ID } from '@/utils/constants/mock';
|
||||
import { getUpdateOneError } from '@/utils/test/errors/messages';
|
||||
import { installContentFixtures } from '@/utils/test/fixtures/content';
|
||||
@@ -25,6 +22,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { ContentTypeCreateDto } from '../dto/contentType.dto';
|
||||
import { ContentTypeRepository } from '../repositories/content-type.repository';
|
||||
@@ -44,7 +42,7 @@ describe('ContentTypeController', () => {
|
||||
let blockService: BlockService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [ContentTypeController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installContentFixtures),
|
||||
@@ -61,8 +59,6 @@ describe('ContentTypeController', () => {
|
||||
ContentTypeService,
|
||||
ContentService,
|
||||
AttachmentService,
|
||||
LoggerService,
|
||||
EventEmitter2,
|
||||
{
|
||||
provide: BlockService,
|
||||
useValue: {
|
||||
@@ -70,13 +66,14 @@ describe('ContentTypeController', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
blockService = module.get<BlockService>(BlockService);
|
||||
contentTypeController = module.get<ContentTypeController>(
|
||||
ContentTypeController,
|
||||
);
|
||||
contentTypeService = module.get<ContentTypeService>(ContentTypeService);
|
||||
contentService = module.get<ContentService>(ContentService);
|
||||
});
|
||||
[blockService, contentTypeController, contentTypeService, contentService] =
|
||||
await getMocks([
|
||||
BlockService,
|
||||
ContentTypeController,
|
||||
ContentTypeService,
|
||||
ContentService,
|
||||
]);
|
||||
contentType = await contentTypeService.findOne({ name: 'Product' })!;
|
||||
});
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
import { PageQueryPipe } from '@/utils/pagination/pagination-query.pipe';
|
||||
@@ -39,10 +38,7 @@ import { ContentTypeService } from '../services/content-type.service';
|
||||
@UseInterceptors(CsrfInterceptor)
|
||||
@Controller('contenttype')
|
||||
export class ContentTypeController extends BaseController<ContentType> {
|
||||
constructor(
|
||||
private readonly contentTypeService: ContentTypeService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
constructor(private readonly contentTypeService: ContentTypeService) {
|
||||
super(contentTypeService);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,8 @@
|
||||
*/
|
||||
|
||||
import { NotFoundException } from '@nestjs/common/exceptions';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { NOT_FOUND_ID } from '@/utils/constants/mock';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
import { IGNORED_TEST_FIELDS } from '@/utils/test/constants';
|
||||
@@ -25,6 +22,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { ContentCreateDto } from '../dto/content.dto';
|
||||
import { ContentTypeRepository } from '../repositories/content-type.repository';
|
||||
@@ -46,24 +44,24 @@ describe('ContentController', () => {
|
||||
let pageQuery: PageQueryDto<Content>;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [ContentController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installContentFixtures),
|
||||
MongooseModule.forFeature([ContentTypeModel, ContentModel]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
ContentTypeService,
|
||||
ContentService,
|
||||
ContentRepository,
|
||||
ContentTypeRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
contentController = module.get<ContentController>(ContentController);
|
||||
contentService = module.get<ContentService>(ContentService);
|
||||
contentTypeService = module.get<ContentTypeService>(ContentTypeService);
|
||||
});
|
||||
[contentController, contentService, contentTypeService] = await getMocks([
|
||||
ContentController,
|
||||
ContentService,
|
||||
ContentTypeService,
|
||||
]);
|
||||
contentType = await contentTypeService.findOne({ name: 'Product' });
|
||||
content = await contentService.findOne({
|
||||
title: 'Jean',
|
||||
|
||||
@@ -24,7 +24,6 @@ import { FileInterceptor } from '@nestjs/platform-express';
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
import { PageQueryPipe } from '@/utils/pagination/pagination-query.pipe';
|
||||
@@ -54,7 +53,6 @@ export class ContentController extends BaseController<
|
||||
constructor(
|
||||
private readonly contentService: ContentService,
|
||||
private readonly contentTypeService: ContentTypeService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
super(contentService);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -7,11 +7,8 @@
|
||||
*/
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
installMenuFixtures,
|
||||
offerMenuFixture,
|
||||
@@ -22,6 +19,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { MenuRepository } from '../repositories/menu.repository';
|
||||
import { MenuModel } from '../schemas/menu.schema';
|
||||
@@ -35,7 +33,7 @@ describe('MenuController', () => {
|
||||
let menuController: MenuController;
|
||||
let menuService: MenuService;
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installMenuFixtures),
|
||||
MongooseModule.forFeature([MenuModel]),
|
||||
@@ -43,7 +41,6 @@ describe('MenuController', () => {
|
||||
providers: [
|
||||
MenuRepository,
|
||||
MenuService,
|
||||
EventEmitter2,
|
||||
{
|
||||
provide: CACHE_MANAGER,
|
||||
useValue: {
|
||||
@@ -52,12 +49,13 @@ describe('MenuController', () => {
|
||||
set: jest.fn(),
|
||||
},
|
||||
},
|
||||
LoggerService,
|
||||
],
|
||||
controllers: [MenuController],
|
||||
}).compile();
|
||||
menuController = module.get<MenuController>(MenuController);
|
||||
menuService = module.get<MenuService>(MenuService);
|
||||
});
|
||||
[menuController, menuService] = await getMocks([
|
||||
MenuController,
|
||||
MenuService,
|
||||
]);
|
||||
});
|
||||
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
@@ -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.
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
import { PageQueryPipe } from '@/utils/pagination/pagination-query.pipe';
|
||||
@@ -41,10 +40,7 @@ export class MenuController extends BaseController<
|
||||
MenuPopulate,
|
||||
MenuFull
|
||||
> {
|
||||
constructor(
|
||||
private readonly menuService: MenuService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
constructor(private readonly menuService: MenuService) {
|
||||
super(menuService);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule, getModelToken } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
import { BlockRepository } from '@/chat/repositories/block.repository';
|
||||
@@ -18,11 +16,11 @@ import {
|
||||
ContentType,
|
||||
ContentTypeModel,
|
||||
} from '@/cms/schemas/content-type.schema';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { Content, ContentModel } from '../schemas/content.schema';
|
||||
|
||||
@@ -37,13 +35,12 @@ describe('ContentTypeRepository', () => {
|
||||
let blockService: BlockService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installContentFixtures),
|
||||
MongooseModule.forFeature([ContentTypeModel, ContentModel, BlockModel]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
ContentRepository,
|
||||
ContentTypeRepository,
|
||||
BlockService,
|
||||
@@ -54,18 +51,15 @@ describe('ContentTypeRepository', () => {
|
||||
findOne: jest.fn(),
|
||||
},
|
||||
},
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
blockService = module.get<BlockService>(BlockService);
|
||||
contentTypeRepository = module.get<ContentTypeRepository>(
|
||||
ContentTypeRepository,
|
||||
);
|
||||
contentTypeModel = module.get<Model<ContentType>>(
|
||||
getModelToken('ContentType'),
|
||||
);
|
||||
|
||||
contentModel = module.get<Model<Content>>(getModelToken('Content'));
|
||||
});
|
||||
[blockService, contentTypeRepository, contentTypeModel, contentModel] =
|
||||
await getMocks([
|
||||
BlockService,
|
||||
ContentTypeRepository,
|
||||
getModelToken(ContentType.name),
|
||||
getModelToken(Content.name),
|
||||
]);
|
||||
});
|
||||
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { ForbiddenException, Injectable, Optional } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Document, Model, Query } from 'mongoose';
|
||||
|
||||
@@ -27,12 +26,11 @@ export class ContentTypeRepository extends BaseRepository<
|
||||
ContentTypeDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(ContentType.name) readonly model: Model<ContentType>,
|
||||
@InjectModel(Content.name) private readonly contentModel: Model<Content>,
|
||||
@Optional() private readonly blockService?: BlockService,
|
||||
) {
|
||||
super(eventEmitter, model, ContentType);
|
||||
super(model, ContentType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule, getModelToken } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
import {
|
||||
ContentType,
|
||||
ContentTypeModel,
|
||||
} from '@/cms/schemas/content-type.schema';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { contentTypeFixtures } from '@/utils/test/fixtures/contenttype';
|
||||
import { getPageQuery } from '@/utils/test/pagination';
|
||||
import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { Content, ContentModel } from '../schemas/content.schema';
|
||||
|
||||
@@ -37,18 +35,18 @@ describe('ContentRepository', () => {
|
||||
let contentTypeModel: Model<ContentType>;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installContentFixtures),
|
||||
MongooseModule.forFeature([ContentTypeModel, ContentModel]),
|
||||
],
|
||||
providers: [LoggerService, ContentRepository, EventEmitter2],
|
||||
}).compile();
|
||||
contentRepository = module.get<ContentRepository>(ContentRepository);
|
||||
contentModel = module.get<Model<Content>>(getModelToken('Content'));
|
||||
contentTypeModel = module.get<Model<ContentType>>(
|
||||
getModelToken('ContentType'),
|
||||
);
|
||||
providers: [ContentRepository],
|
||||
});
|
||||
[contentRepository, contentModel, contentTypeModel] = await getMocks([
|
||||
ContentRepository,
|
||||
getModelToken(Content.name),
|
||||
getModelToken(ContentType.name),
|
||||
]);
|
||||
});
|
||||
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import {
|
||||
Document,
|
||||
@@ -36,11 +35,8 @@ export class ContentRepository extends BaseRepository<
|
||||
ContentFull,
|
||||
ContentDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Content.name) readonly model: Model<Content>,
|
||||
) {
|
||||
super(eventEmitter, model, Content, CONTENT_POPULATE, ContentFull);
|
||||
constructor(@InjectModel(Content.name) readonly model: Model<Content>) {
|
||||
super(model, Content, CONTENT_POPULATE, ContentFull);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import {
|
||||
installMenuFixtures,
|
||||
@@ -18,6 +16,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { MenuModel } from '../schemas/menu.schema';
|
||||
import { MenuType } from '../schemas/types/menu';
|
||||
@@ -27,19 +26,18 @@ import { MenuRepository } from './menu.repository';
|
||||
describe('MenuRepository', () => {
|
||||
let menuRepository: MenuRepository;
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installMenuFixtures),
|
||||
MongooseModule.forFeature([MenuModel]),
|
||||
],
|
||||
providers: [MenuRepository, EventEmitter2],
|
||||
}).compile();
|
||||
menuRepository = module.get<MenuRepository>(MenuRepository);
|
||||
});
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
providers: [MenuRepository],
|
||||
});
|
||||
[menuRepository] = await getMocks([MenuRepository]);
|
||||
});
|
||||
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
describe('findOneAndPopulate', () => {
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
@@ -30,11 +29,8 @@ export class MenuRepository extends BaseRepository<
|
||||
MenuFull,
|
||||
MenuDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Menu.name) readonly model: Model<Menu>,
|
||||
) {
|
||||
super(eventEmitter, model, Menu, MENU_POPULATE, MenuFull);
|
||||
constructor(@InjectModel(Menu.name) readonly model: Model<Menu>) {
|
||||
super(model, Menu, MENU_POPULATE, MenuFull);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { BlockService } from '@/chat/services/block.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { installContentFixtures } from '@/utils/test/fixtures/content';
|
||||
import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { ContentTypeRepository } from '../repositories/content-type.repository';
|
||||
import { ContentRepository } from '../repositories/content.repository';
|
||||
@@ -36,7 +34,7 @@ describe('ContentTypeService', () => {
|
||||
let blockService: BlockService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installContentFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -52,8 +50,6 @@ describe('ContentTypeService', () => {
|
||||
ContentTypeService,
|
||||
ContentService,
|
||||
AttachmentService,
|
||||
LoggerService,
|
||||
EventEmitter2,
|
||||
{
|
||||
provide: BlockService,
|
||||
useValue: {
|
||||
@@ -61,18 +57,17 @@ describe('ContentTypeService', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
blockService = module.get<BlockService>(BlockService);
|
||||
contentTypeService = module.get<ContentTypeService>(ContentTypeService);
|
||||
contentService = module.get<ContentService>(ContentService);
|
||||
contentTypeRepository = module.get<ContentTypeRepository>(
|
||||
ContentTypeRepository,
|
||||
);
|
||||
});
|
||||
[blockService, contentTypeService, contentService, contentTypeRepository] =
|
||||
await getMocks([
|
||||
BlockService,
|
||||
ContentTypeService,
|
||||
ContentService,
|
||||
ContentTypeRepository,
|
||||
]);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -6,13 +6,10 @@
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { OutgoingMessageFormat } from '@/chat/schemas/types/message';
|
||||
import { ContentOptions } from '@/chat/schemas/types/options';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { IGNORED_TEST_FIELDS } from '@/utils/test/constants';
|
||||
import {
|
||||
contentFixtures,
|
||||
@@ -23,6 +20,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { ContentTypeRepository } from '../repositories/content-type.repository';
|
||||
import { ContentRepository } from '../repositories/content.repository';
|
||||
@@ -38,7 +36,7 @@ describe('ContentService', () => {
|
||||
let contentRepository: ContentRepository;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installContentFixtures),
|
||||
MongooseModule.forFeature([ContentTypeModel, ContentModel]),
|
||||
@@ -48,18 +46,16 @@ describe('ContentService', () => {
|
||||
ContentRepository,
|
||||
ContentTypeService,
|
||||
ContentService,
|
||||
LoggerService,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
contentService = module.get<ContentService>(ContentService);
|
||||
contentTypeService = module.get<ContentTypeService>(ContentTypeService);
|
||||
contentRepository = module.get<ContentRepository>(ContentRepository);
|
||||
});
|
||||
[contentService, contentTypeService, contentRepository] = await getMocks([
|
||||
ContentService,
|
||||
ContentTypeService,
|
||||
ContentRepository,
|
||||
]);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import Papa from 'papaparse';
|
||||
|
||||
import { StdOutgoingListMessage } from '@/chat/schemas/types/message';
|
||||
import { ContentOptions } from '@/chat/schemas/types/options';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
|
||||
@@ -31,10 +30,7 @@ export class ContentService extends BaseService<
|
||||
ContentFull,
|
||||
ContentDto
|
||||
> {
|
||||
constructor(
|
||||
readonly repository: ContentRepository,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
constructor(readonly repository: ContentRepository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@@ -149,7 +145,7 @@ export class ContentService extends BaseService<
|
||||
...acc,
|
||||
{
|
||||
title: String(title),
|
||||
status: Boolean(status),
|
||||
status: status.trim().toLowerCase() === 'true',
|
||||
entity: targetContentType,
|
||||
dynamicFields: Object.keys(rest)
|
||||
.filter((key) =>
|
||||
|
||||
@@ -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.
|
||||
@@ -8,11 +8,8 @@
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { NotFoundException } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
installMenuFixtures,
|
||||
rootMenuFixtures,
|
||||
@@ -21,6 +18,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { MenuRepository } from '../repositories/menu.repository';
|
||||
import { MenuModel } from '../schemas/menu.schema';
|
||||
@@ -33,7 +31,7 @@ describe('MenuService', () => {
|
||||
let menuService: MenuService;
|
||||
let menuRepository: MenuRepository;
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installMenuFixtures),
|
||||
MongooseModule.forFeature([MenuModel]),
|
||||
@@ -41,7 +39,6 @@ describe('MenuService', () => {
|
||||
providers: [
|
||||
MenuRepository,
|
||||
MenuService,
|
||||
EventEmitter2,
|
||||
{
|
||||
provide: CACHE_MANAGER,
|
||||
useValue: {
|
||||
@@ -50,16 +47,16 @@ describe('MenuService', () => {
|
||||
set: jest.fn(),
|
||||
},
|
||||
},
|
||||
LoggerService,
|
||||
],
|
||||
}).compile();
|
||||
menuService = module.get<MenuService>(MenuService);
|
||||
menuRepository = module.get<MenuRepository>(MenuRepository);
|
||||
});
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
[menuService, menuRepository] = await getMocks([
|
||||
MenuService,
|
||||
MenuRepository,
|
||||
]);
|
||||
});
|
||||
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
describe('create', () => {
|
||||
it('should create the menu successfully', async () => {
|
||||
|
||||
109
api/src/extension/cleanup.service.spec.ts
Normal file
109
api/src/extension/cleanup.service.spec.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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 { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { ChannelService } from '@/channel/channel.service';
|
||||
import { SubscriberRepository } from '@/chat/repositories/subscriber.repository';
|
||||
import { SubscriberModel } from '@/chat/schemas/subscriber.schema';
|
||||
import { SubscriberService } from '@/chat/services/subscriber.service';
|
||||
import LocalStorageHelper from '@/extensions/helpers/local-storage/index.helper';
|
||||
import { HelperService } from '@/helper/helper.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { SettingRepository } from '@/setting/repositories/setting.repository';
|
||||
import { Setting, SettingModel } from '@/setting/schemas/setting.schema';
|
||||
import { SettingSeeder } from '@/setting/seeds/setting.seed';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import { installSettingFixtures } from '@/utils/test/fixtures/setting';
|
||||
import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { CleanupService } from './cleanup.service';
|
||||
import { TNamespace } from './types';
|
||||
|
||||
describe('CleanupService', () => {
|
||||
let initialSettings: Setting[];
|
||||
let helperService: HelperService;
|
||||
let cleanupService: CleanupService;
|
||||
let settingService: SettingService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const { getMocks, resolveMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installSettingFixtures),
|
||||
MongooseModule.forFeature([
|
||||
SettingModel,
|
||||
SubscriberModel,
|
||||
AttachmentModel,
|
||||
]),
|
||||
],
|
||||
providers: [
|
||||
CleanupService,
|
||||
HelperService,
|
||||
SettingService,
|
||||
SettingRepository,
|
||||
{
|
||||
provide: CACHE_MANAGER,
|
||||
useValue: {
|
||||
del: jest.fn(),
|
||||
get: jest.fn(),
|
||||
set: jest.fn(),
|
||||
},
|
||||
},
|
||||
SettingSeeder,
|
||||
SubscriberService,
|
||||
SubscriberRepository,
|
||||
AttachmentService,
|
||||
AttachmentRepository,
|
||||
ChannelService,
|
||||
],
|
||||
});
|
||||
[cleanupService, settingService, helperService] = await getMocks([
|
||||
CleanupService,
|
||||
SettingService,
|
||||
HelperService,
|
||||
]);
|
||||
|
||||
const [loggerService] = await resolveMocks([LoggerService]);
|
||||
initialSettings = await settingService.findAll();
|
||||
|
||||
helperService.register(
|
||||
new LocalStorageHelper(settingService, helperService, loggerService),
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
describe('delete', () => {
|
||||
it('should delete all the unregistered settings with a group suffix `_channel` or/and `_helper`', async () => {
|
||||
const registeredNamespaces = [
|
||||
...cleanupService.getChannelNamespaces(),
|
||||
...cleanupService.getHelperNamespaces(),
|
||||
];
|
||||
|
||||
await cleanupService.pruneExtensionSettings();
|
||||
const cleanSettings = await settingService.findAll();
|
||||
const filteredSettings = initialSettings.filter(
|
||||
({ group }) =>
|
||||
!/_(channel|helper)$/.test(group) !==
|
||||
registeredNamespaces.includes(group as TNamespace),
|
||||
);
|
||||
|
||||
expect(cleanSettings).toEqualPayload(filteredSettings);
|
||||
});
|
||||
});
|
||||
});
|
||||
86
api/src/extension/cleanup.service.ts
Normal file
86
api/src/extension/cleanup.service.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 { Injectable } from '@nestjs/common';
|
||||
|
||||
import { ChannelService } from '@/channel/channel.service';
|
||||
import { HelperService } from '@/helper/helper.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
|
||||
import { TCriteria, TExtractExtension, TExtractNamespace } from './types';
|
||||
|
||||
@Injectable()
|
||||
export class CleanupService {
|
||||
constructor(
|
||||
private readonly helperService: HelperService,
|
||||
private readonly loggerService: LoggerService,
|
||||
private readonly settingService: SettingService,
|
||||
private readonly channelService: ChannelService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Deletes unused settings with the specified criteria.
|
||||
*
|
||||
* @param criteria - An array of criteria objects containing:
|
||||
* - suffix: Regex pattern to match setting groups
|
||||
* - namespaces: Array of namespaces to exclude from deletion
|
||||
* @returns A promise that resolves to the result of the deletion operation.
|
||||
*/
|
||||
private async deleteManyBySuffixAndNamespaces(
|
||||
criteria: TCriteria[],
|
||||
): Promise<DeleteResult> {
|
||||
return await this.settingService.deleteMany({
|
||||
$or: criteria.map(({ suffix, namespaces }) => ({
|
||||
group: { $regex: new RegExp(`${suffix}$`), $nin: namespaces },
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of channel Namespaces.
|
||||
*
|
||||
* @returns An array of channel Namespaces.
|
||||
*/
|
||||
public getChannelNamespaces(): TExtractNamespace<'channel'>[] {
|
||||
return this.channelService
|
||||
.getAll()
|
||||
.map((channel) => channel.getNamespace<TExtractExtension<'channel'>>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of helper Namespaces.
|
||||
*
|
||||
* @returns An array of helper Namespaces.
|
||||
*/
|
||||
public getHelperNamespaces(): TExtractNamespace<'helper'>[] {
|
||||
return this.helperService
|
||||
.getAll()
|
||||
.map((helper) => helper.getNamespace<TExtractExtension<'helper'>>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune extensions unused settings.
|
||||
*
|
||||
*/
|
||||
public async pruneExtensionSettings(): Promise<void> {
|
||||
const channels = this.getChannelNamespaces();
|
||||
const helpers = this.getHelperNamespaces();
|
||||
const { deletedCount } = await this.deleteManyBySuffixAndNamespaces([
|
||||
{ suffix: '_channel', namespaces: channels },
|
||||
{ suffix: '_helper', namespaces: helpers },
|
||||
]);
|
||||
|
||||
if (deletedCount > 0) {
|
||||
this.loggerService.log(
|
||||
`${deletedCount} unused setting${deletedCount === 1 ? '' : 's'} ${deletedCount === 1 ? 'is' : 'are'} successfully deleted!`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
api/src/extension/extension.module.ts
Normal file
33
api/src/extension/extension.module.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 { Global, Module, OnApplicationBootstrap } from '@nestjs/common';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
|
||||
import { CleanupService } from './cleanup.service';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
providers: [CleanupService],
|
||||
exports: [CleanupService],
|
||||
})
|
||||
export class ExtensionModule implements OnApplicationBootstrap {
|
||||
constructor(
|
||||
private readonly loggerService: LoggerService,
|
||||
private readonly cleanupService: CleanupService,
|
||||
) {}
|
||||
|
||||
async onApplicationBootstrap() {
|
||||
try {
|
||||
await this.cleanupService.pruneExtensionSettings();
|
||||
} catch (error) {
|
||||
this.loggerService.error('Unable to delete unused settings', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
41
api/src/extension/types.ts
Normal file
41
api/src/extension/types.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 { ExtensionName } from '@/utils/types/extension';
|
||||
|
||||
type TExcludedExtension = 'plugin';
|
||||
|
||||
type TExcludeSuffix<
|
||||
T,
|
||||
S extends string = '_',
|
||||
Suffix extends string = `${S}${TExcludedExtension}`,
|
||||
> = T extends `${infer _Base}${Suffix}` ? never : T;
|
||||
|
||||
export type TExtensionName = TExcludeSuffix<ExtensionName, '-'>;
|
||||
|
||||
export type TExtension =
|
||||
Extract<TExtensionName, `${string}-${string}`> extends `${string}-${infer S}`
|
||||
? `${S}`
|
||||
: never;
|
||||
|
||||
export type TNamespace = HyphenToUnderscore<TExtensionName>;
|
||||
|
||||
export type TExtractNamespace<
|
||||
T extends TExtension = TExtension,
|
||||
M extends TExtensionName = TExtensionName,
|
||||
> = M extends `${string}${T}` ? HyphenToUnderscore<M> : never;
|
||||
|
||||
export type TExtractExtension<
|
||||
T extends TExtension = TExtension,
|
||||
M extends TExtensionName = TExtensionName,
|
||||
> = M extends `${string}${T}` ? M : never;
|
||||
|
||||
export type TCriteria = {
|
||||
suffix: `_${TExtension}`;
|
||||
namespaces: TNamespace[];
|
||||
};
|
||||
@@ -7,10 +7,8 @@
|
||||
*/
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { Request } from 'express';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
@@ -36,7 +34,6 @@ import { MenuRepository } from '@/cms/repositories/menu.repository';
|
||||
import { MenuModel } from '@/cms/schemas/menu.schema';
|
||||
import { MenuService } from '@/cms/services/menu.service';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import { UserModel } from '@/user/schemas/user.schema';
|
||||
import { installMessageFixtures } from '@/utils/test/fixtures/message';
|
||||
@@ -44,6 +41,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
import { SocketEventDispatcherService } from '@/websocket/services/socket-event-dispatcher.service';
|
||||
import { SocketRequest } from '@/websocket/utils/socket-request';
|
||||
import { SocketResponse } from '@/websocket/utils/socket-response';
|
||||
@@ -66,7 +64,7 @@ describe('WebChannelHandler', () => {
|
||||
const webSettings = {};
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(async () => {
|
||||
await installMessageFixtures();
|
||||
@@ -105,8 +103,6 @@ describe('WebChannelHandler', () => {
|
||||
MenuService,
|
||||
MenuRepository,
|
||||
WebChannelHandler,
|
||||
EventEmitter2,
|
||||
LoggerService,
|
||||
{
|
||||
provide: I18nService,
|
||||
useValue: {
|
||||
@@ -122,9 +118,11 @@ describe('WebChannelHandler', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
subscriberService = module.get<SubscriberService>(SubscriberService);
|
||||
handler = module.get<WebChannelHandler>(WebChannelHandler);
|
||||
});
|
||||
[subscriberService, handler] = await getMocks([
|
||||
SubscriberService,
|
||||
WebChannelHandler,
|
||||
]);
|
||||
|
||||
jest
|
||||
.spyOn(handler, 'getPublicUrl')
|
||||
|
||||
@@ -7,10 +7,8 @@
|
||||
*/
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import {
|
||||
@@ -33,7 +31,6 @@ import { MenuRepository } from '@/cms/repositories/menu.repository';
|
||||
import { MenuModel } from '@/cms/schemas/menu.schema';
|
||||
import { MenuService } from '@/cms/services/menu.service';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { NlpService } from '@/nlp/services/nlp.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import { installSubscriberFixtures } from '@/utils/test/fixtures/subscriber';
|
||||
@@ -41,6 +38,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
import { SocketEventDispatcherService } from '@/websocket/services/socket-event-dispatcher.service';
|
||||
import { WebsocketGateway } from '@/websocket/websocket.gateway';
|
||||
|
||||
@@ -54,11 +52,9 @@ describe(`Web event wrapper`, () => {
|
||||
let handler: WebChannelHandler;
|
||||
const webSettings = {};
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(async () => {
|
||||
await installSubscriberFixtures();
|
||||
}),
|
||||
rootMongooseTestModule(installSubscriberFixtures),
|
||||
MongooseModule.forFeature([
|
||||
SubscriberModel,
|
||||
AttachmentModel,
|
||||
@@ -97,8 +93,6 @@ describe(`Web event wrapper`, () => {
|
||||
MenuService,
|
||||
MenuRepository,
|
||||
WebChannelHandler,
|
||||
EventEmitter2,
|
||||
LoggerService,
|
||||
{
|
||||
provide: I18nService,
|
||||
useValue: {
|
||||
@@ -114,8 +108,8 @@ describe(`Web event wrapper`, () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
handler = module.get<WebChannelHandler>(WebChannelHandler);
|
||||
});
|
||||
[handler] = await getMocks([WebChannelHandler]);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
||||
@@ -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.
|
||||
@@ -8,12 +8,9 @@
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { BadRequestException } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { NOT_FOUND_ID } from '@/utils/constants/mock';
|
||||
import { getUpdateOneError } from '@/utils/test/errors/messages';
|
||||
import {
|
||||
@@ -25,6 +22,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { LanguageUpdateDto } from '../dto/language.dto';
|
||||
import { LanguageRepository } from '../repositories/language.repository';
|
||||
@@ -39,7 +37,7 @@ describe('LanguageController', () => {
|
||||
let language: Language;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installLanguageFixtures),
|
||||
MongooseModule.forFeature([LanguageModel]),
|
||||
@@ -48,7 +46,6 @@ describe('LanguageController', () => {
|
||||
LanguageController,
|
||||
LanguageService,
|
||||
LanguageRepository,
|
||||
LoggerService,
|
||||
{
|
||||
provide: I18nService,
|
||||
useValue: {
|
||||
@@ -64,12 +61,12 @@ describe('LanguageController', () => {
|
||||
set: jest.fn(),
|
||||
},
|
||||
},
|
||||
LoggerService,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
languageService = module.get<LanguageService>(LanguageService);
|
||||
languageController = module.get<LanguageController>(LanguageController);
|
||||
});
|
||||
[languageService, languageController] = await getMocks([
|
||||
LanguageService,
|
||||
LanguageController,
|
||||
]);
|
||||
language = (await languageService.findOne({ code: 'en' })) as Language;
|
||||
});
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
@@ -38,10 +37,7 @@ import { LanguageService } from '../services/language.service';
|
||||
@UseInterceptors(CsrfInterceptor)
|
||||
@Controller('language')
|
||||
export class LanguageController extends BaseController<Language> {
|
||||
constructor(
|
||||
private readonly languageService: LanguageService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
constructor(private readonly languageService: LanguageService) {
|
||||
super(languageService);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -7,9 +7,7 @@
|
||||
*/
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentRepository } from '@/attachment/repositories/attachment.repository';
|
||||
import { AttachmentModel } from '@/attachment/schemas/attachment.schema';
|
||||
@@ -32,7 +30,6 @@ import { MenuModel } from '@/cms/schemas/menu.schema';
|
||||
import { ContentService } from '@/cms/services/content.service';
|
||||
import { MenuService } from '@/cms/services/menu.service';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { NlpService } from '@/nlp/services/nlp.service';
|
||||
import { PluginService } from '@/plugins/plugins.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
@@ -47,6 +44,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { TranslationUpdateDto } from '../dto/translation.dto';
|
||||
import { LanguageRepository } from '../repositories/language.repository';
|
||||
@@ -64,7 +62,7 @@ describe('TranslationController', () => {
|
||||
let translation: Translation;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [MessageController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installTranslationFixtures),
|
||||
@@ -115,8 +113,6 @@ describe('TranslationController', () => {
|
||||
provide: PluginService,
|
||||
useValue: {},
|
||||
},
|
||||
EventEmitter2,
|
||||
LoggerService,
|
||||
{
|
||||
provide: I18nService,
|
||||
useValue: {
|
||||
@@ -132,15 +128,14 @@ describe('TranslationController', () => {
|
||||
set: jest.fn(),
|
||||
},
|
||||
},
|
||||
LoggerService,
|
||||
LanguageService,
|
||||
LanguageRepository,
|
||||
],
|
||||
}).compile();
|
||||
translationService = module.get<TranslationService>(TranslationService);
|
||||
translationController = module.get<TranslationController>(
|
||||
});
|
||||
[translationService, translationController] = await getMocks([
|
||||
TranslationService,
|
||||
TranslationController,
|
||||
);
|
||||
]);
|
||||
translation = (await translationService.findOne({
|
||||
str: 'Welcome',
|
||||
})) as Translation;
|
||||
|
||||
@@ -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.
|
||||
@@ -23,8 +23,6 @@ import {
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
@@ -43,8 +41,6 @@ export class TranslationController extends BaseController<Translation> {
|
||||
constructor(
|
||||
private readonly languageService: LanguageService,
|
||||
private readonly translationService: TranslationService,
|
||||
private readonly settingService: SettingService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
super(translationService);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Document, Model, Query } from 'mongoose';
|
||||
|
||||
@@ -24,11 +23,8 @@ export class LanguageRepository extends BaseRepository<
|
||||
never,
|
||||
LanguageDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Language.name) readonly model: Model<Language>,
|
||||
) {
|
||||
super(eventEmitter, model, Language);
|
||||
constructor(@InjectModel(Language.name) readonly model: Model<Language>) {
|
||||
super(model, Language);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
@@ -18,9 +17,8 @@ import { Translation } from '../../i18n/schemas/translation.schema';
|
||||
@Injectable()
|
||||
export class TranslationRepository extends BaseRepository<Translation> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(Translation.name) readonly model: Model<Translation>,
|
||||
) {
|
||||
super(eventEmitter, model, Translation);
|
||||
super(model, Translation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,7 +15,6 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { Cache } from 'cache-manager';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import {
|
||||
DEFAULT_LANGUAGE_CACHE_KEY,
|
||||
LANGUAGES_CACHE_KEY,
|
||||
@@ -37,7 +36,6 @@ export class LanguageService extends BaseService<
|
||||
constructor(
|
||||
readonly repository: LanguageRepository,
|
||||
@Inject(CACHE_MANAGER) private readonly cacheManager: Cache,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@@ -6,15 +6,13 @@
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { BasePlugin } from '@/plugins/base-plugin.service';
|
||||
import { PluginService } from '@/plugins/plugins.service';
|
||||
import { PluginBlockTemplate } from '@/plugins/types';
|
||||
import { SettingType } from '@/setting/schemas/types';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { Block } from '../../chat/schemas/block.schema';
|
||||
import { BlockOptions } from '../../chat/schemas/types/options';
|
||||
@@ -24,11 +22,11 @@ import { TranslationService } from '../services/translation.service';
|
||||
|
||||
describe('TranslationService', () => {
|
||||
let service: TranslationService;
|
||||
let i18nService: I18nService;
|
||||
let i18nService: I18nService<unknown>;
|
||||
let pluginService: PluginService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
providers: [
|
||||
TranslationService,
|
||||
{
|
||||
@@ -106,13 +104,13 @@ describe('TranslationService', () => {
|
||||
refreshDynamicTranslations: jest.fn(),
|
||||
},
|
||||
},
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<TranslationService>(TranslationService);
|
||||
i18nService = module.get<I18nService>(I18nService);
|
||||
pluginService = module.get<PluginService>(PluginService);
|
||||
});
|
||||
[service, i18nService, pluginService] = await getMocks([
|
||||
TranslationService,
|
||||
I18nService,
|
||||
PluginService,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should call refreshDynamicTranslations with translations from findAll', async () => {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { OnEvent } from '@nestjs/event-emitter';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { PluginService } from '@/plugins/plugins.service';
|
||||
import { PluginType } from '@/plugins/types';
|
||||
import { SettingType } from '@/setting/schemas/types';
|
||||
import { SettingService } from '@/setting/services/setting.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
|
||||
@@ -57,21 +58,35 @@ export class TranslationService extends BaseService<Translation> {
|
||||
PluginType.block,
|
||||
block.message.plugin,
|
||||
);
|
||||
const defaultSettings = await plugin?.getDefaultSettings();
|
||||
const defaultSettings = (await plugin?.getDefaultSettings()) || [];
|
||||
const filteredSettings = defaultSettings.filter(
|
||||
({ translatable, type }) =>
|
||||
[
|
||||
SettingType.text,
|
||||
SettingType.textarea,
|
||||
SettingType.multiple_text,
|
||||
].includes(type) &&
|
||||
(translatable === undefined || translatable === true),
|
||||
);
|
||||
const settingTypeMap = new Map(
|
||||
filteredSettings.map((setting) => [setting.label, setting.type]),
|
||||
);
|
||||
|
||||
// plugin
|
||||
Object.entries(block.message.args).forEach(([l, arg]) => {
|
||||
const setting = defaultSettings?.find(({ label }) => label === l);
|
||||
if (setting?.translatable) {
|
||||
if (Array.isArray(arg)) {
|
||||
// array of text
|
||||
strings = strings.concat(arg);
|
||||
} else if (typeof arg === 'string') {
|
||||
// text
|
||||
strings.push(arg);
|
||||
}
|
||||
for (const [key, value] of Object.entries(block.message.args)) {
|
||||
const settingType = settingTypeMap.get(key);
|
||||
|
||||
switch (settingType) {
|
||||
case SettingType.multiple_text:
|
||||
strings = strings.concat(value);
|
||||
break;
|
||||
case SettingType.text:
|
||||
case SettingType.textarea:
|
||||
strings.push(value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if ('text' in block.message && Array.isArray(block.message.text)) {
|
||||
// array of text
|
||||
strings = strings.concat(block.message.text);
|
||||
|
||||
@@ -10,9 +10,7 @@ import fs from 'fs';
|
||||
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import { ModuleRef } from '@nestjs/core';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { getModelToken, MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { AttachmentService } from '@/attachment/services/attachment.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
@@ -23,6 +21,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { Migration, MigrationModel } from './migration.schema';
|
||||
import { MigrationService } from './migration.service';
|
||||
@@ -34,7 +33,7 @@ describe('MigrationService', () => {
|
||||
let metadataService: MetadataService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks, resolveMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(async () => await Promise.resolve()),
|
||||
MongooseModule.forFeature([MetadataModel, MigrationModel]),
|
||||
@@ -43,7 +42,6 @@ describe('MigrationService', () => {
|
||||
MetadataRepository,
|
||||
MetadataService,
|
||||
MigrationService,
|
||||
EventEmitter2,
|
||||
{
|
||||
provide: LoggerService,
|
||||
useValue: {
|
||||
@@ -74,11 +72,12 @@ describe('MigrationService', () => {
|
||||
useValue: jest.fn(),
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
service = module.get<MigrationService>(MigrationService);
|
||||
loggerService = await module.resolve<LoggerService>(LoggerService);
|
||||
metadataService = module.get<MetadataService>(MetadataService);
|
||||
});
|
||||
[service, metadataService] = await getMocks([
|
||||
MigrationService,
|
||||
MetadataService,
|
||||
]);
|
||||
[loggerService] = await resolveMocks([LoggerService]);
|
||||
});
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
@@ -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.
|
||||
@@ -11,11 +11,8 @@ import {
|
||||
MethodNotAllowedException,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { IGNORED_TEST_FIELDS } from '@/utils/test/constants';
|
||||
import { nlpEntityFixtures } from '@/utils/test/fixtures/nlpentity';
|
||||
import {
|
||||
@@ -28,6 +25,7 @@ import {
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { TFixtures } from '@/utils/test/types';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { NlpEntityCreateDto } from '../dto/nlp-entity.dto';
|
||||
import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
|
||||
@@ -53,7 +51,7 @@ describe('NlpEntityController', () => {
|
||||
let buitInEntityId: string | null;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [NlpEntityController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installNlpValueFixtures),
|
||||
@@ -64,19 +62,18 @@ describe('NlpEntityController', () => {
|
||||
]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
NlpEntityService,
|
||||
NlpEntityRepository,
|
||||
NlpValueService,
|
||||
NlpSampleEntityRepository,
|
||||
NlpValueRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
nlpEntityController = module.get<NlpEntityController>(NlpEntityController);
|
||||
nlpValueService = module.get<NlpValueService>(NlpValueService);
|
||||
nlpEntityService = module.get<NlpEntityService>(NlpEntityService);
|
||||
|
||||
});
|
||||
[nlpEntityController, nlpValueService, nlpEntityService] = await getMocks([
|
||||
NlpEntityController,
|
||||
NlpValueService,
|
||||
NlpEntityService,
|
||||
]);
|
||||
intentEntityId =
|
||||
(
|
||||
await nlpEntityService.findOne({
|
||||
@@ -90,9 +87,8 @@ describe('NlpEntityController', () => {
|
||||
})
|
||||
)?.id || null;
|
||||
});
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
@@ -51,10 +50,7 @@ export class NlpEntityController extends BaseController<
|
||||
NlpEntityPopulate,
|
||||
NlpEntityFull
|
||||
> {
|
||||
constructor(
|
||||
private readonly nlpEntityService: NlpEntityService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
constructor(private readonly nlpEntityService: NlpEntityService) {
|
||||
super(nlpEntityService);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,16 +8,13 @@
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { HelperService } from '@/helper/helper.service';
|
||||
import { LanguageRepository } from '@/i18n/repositories/language.repository';
|
||||
import { Language, LanguageModel } from '@/i18n/schemas/language.schema';
|
||||
import { I18nService } from '@/i18n/services/i18n.service';
|
||||
import { LanguageService } from '@/i18n/services/language.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { SettingRepository } from '@/setting/repositories/setting.repository';
|
||||
import { SettingModel } from '@/setting/schemas/setting.schema';
|
||||
import { SettingSeeder } from '@/setting/seeds/setting.seed';
|
||||
@@ -32,6 +29,7 @@ import {
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { TFixtures } from '@/utils/test/types';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { NlpSampleDto } from '../dto/nlp-sample.dto';
|
||||
import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
|
||||
@@ -65,7 +63,7 @@ describe('NlpSampleController', () => {
|
||||
let languages: Language[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [NlpSampleController],
|
||||
imports: [
|
||||
rootMongooseTestModule(async () => {
|
||||
@@ -82,7 +80,6 @@ describe('NlpSampleController', () => {
|
||||
]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
NlpSampleRepository,
|
||||
NlpSampleEntityRepository,
|
||||
NlpEntityService,
|
||||
@@ -93,7 +90,6 @@ describe('NlpSampleController', () => {
|
||||
NlpSampleEntityService,
|
||||
LanguageRepository,
|
||||
LanguageService,
|
||||
EventEmitter2,
|
||||
HelperService,
|
||||
SettingRepository,
|
||||
SettingService,
|
||||
@@ -113,26 +109,32 @@ describe('NlpSampleController', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
nlpSampleController = module.get<NlpSampleController>(NlpSampleController);
|
||||
nlpSampleEntityService = module.get<NlpSampleEntityService>(
|
||||
});
|
||||
[
|
||||
nlpSampleController,
|
||||
nlpSampleEntityService,
|
||||
nlpSampleService,
|
||||
nlpEntityService,
|
||||
nlpValueService,
|
||||
languageService,
|
||||
] = await getMocks([
|
||||
NlpSampleController,
|
||||
NlpSampleEntityService,
|
||||
);
|
||||
nlpSampleService = module.get<NlpSampleService>(NlpSampleService);
|
||||
nlpEntityService = module.get<NlpEntityService>(NlpEntityService);
|
||||
nlpValueService = module.get<NlpValueService>(NlpValueService);
|
||||
NlpSampleService,
|
||||
NlpEntityService,
|
||||
NlpValueService,
|
||||
LanguageService,
|
||||
]);
|
||||
byeJhonSampleId =
|
||||
(
|
||||
await nlpSampleService.findOne({
|
||||
text: 'Bye Jhon',
|
||||
})
|
||||
)?.id || null;
|
||||
languageService = module.get<LanguageService>(LanguageService);
|
||||
languages = await languageService.findAll();
|
||||
});
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@ import { HelperService } from '@/helper/helper.service';
|
||||
import { HelperType } from '@/helper/types';
|
||||
import { LanguageService } from '@/i18n/services/language.service';
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
@@ -68,7 +67,6 @@ export class NlpSampleController extends BaseController<
|
||||
private readonly nlpSampleService: NlpSampleService,
|
||||
private readonly nlpSampleEntityService: NlpSampleEntityService,
|
||||
private readonly nlpEntityService: NlpEntityService,
|
||||
private readonly logger: LoggerService,
|
||||
private readonly languageService: LanguageService,
|
||||
private readonly helperService: HelperService,
|
||||
) {
|
||||
|
||||
@@ -7,23 +7,18 @@
|
||||
*/
|
||||
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { getUpdateOneError } from '@/utils/test/errors/messages';
|
||||
import { nlpEntityFixtures } from '@/utils/test/fixtures/nlpentity';
|
||||
import {
|
||||
installNlpValueFixtures,
|
||||
nlpValueFixtures,
|
||||
} from '@/utils/test/fixtures/nlpvalue';
|
||||
import { getPageQuery } from '@/utils/test/pagination';
|
||||
import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { TFixtures } from '@/utils/test/types';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { NlpValueCreateDto } from '../dto/nlp-value.dto';
|
||||
import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
|
||||
@@ -31,11 +26,7 @@ import { NlpSampleEntityRepository } from '../repositories/nlp-sample-entity.rep
|
||||
import { NlpValueRepository } from '../repositories/nlp-value.repository';
|
||||
import { NlpEntityModel } from '../schemas/nlp-entity.schema';
|
||||
import { NlpSampleEntityModel } from '../schemas/nlp-sample-entity.schema';
|
||||
import {
|
||||
NlpValue,
|
||||
NlpValueFull,
|
||||
NlpValueModel,
|
||||
} from '../schemas/nlp-value.schema';
|
||||
import { NlpValue, NlpValueModel } from '../schemas/nlp-value.schema';
|
||||
import { NlpEntityService } from '../services/nlp-entity.service';
|
||||
import { NlpValueService } from '../services/nlp-value.service';
|
||||
|
||||
@@ -50,7 +41,7 @@ describe('NlpValueController', () => {
|
||||
let negativeValue: NlpValue | null;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
controllers: [NlpValueController],
|
||||
imports: [
|
||||
rootMongooseTestModule(installNlpValueFixtures),
|
||||
@@ -61,85 +52,27 @@ describe('NlpValueController', () => {
|
||||
]),
|
||||
],
|
||||
providers: [
|
||||
LoggerService,
|
||||
NlpValueRepository,
|
||||
NlpValueService,
|
||||
NlpSampleEntityRepository,
|
||||
NlpEntityService,
|
||||
NlpEntityRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
nlpValueController = module.get<NlpValueController>(NlpValueController);
|
||||
nlpValueService = module.get<NlpValueService>(NlpValueService);
|
||||
nlpEntityService = module.get<NlpEntityService>(NlpEntityService);
|
||||
});
|
||||
[nlpValueController, nlpValueService, nlpEntityService] = await getMocks([
|
||||
NlpValueController,
|
||||
NlpValueService,
|
||||
NlpEntityService,
|
||||
]);
|
||||
jhonNlpValue = await nlpValueService.findOne({ value: 'jhon' });
|
||||
positiveValue = await nlpValueService.findOne({ value: 'positive' });
|
||||
negativeValue = await nlpValueService.findOne({ value: 'negative' });
|
||||
});
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
describe('findPage', () => {
|
||||
it('should find nlp Values, and foreach nlp value populate the corresponding entity', async () => {
|
||||
const pageQuery = getPageQuery<NlpValue>({
|
||||
sort: ['value', 'desc'],
|
||||
});
|
||||
const result = await nlpValueController.findPage(
|
||||
pageQuery,
|
||||
['entity'],
|
||||
{},
|
||||
);
|
||||
|
||||
const nlpValueFixturesWithEntities = nlpValueFixtures.reduce(
|
||||
(acc, curr) => {
|
||||
acc.push({
|
||||
...curr,
|
||||
entity: nlpEntityFixtures[
|
||||
parseInt(curr.entity!)
|
||||
] as NlpValueFull['entity'],
|
||||
builtin: curr.builtin!,
|
||||
expressions: curr.expressions!,
|
||||
metadata: curr.metadata!,
|
||||
});
|
||||
return acc;
|
||||
},
|
||||
[] as TFixtures<NlpValueFull>[],
|
||||
);
|
||||
expect(result).toEqualPayload(nlpValueFixturesWithEntities);
|
||||
});
|
||||
|
||||
it('should find nlp Values', async () => {
|
||||
const pageQuery = getPageQuery<NlpValue>({
|
||||
sort: ['value', 'desc'],
|
||||
});
|
||||
const result = await nlpValueController.findPage(
|
||||
pageQuery,
|
||||
['invalidCriteria'],
|
||||
{},
|
||||
);
|
||||
const nlpEntities = await nlpEntityService.findAll();
|
||||
const nlpValueFixturesWithEntities = nlpValueFixtures.reduce(
|
||||
(acc, curr) => {
|
||||
const ValueWithEntities = {
|
||||
...curr,
|
||||
entity: curr.entity ? nlpEntities[parseInt(curr.entity!)].id : null,
|
||||
expressions: curr.expressions!,
|
||||
metadata: curr.metadata!,
|
||||
builtin: curr.builtin!,
|
||||
};
|
||||
acc.push(ValueWithEntities);
|
||||
return acc;
|
||||
},
|
||||
[] as TFixtures<NlpValueCreateDto>[],
|
||||
);
|
||||
expect(result).toEqualPayload(nlpValueFixturesWithEntities);
|
||||
});
|
||||
});
|
||||
|
||||
describe('count', () => {
|
||||
it('should count the nlp Values', async () => {
|
||||
const result = await nlpValueController.filterCount();
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
import { CsrfCheck } from '@tekuconcept/nestjs-csrf';
|
||||
|
||||
import { CsrfInterceptor } from '@/interceptors/csrf.interceptor';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseController } from '@/utils/generics/base-controller';
|
||||
import { DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
@@ -31,6 +30,7 @@ import { PageQueryPipe } from '@/utils/pagination/pagination-query.pipe';
|
||||
import { PopulatePipe } from '@/utils/pipes/populate.pipe';
|
||||
import { SearchFilterPipe } from '@/utils/pipes/search-filter.pipe';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
import { Format } from '@/utils/types/format.types';
|
||||
|
||||
import { NlpValueCreateDto, NlpValueUpdateDto } from '../dto/nlp-value.dto';
|
||||
import {
|
||||
@@ -53,7 +53,6 @@ export class NlpValueController extends BaseController<
|
||||
constructor(
|
||||
private readonly nlpValueService: NlpValueService,
|
||||
private readonly nlpEntityService: NlpEntityService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
super(nlpValueService);
|
||||
}
|
||||
@@ -128,7 +127,7 @@ export class NlpValueController extends BaseController<
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a paginated list of NLP values.
|
||||
* Retrieves a paginated list of NLP values with NLP Samples count.
|
||||
*
|
||||
* Supports filtering, pagination, and optional population of related entities.
|
||||
*
|
||||
@@ -136,10 +135,10 @@ export class NlpValueController extends BaseController<
|
||||
* @param populate - An array of related entities to populate.
|
||||
* @param filters - Filters to apply when retrieving the NLP values.
|
||||
*
|
||||
* @returns A promise resolving to a paginated list of NLP values.
|
||||
* @returns A promise resolving to a paginated list of NLP values with NLP Samples count.
|
||||
*/
|
||||
@Get()
|
||||
async findPage(
|
||||
async findWithCount(
|
||||
@Query(PageQueryPipe) pageQuery: PageQueryDto<NlpValue>,
|
||||
@Query(PopulatePipe) populate: string[],
|
||||
@Query(
|
||||
@@ -149,9 +148,11 @@ export class NlpValueController extends BaseController<
|
||||
)
|
||||
filters: TFilterQuery<NlpValue>,
|
||||
) {
|
||||
return this.canPopulate(populate)
|
||||
? await this.nlpValueService.findAndPopulate(filters, pageQuery)
|
||||
: await this.nlpValueService.find(filters, pageQuery);
|
||||
return await this.nlpValueService.findWithCount(
|
||||
this.canPopulate(populate) ? Format.FULL : Format.STUB,
|
||||
pageQuery,
|
||||
filters,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { nlpEntityFixtures } from '@/utils/test/fixtures/nlpentity';
|
||||
import { installNlpValueFixtures } from '@/utils/test/fixtures/nlpvalue';
|
||||
@@ -17,6 +15,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { NlpEntity, NlpEntityModel } from '../schemas/nlp-entity.schema';
|
||||
import { NlpSampleEntityModel } from '../schemas/nlp-sample-entity.schema';
|
||||
@@ -32,7 +31,7 @@ describe('NlpEntityRepository', () => {
|
||||
let firstNameNlpEntity: NlpEntity | null;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installNlpValueFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -45,19 +44,18 @@ describe('NlpEntityRepository', () => {
|
||||
NlpEntityRepository,
|
||||
NlpValueRepository,
|
||||
NlpSampleEntityRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
nlpEntityRepository = module.get<NlpEntityRepository>(NlpEntityRepository);
|
||||
nlpValueRepository = module.get<NlpValueRepository>(NlpValueRepository);
|
||||
});
|
||||
[nlpEntityRepository, nlpValueRepository] = await getMocks([
|
||||
NlpEntityRepository,
|
||||
NlpValueRepository,
|
||||
]);
|
||||
firstNameNlpEntity = await nlpEntityRepository.findOne({
|
||||
name: 'first_name',
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Document, Model, Query } from 'mongoose';
|
||||
|
||||
@@ -34,12 +33,11 @@ export class NlpEntityRepository extends BaseRepository<
|
||||
NlpEntityDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(NlpEntity.name) readonly model: Model<NlpEntity>,
|
||||
private readonly nlpValueRepository: NlpValueRepository,
|
||||
private readonly nlpSampleEntityRepository: NlpSampleEntityRepository,
|
||||
) {
|
||||
super(eventEmitter, model, NlpEntity, NLP_ENTITY_POPULATE, NlpEntityFull);
|
||||
super(model, NlpEntity, NLP_ENTITY_POPULATE, NlpEntityFull);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LanguageRepository } from '@/i18n/repositories/language.repository';
|
||||
import { Language, LanguageModel } from '@/i18n/schemas/language.schema';
|
||||
@@ -24,6 +22,7 @@ import {
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { TFixtures } from '@/utils/test/types';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { NlpEntity, NlpEntityModel } from '../schemas/nlp-entity.schema';
|
||||
import {
|
||||
@@ -47,7 +46,7 @@ describe('NlpSampleEntityRepository', () => {
|
||||
let languages: Language[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installNlpSampleEntityFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -63,22 +62,20 @@ describe('NlpSampleEntityRepository', () => {
|
||||
NlpEntityRepository,
|
||||
NlpValueRepository,
|
||||
LanguageRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
nlpSampleEntityRepository = module.get<NlpSampleEntityRepository>(
|
||||
NlpSampleEntityRepository,
|
||||
);
|
||||
nlpEntityRepository = module.get<NlpEntityRepository>(NlpEntityRepository);
|
||||
languageRepository = module.get<LanguageRepository>(LanguageRepository);
|
||||
});
|
||||
[nlpSampleEntityRepository, nlpEntityRepository, languageRepository] =
|
||||
await getMocks([
|
||||
NlpSampleEntityRepository,
|
||||
NlpEntityRepository,
|
||||
LanguageRepository,
|
||||
]);
|
||||
nlpSampleEntities = await nlpSampleEntityRepository.findAll();
|
||||
nlpEntities = await nlpEntityRepository.findAll();
|
||||
languages = await languageRepository.findAll();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model } from 'mongoose';
|
||||
|
||||
@@ -27,11 +26,9 @@ export class NlpSampleEntityRepository extends BaseRepository<
|
||||
NlpSampleEntityFull
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(NlpSampleEntity.name) readonly model: Model<NlpSampleEntity>,
|
||||
) {
|
||||
super(
|
||||
eventEmitter,
|
||||
model,
|
||||
NlpSampleEntity,
|
||||
NLP_SAMPLE_ENTITY_POPULATE,
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LanguageRepository } from '@/i18n/repositories/language.repository';
|
||||
import { Language, LanguageModel } from '@/i18n/schemas/language.schema';
|
||||
@@ -20,6 +18,7 @@ import {
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { TFixtures } from '@/utils/test/types';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import {
|
||||
NlpSampleEntity,
|
||||
@@ -43,7 +42,7 @@ describe('NlpSampleRepository', () => {
|
||||
let languages: Language[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installNlpSampleEntityFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -56,14 +55,14 @@ describe('NlpSampleRepository', () => {
|
||||
NlpSampleRepository,
|
||||
NlpSampleEntityRepository,
|
||||
LanguageRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
nlpSampleRepository = module.get<NlpSampleRepository>(NlpSampleRepository);
|
||||
nlpSampleEntityRepository = module.get<NlpSampleEntityRepository>(
|
||||
NlpSampleEntityRepository,
|
||||
);
|
||||
languageRepository = module.get<LanguageRepository>(LanguageRepository);
|
||||
});
|
||||
[nlpSampleRepository, nlpSampleEntityRepository, languageRepository] =
|
||||
await getMocks([
|
||||
NlpSampleRepository,
|
||||
NlpSampleEntityRepository,
|
||||
LanguageRepository,
|
||||
]);
|
||||
noNlpSample = await nlpSampleRepository.findOne({ text: 'No' });
|
||||
nlpSampleEntity = await nlpSampleEntityRepository.findOne({
|
||||
sample: noNlpSample!.id,
|
||||
@@ -71,9 +70,7 @@ describe('NlpSampleRepository', () => {
|
||||
languages = await languageRepository.findAll();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -7,7 +7,6 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Document, Model, Query } from 'mongoose';
|
||||
|
||||
@@ -32,11 +31,10 @@ export class NlpSampleRepository extends BaseRepository<
|
||||
TNlpSampleDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(NlpSample.name) readonly model: Model<NlpSample>,
|
||||
private readonly nlpSampleEntityRepository: NlpSampleEntityRepository,
|
||||
) {
|
||||
super(eventEmitter, model, NlpSample, NLP_SAMPLE_POPULATE, NlpSampleFull);
|
||||
super(model, NlpSample, NLP_SAMPLE_POPULATE, NlpSampleFull);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { nlpEntityFixtures } from '@/utils/test/fixtures/nlpentity';
|
||||
import { installNlpSampleEntityFixtures } from '@/utils/test/fixtures/nlpsampleentity';
|
||||
@@ -19,6 +17,7 @@ import {
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { TFixtures } from '@/utils/test/types';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { NlpEntityModel } from '../schemas/nlp-entity.schema';
|
||||
import { NlpSampleEntityModel } from '../schemas/nlp-sample-entity.schema';
|
||||
@@ -37,7 +36,7 @@ describe('NlpValueRepository', () => {
|
||||
let nlpValues: NlpValue[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installNlpSampleEntityFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -46,18 +45,17 @@ describe('NlpValueRepository', () => {
|
||||
NlpEntityModel,
|
||||
]),
|
||||
],
|
||||
providers: [NlpValueRepository, NlpSampleEntityRepository, EventEmitter2],
|
||||
}).compile();
|
||||
nlpValueRepository = module.get<NlpValueRepository>(NlpValueRepository);
|
||||
nlpSampleEntityRepository = module.get<NlpSampleEntityRepository>(
|
||||
providers: [NlpValueRepository, NlpSampleEntityRepository],
|
||||
});
|
||||
[nlpValueRepository, nlpSampleEntityRepository] = await getMocks([
|
||||
NlpValueRepository,
|
||||
NlpSampleEntityRepository,
|
||||
);
|
||||
]);
|
||||
|
||||
nlpValues = await nlpValueRepository.findAll();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -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.
|
||||
@@ -7,12 +7,21 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Document, Model, Query } from 'mongoose';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import {
|
||||
Document,
|
||||
Model,
|
||||
PipelineStage,
|
||||
Query,
|
||||
SortOrder,
|
||||
Types,
|
||||
} from 'mongoose';
|
||||
|
||||
import { BaseRepository, DeleteResult } from '@/utils/generics/base-repository';
|
||||
import { PageQueryDto } from '@/utils/pagination/pagination-query.dto';
|
||||
import { TFilterQuery } from '@/utils/types/filter.types';
|
||||
import { Format } from '@/utils/types/format.types';
|
||||
|
||||
import { NlpValueDto } from '../dto/nlp-value.dto';
|
||||
import {
|
||||
@@ -20,7 +29,10 @@ import {
|
||||
NlpValue,
|
||||
NlpValueDocument,
|
||||
NlpValueFull,
|
||||
NlpValueFullWithCount,
|
||||
NlpValuePopulate,
|
||||
NlpValueWithCount,
|
||||
TNlpValueCount,
|
||||
} from '../schemas/nlp-value.schema';
|
||||
|
||||
import { NlpSampleEntityRepository } from './nlp-sample-entity.repository';
|
||||
@@ -33,11 +45,10 @@ export class NlpValueRepository extends BaseRepository<
|
||||
NlpValueDto
|
||||
> {
|
||||
constructor(
|
||||
readonly eventEmitter: EventEmitter2,
|
||||
@InjectModel(NlpValue.name) readonly model: Model<NlpValue>,
|
||||
private readonly nlpSampleEntityRepository: NlpSampleEntityRepository,
|
||||
) {
|
||||
super(eventEmitter, model, NlpValue, NLP_VALUE_POPULATE, NlpValueFull);
|
||||
super(model, NlpValue, NLP_VALUE_POPULATE, NlpValueFull);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,4 +119,139 @@ export class NlpValueRepository extends BaseRepository<
|
||||
throw new Error('Attempted to delete a NLP value using unknown criteria');
|
||||
}
|
||||
}
|
||||
|
||||
private getSortDirection(sortOrder: SortOrder) {
|
||||
return typeof sortOrder === 'number'
|
||||
? sortOrder
|
||||
: sortOrder.toString().toLowerCase() === 'desc'
|
||||
? -1
|
||||
: 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an aggregation to retrieve NLP values with their sample counts.
|
||||
*
|
||||
* @param format - The format can be full or stub
|
||||
* @param pageQuery - The pagination parameters
|
||||
* @param filterQuery - The filter criteria
|
||||
* @returns Aggregated Nlp Value results with sample counts
|
||||
*/
|
||||
private async aggregateWithCount<F extends Format>(
|
||||
format: F,
|
||||
{
|
||||
limit = 10,
|
||||
skip = 0,
|
||||
sort = ['createdAt', 'desc'],
|
||||
}: PageQueryDto<NlpValue>,
|
||||
{ $and = [], ...rest }: TFilterQuery<NlpValue>,
|
||||
): Promise<TNlpValueCount<F>[]> {
|
||||
const pipeline: PipelineStage[] = [
|
||||
{
|
||||
$match: {
|
||||
...rest,
|
||||
...($and.length
|
||||
? {
|
||||
$and: $and.map(({ entity, ...rest }) => ({
|
||||
...rest,
|
||||
...(entity
|
||||
? { entity: new Types.ObjectId(String(entity)) }
|
||||
: {}),
|
||||
})),
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
},
|
||||
{
|
||||
$skip: skip,
|
||||
},
|
||||
{
|
||||
$limit: limit,
|
||||
},
|
||||
{
|
||||
$lookup: {
|
||||
from: 'nlpsampleentities',
|
||||
localField: '_id',
|
||||
foreignField: 'value',
|
||||
as: '_sampleEntities',
|
||||
},
|
||||
},
|
||||
{
|
||||
$unwind: {
|
||||
path: '$_sampleEntities',
|
||||
preserveNullAndEmptyArrays: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: '$_id',
|
||||
_originalDoc: {
|
||||
$first: {
|
||||
$unsetField: { input: '$$ROOT', field: 'nlpSamplesCount' },
|
||||
},
|
||||
},
|
||||
nlpSamplesCount: {
|
||||
$sum: { $cond: [{ $ifNull: ['$_sampleEntities', false] }, 1, 0] },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
$replaceWith: {
|
||||
$mergeObjects: [
|
||||
'$_originalDoc',
|
||||
{ nlpSamplesCount: '$nlpSamplesCount' },
|
||||
],
|
||||
},
|
||||
},
|
||||
...(format === Format.FULL
|
||||
? [
|
||||
{
|
||||
$lookup: {
|
||||
from: 'nlpentities',
|
||||
localField: 'entity',
|
||||
foreignField: '_id',
|
||||
as: 'entity',
|
||||
},
|
||||
},
|
||||
{
|
||||
$unwind: '$entity',
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
$sort: {
|
||||
[sort[0]]: this.getSortDirection(sort[1]),
|
||||
_id: this.getSortDirection(sort[1]),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return await this.model.aggregate<TNlpValueCount<F>>(pipeline).exec();
|
||||
}
|
||||
|
||||
async findWithCount<F extends Format>(
|
||||
format: F,
|
||||
pageQuery: PageQueryDto<NlpValue>,
|
||||
filterQuery: TFilterQuery<NlpValue>,
|
||||
): Promise<TNlpValueCount<F>[]> {
|
||||
try {
|
||||
const aggregatedResults = await this.aggregateWithCount(
|
||||
format,
|
||||
pageQuery,
|
||||
filterQuery,
|
||||
);
|
||||
|
||||
if (format === Format.FULL) {
|
||||
return plainToInstance(NlpValueFullWithCount, aggregatedResults, {
|
||||
excludePrefixes: ['_'],
|
||||
}) as TNlpValueCount<F>[];
|
||||
}
|
||||
|
||||
return plainToInstance(NlpValueWithCount, aggregatedResults, {
|
||||
excludePrefixes: ['_'],
|
||||
}) as TNlpValueCount<F>[];
|
||||
} catch (error) {
|
||||
this.logger.error(`Error in findWithCount: ${error.message}`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
TFilterPopulateFields,
|
||||
THydratedDocument,
|
||||
} from '@/utils/types/filter.types';
|
||||
import { TStubOrFull } from '@/utils/types/format.types';
|
||||
|
||||
import { NlpEntity, NlpEntityFull } from './nlp-entity.schema';
|
||||
import { NlpValueMap } from './types';
|
||||
@@ -106,6 +107,14 @@ export class NlpValueFull extends NlpValueStub {
|
||||
entity: NlpEntity;
|
||||
}
|
||||
|
||||
export class NlpValueWithCount extends NlpValue {
|
||||
nlpSamplesCount: number;
|
||||
}
|
||||
|
||||
export class NlpValueFullWithCount extends NlpValueFull {
|
||||
nlpSamplesCount: number;
|
||||
}
|
||||
|
||||
export type NlpValueDocument = THydratedDocument<NlpValue>;
|
||||
|
||||
export const NlpValueModel: ModelDefinition = LifecycleHookManager.attach({
|
||||
@@ -121,3 +130,9 @@ export type NlpValuePopulate = keyof TFilterPopulateFields<
|
||||
>;
|
||||
|
||||
export const NLP_VALUE_POPULATE: NlpValuePopulate[] = ['entity'];
|
||||
|
||||
export type TNlpValueCount<T> = TStubOrFull<
|
||||
T,
|
||||
NlpValueWithCount,
|
||||
NlpValueFullWithCount
|
||||
>;
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { nlpEntityFixtures } from '@/utils/test/fixtures/nlpentity';
|
||||
import { installNlpValueFixtures } from '@/utils/test/fixtures/nlpvalue';
|
||||
@@ -17,6 +15,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
|
||||
import { NlpSampleEntityRepository } from '../repositories/nlp-sample-entity.repository';
|
||||
@@ -34,7 +33,7 @@ describe('nlpEntityService', () => {
|
||||
let nlpValueRepository: NlpValueRepository;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installNlpValueFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -49,17 +48,17 @@ describe('nlpEntityService', () => {
|
||||
NlpValueService,
|
||||
NlpValueRepository,
|
||||
NlpSampleEntityRepository,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
nlpEntityService = module.get<NlpEntityService>(NlpEntityService);
|
||||
nlpEntityRepository = module.get<NlpEntityRepository>(NlpEntityRepository);
|
||||
nlpValueRepository = module.get<NlpValueRepository>(NlpValueRepository);
|
||||
});
|
||||
[nlpEntityService, nlpEntityRepository, nlpValueRepository] =
|
||||
await getMocks([
|
||||
NlpEntityService,
|
||||
NlpEntityRepository,
|
||||
NlpValueRepository,
|
||||
]);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -6,9 +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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LanguageRepository } from '@/i18n/repositories/language.repository';
|
||||
import { Language, LanguageModel } from '@/i18n/schemas/language.schema';
|
||||
@@ -24,6 +22,7 @@ import {
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { TFixtures } from '@/utils/test/types';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { NlpSampleEntityCreateDto } from '../dto/nlp-sample-entity.dto';
|
||||
import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
|
||||
@@ -58,7 +57,7 @@ describe('NlpSampleEntityService', () => {
|
||||
let nlpValueService: NlpValueService;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installNlpSampleEntityFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -77,22 +76,25 @@ describe('NlpSampleEntityService', () => {
|
||||
NlpSampleEntityService,
|
||||
NlpEntityService,
|
||||
NlpValueService,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
nlpSampleEntityService = module.get<NlpSampleEntityService>(
|
||||
});
|
||||
[
|
||||
nlpSampleEntityService,
|
||||
nlpSampleEntityRepository,
|
||||
nlpEntityRepository,
|
||||
languageRepository,
|
||||
nlpSampleEntityService,
|
||||
nlpEntityService,
|
||||
nlpValueService,
|
||||
] = await getMocks([
|
||||
NlpSampleEntityService,
|
||||
);
|
||||
nlpSampleEntityRepository = module.get<NlpSampleEntityRepository>(
|
||||
NlpSampleEntityRepository,
|
||||
);
|
||||
nlpEntityRepository = module.get<NlpEntityRepository>(NlpEntityRepository);
|
||||
languageRepository = module.get<LanguageRepository>(LanguageRepository);
|
||||
nlpSampleEntityService = module.get<NlpSampleEntityService>(
|
||||
NlpEntityRepository,
|
||||
LanguageRepository,
|
||||
NlpSampleEntityService,
|
||||
);
|
||||
nlpEntityService = module.get<NlpEntityService>(NlpEntityService);
|
||||
nlpValueService = module.get<NlpValueService>(NlpValueService);
|
||||
NlpEntityService,
|
||||
NlpValueService,
|
||||
]);
|
||||
nlpSampleEntities = await nlpSampleEntityRepository.findAll();
|
||||
nlpEntities = await nlpEntityRepository.findAll();
|
||||
languages = await languageRepository.findAll();
|
||||
|
||||
@@ -8,14 +8,11 @@
|
||||
|
||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { LanguageRepository } from '@/i18n/repositories/language.repository';
|
||||
import { Language, LanguageModel } from '@/i18n/schemas/language.schema';
|
||||
import { LanguageService } from '@/i18n/services/language.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { nlpSampleFixtures } from '@/utils/test/fixtures/nlpsample';
|
||||
import { installNlpSampleEntityFixtures } from '@/utils/test/fixtures/nlpsampleentity';
|
||||
import { getPageQuery } from '@/utils/test/pagination';
|
||||
@@ -23,6 +20,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { NlpSampleEntityCreateDto } from '../dto/nlp-sample-entity.dto';
|
||||
import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
|
||||
@@ -63,7 +61,7 @@ describe('NlpSampleService', () => {
|
||||
let languages: Language[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installNlpSampleEntityFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -85,8 +83,7 @@ describe('NlpSampleService', () => {
|
||||
NlpEntityService,
|
||||
NlpValueService,
|
||||
LanguageService,
|
||||
EventEmitter2,
|
||||
LoggerService,
|
||||
|
||||
{
|
||||
provide: CACHE_MANAGER,
|
||||
useValue: {
|
||||
@@ -96,21 +93,26 @@ describe('NlpSampleService', () => {
|
||||
},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
nlpEntityService = module.get<NlpEntityService>(NlpEntityService);
|
||||
nlpSampleService = module.get<NlpSampleService>(NlpSampleService);
|
||||
nlpSampleEntityService = module.get<NlpSampleEntityService>(
|
||||
});
|
||||
[
|
||||
nlpEntityService,
|
||||
nlpSampleService,
|
||||
nlpSampleEntityService,
|
||||
nlpSampleRepository,
|
||||
nlpSampleEntityRepository,
|
||||
nlpSampleEntityRepository,
|
||||
languageService,
|
||||
languageRepository,
|
||||
] = await getMocks([
|
||||
NlpEntityService,
|
||||
NlpSampleService,
|
||||
NlpSampleEntityService,
|
||||
);
|
||||
nlpSampleRepository = module.get<NlpSampleRepository>(NlpSampleRepository);
|
||||
nlpSampleEntityRepository = module.get<NlpSampleEntityRepository>(
|
||||
NlpSampleRepository,
|
||||
NlpSampleEntityRepository,
|
||||
);
|
||||
nlpSampleEntityRepository = module.get<NlpSampleEntityRepository>(
|
||||
NlpSampleEntityRepository,
|
||||
);
|
||||
languageService = module.get<LanguageService>(LanguageService);
|
||||
languageRepository = module.get<LanguageRepository>(LanguageRepository);
|
||||
LanguageService,
|
||||
LanguageRepository,
|
||||
]);
|
||||
noNlpSample = await nlpSampleService.findOne({ text: 'No' });
|
||||
nlpSampleEntity = await nlpSampleEntityRepository.findOne({
|
||||
sample: noNlpSample!.id,
|
||||
@@ -118,9 +120,7 @@ describe('NlpSampleService', () => {
|
||||
languages = await languageRepository.findAll();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await closeInMongodConnection();
|
||||
});
|
||||
afterAll(closeInMongodConnection);
|
||||
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import Papa from 'papaparse';
|
||||
import { Message } from '@/chat/schemas/message.schema';
|
||||
import { Language } from '@/i18n/schemas/language.schema';
|
||||
import { LanguageService } from '@/i18n/services/language.service';
|
||||
import { LoggerService } from '@/logger/logger.service';
|
||||
import { BaseService } from '@/utils/generics/base-service';
|
||||
import { THydratedDocument } from '@/utils/types/filter.types';
|
||||
|
||||
@@ -47,7 +46,6 @@ export class NlpSampleService extends BaseService<
|
||||
private readonly nlpSampleEntityService: NlpSampleEntityService,
|
||||
private readonly nlpEntityService: NlpEntityService,
|
||||
private readonly languageService: LanguageService,
|
||||
private readonly logger: LoggerService,
|
||||
) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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 { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
import { BaseSchema } from '@/utils/generics/base-schema';
|
||||
import { nlpEntityFixtures } from '@/utils/test/fixtures/nlpentity';
|
||||
@@ -21,6 +19,7 @@ import {
|
||||
closeInMongodConnection,
|
||||
rootMongooseTestModule,
|
||||
} from '@/utils/test/test';
|
||||
import { buildTestingMocks } from '@/utils/test/utils';
|
||||
|
||||
import { NlpEntityRepository } from '../repositories/nlp-entity.repository';
|
||||
import { NlpSampleEntityRepository } from '../repositories/nlp-sample-entity.repository';
|
||||
@@ -44,7 +43,7 @@ describe('NlpValueService', () => {
|
||||
let nlpValues: NlpValue[];
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
const { getMocks } = await buildTestingMocks({
|
||||
imports: [
|
||||
rootMongooseTestModule(installNlpValueFixtures),
|
||||
MongooseModule.forFeature([
|
||||
@@ -59,13 +58,19 @@ describe('NlpValueService', () => {
|
||||
NlpEntityRepository,
|
||||
NlpValueService,
|
||||
NlpEntityService,
|
||||
EventEmitter2,
|
||||
],
|
||||
}).compile();
|
||||
nlpValueService = module.get<NlpValueService>(NlpValueService);
|
||||
nlpEntityService = module.get<NlpEntityService>(NlpEntityService);
|
||||
nlpValueRepository = module.get<NlpValueRepository>(NlpValueRepository);
|
||||
nlpEntityRepository = module.get<NlpEntityRepository>(NlpEntityRepository);
|
||||
});
|
||||
[
|
||||
nlpValueService,
|
||||
nlpEntityService,
|
||||
nlpValueRepository,
|
||||
nlpEntityRepository,
|
||||
] = await getMocks([
|
||||
NlpValueService,
|
||||
NlpEntityService,
|
||||
NlpValueRepository,
|
||||
NlpEntityRepository,
|
||||
]);
|
||||
nlpValues = await nlpValueRepository.findAll();
|
||||
});
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user