mirror of
https://github.com/hexastack/hexabot
synced 2025-06-26 18:27:28 +00:00
Merge pull request #491 from Hexastack/fix/i18n-and-translation-strict-null-check
Some checks failed
Build and Push Docker API Image / build-and-push (push) Has been cancelled
Build and Push Docker Base Image / build-and-push (push) Has been cancelled
Build and Push Docker NLU Image / build-and-push (push) Has been cancelled
Build and Push Docker UI Image / build-and-push (push) Has been cancelled
Some checks failed
Build and Push Docker API Image / build-and-push (push) Has been cancelled
Build and Push Docker Base Image / build-and-push (push) Has been cancelled
Build and Push Docker NLU Image / build-and-push (push) Has been cancelled
Build and Push Docker UI Image / build-and-push (push) Has been cancelled
Fix: i18n and translation strict null check
This commit is contained in:
commit
1683ce5ca0
@ -73,7 +73,7 @@ export const config: Config = {
|
|||||||
grant3rdPartyCookie: true,
|
grant3rdPartyCookie: true,
|
||||||
onlyAllowOrigins: process.env.FRONTEND_ORIGIN
|
onlyAllowOrigins: process.env.FRONTEND_ORIGIN
|
||||||
? process.env.FRONTEND_ORIGIN.split(',').map((origin) => origin.trim())
|
? process.env.FRONTEND_ORIGIN.split(',').map((origin) => origin.trim())
|
||||||
: [undefined], // ['http://example.com', 'https://example.com'],
|
: [], // ['http://example.com', 'https://example.com'],
|
||||||
},
|
},
|
||||||
session: {
|
session: {
|
||||||
secret: process.env.SESSION_SECRET || 'changeme',
|
secret: process.env.SESSION_SECRET || 'changeme',
|
||||||
@ -91,7 +91,9 @@ export const config: Config = {
|
|||||||
emails: {
|
emails: {
|
||||||
isEnabled: process.env.EMAIL_SMTP_ENABLED === 'true' || false,
|
isEnabled: process.env.EMAIL_SMTP_ENABLED === 'true' || false,
|
||||||
smtp: {
|
smtp: {
|
||||||
port: parseInt(process.env.EMAIL_SMTP_PORT) || 25,
|
port: process.env.EMAIL_SMTP_PORT
|
||||||
|
? parseInt(process.env.EMAIL_SMTP_PORT)
|
||||||
|
: 25,
|
||||||
host: process.env.EMAIL_SMTP_HOST || 'localhost',
|
host: process.env.EMAIL_SMTP_HOST || 'localhost',
|
||||||
ignoreTLS: false,
|
ignoreTLS: false,
|
||||||
secure: process.env.EMAIL_SMTP_SECURE === 'true' || false,
|
secure: process.env.EMAIL_SMTP_SECURE === 'true' || false,
|
||||||
|
|||||||
@ -69,7 +69,7 @@ describe('LanguageController', () => {
|
|||||||
}).compile();
|
}).compile();
|
||||||
languageService = module.get<LanguageService>(LanguageService);
|
languageService = module.get<LanguageService>(LanguageService);
|
||||||
languageController = module.get<LanguageController>(LanguageController);
|
languageController = module.get<LanguageController>(LanguageController);
|
||||||
language = await languageService.findOne({ code: 'en' });
|
language = (await languageService.findOne({ code: 'en' })) as Language;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(jest.clearAllMocks);
|
afterEach(jest.clearAllMocks);
|
||||||
@ -92,7 +92,7 @@ describe('LanguageController', () => {
|
|||||||
|
|
||||||
expect(languageService.findOne).toHaveBeenCalledWith(language.id);
|
expect(languageService.findOne).toHaveBeenCalledWith(language.id);
|
||||||
expect(result).toEqualPayload(
|
expect(result).toEqualPayload(
|
||||||
languageFixtures.find(({ code }) => code === language.code),
|
languageFixtures.find(({ code }) => code === language.code) as Language,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -142,7 +142,9 @@ describe('LanguageController', () => {
|
|||||||
it('should mark a language as default', async () => {
|
it('should mark a language as default', async () => {
|
||||||
jest.spyOn(languageService, 'updateOne');
|
jest.spyOn(languageService, 'updateOne');
|
||||||
const translationUpdateDto = { isDefault: true };
|
const translationUpdateDto = { isDefault: true };
|
||||||
const frLang = await languageService.findOne({ code: 'fr' });
|
const frLang = (await languageService.findOne({
|
||||||
|
code: 'fr',
|
||||||
|
})) as Language;
|
||||||
const result = await languageController.updateOne(
|
const result = await languageController.updateOne(
|
||||||
frLang.id,
|
frLang.id,
|
||||||
translationUpdateDto,
|
translationUpdateDto,
|
||||||
@ -157,7 +159,9 @@ describe('LanguageController', () => {
|
|||||||
...translationUpdateDto,
|
...translationUpdateDto,
|
||||||
});
|
});
|
||||||
|
|
||||||
const enLang = await languageService.findOne({ code: 'en' });
|
const enLang = (await languageService.findOne({
|
||||||
|
code: 'en',
|
||||||
|
})) as Language;
|
||||||
expect(enLang.isDefault).toBe(false);
|
expect(enLang.isDefault).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -171,7 +175,9 @@ describe('LanguageController', () => {
|
|||||||
|
|
||||||
describe('deleteOne', () => {
|
describe('deleteOne', () => {
|
||||||
it('should throw when attempting to delete the default language', async () => {
|
it('should throw when attempting to delete the default language', async () => {
|
||||||
const defaultLang = await languageService.findOne({ isDefault: true });
|
const defaultLang = (await languageService.findOne({
|
||||||
|
isDefault: true,
|
||||||
|
})) as Language;
|
||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
languageController.deleteOne(defaultLang.id),
|
languageController.deleteOne(defaultLang.id),
|
||||||
|
|||||||
@ -141,7 +141,9 @@ describe('TranslationController', () => {
|
|||||||
translationController = module.get<TranslationController>(
|
translationController = module.get<TranslationController>(
|
||||||
TranslationController,
|
TranslationController,
|
||||||
);
|
);
|
||||||
translation = await translationService.findOne({ str: 'Welcome' });
|
translation = (await translationService.findOne({
|
||||||
|
str: 'Welcome',
|
||||||
|
})) as Translation;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(jest.clearAllMocks);
|
afterEach(jest.clearAllMocks);
|
||||||
@ -164,7 +166,9 @@ describe('TranslationController', () => {
|
|||||||
|
|
||||||
expect(translationService.findOne).toHaveBeenCalledWith(translation.id);
|
expect(translationService.findOne).toHaveBeenCalledWith(translation.id);
|
||||||
expect(result).toEqualPayload(
|
expect(result).toEqualPayload(
|
||||||
translationFixtures.find(({ str }) => str === translation.str),
|
translationFixtures.find(
|
||||||
|
({ str }) => str === translation.str,
|
||||||
|
) as Translation,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import {
|
|||||||
forwardRef,
|
forwardRef,
|
||||||
Global,
|
Global,
|
||||||
Inject,
|
Inject,
|
||||||
|
InternalServerErrorException,
|
||||||
Module,
|
Module,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { HttpAdapterHost } from '@nestjs/core';
|
import { HttpAdapterHost } from '@nestjs/core';
|
||||||
@ -54,6 +55,11 @@ export class I18nModule extends NativeI18nModule {
|
|||||||
|
|
||||||
static forRoot(options: I18nOptions): DynamicModule {
|
static forRoot(options: I18nOptions): DynamicModule {
|
||||||
const { imports, providers, controllers, exports } = super.forRoot(options);
|
const { imports, providers, controllers, exports } = super.forRoot(options);
|
||||||
|
if (!providers || !exports) {
|
||||||
|
throw new InternalServerErrorException(
|
||||||
|
'I18n: Unable to find providers and/or exports forRoot()',
|
||||||
|
);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
module: I18nModule,
|
module: I18nModule,
|
||||||
imports: (imports || []).concat([
|
imports: (imports || []).concat([
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
|
* 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 { Injectable, InternalServerErrorException } from '@nestjs/common';
|
||||||
import {
|
import {
|
||||||
I18nService as NativeI18nService,
|
I18nService as NativeI18nService,
|
||||||
Path,
|
Path,
|
||||||
@ -34,6 +34,11 @@ export class I18nService<
|
|||||||
...options,
|
...options,
|
||||||
};
|
};
|
||||||
let { lang } = options;
|
let { lang } = options;
|
||||||
|
|
||||||
|
if (!lang) {
|
||||||
|
throw new InternalServerErrorException('I18nService: lang is undefined');
|
||||||
|
}
|
||||||
|
|
||||||
lang = this.resolveLanguage(lang);
|
lang = this.resolveLanguage(lang);
|
||||||
|
|
||||||
// Translate block message, button text, ...
|
// Translate block message, button text, ...
|
||||||
|
|||||||
@ -7,7 +7,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
import { CACHE_MANAGER } from '@nestjs/cache-manager';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import {
|
||||||
|
Inject,
|
||||||
|
Injectable,
|
||||||
|
InternalServerErrorException,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { Cache } from 'cache-manager';
|
import { Cache } from 'cache-manager';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -53,7 +57,13 @@ export class LanguageService extends BaseService<Language> {
|
|||||||
*/
|
*/
|
||||||
@Cacheable(DEFAULT_LANGUAGE_CACHE_KEY)
|
@Cacheable(DEFAULT_LANGUAGE_CACHE_KEY)
|
||||||
async getDefaultLanguage() {
|
async getDefaultLanguage() {
|
||||||
return await this.findOne({ isDefault: true });
|
const defaultLanguage = await this.findOne({ isDefault: true });
|
||||||
|
if (!defaultLanguage) {
|
||||||
|
throw new InternalServerErrorException(
|
||||||
|
'Default language not found: getDefaultLanguage()',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return defaultLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -100,6 +100,7 @@ export class TranslationService extends BaseService<Translation> {
|
|||||||
}
|
}
|
||||||
// Add fallback messages
|
// Add fallback messages
|
||||||
if (
|
if (
|
||||||
|
block.options &&
|
||||||
'fallback' in block.options &&
|
'fallback' in block.options &&
|
||||||
block.options.fallback &&
|
block.options.fallback &&
|
||||||
'message' in block.options.fallback &&
|
'message' in block.options.fallback &&
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import { I18nService } from '@/i18n/services/i18n.service';
|
|||||||
import { LanguageService } from '@/i18n/services/language.service';
|
import { LanguageService } from '@/i18n/services/language.service';
|
||||||
import { LoggerService } from '@/logger/logger.service';
|
import { LoggerService } from '@/logger/logger.service';
|
||||||
import { getRandom } from '@/utils/helpers/safeRandom';
|
import { getRandom } from '@/utils/helpers/safeRandom';
|
||||||
|
import { installLanguageFixtures } from '@/utils/test/fixtures/language';
|
||||||
import { installUserFixtures } from '@/utils/test/fixtures/user';
|
import { installUserFixtures } from '@/utils/test/fixtures/user';
|
||||||
import {
|
import {
|
||||||
closeInMongodConnection,
|
closeInMongodConnection,
|
||||||
@ -43,7 +44,7 @@ import { RoleRepository } from '../repositories/role.repository';
|
|||||||
import { UserRepository } from '../repositories/user.repository';
|
import { UserRepository } from '../repositories/user.repository';
|
||||||
import { InvitationModel } from '../schemas/invitation.schema';
|
import { InvitationModel } from '../schemas/invitation.schema';
|
||||||
import { PermissionModel } from '../schemas/permission.schema';
|
import { PermissionModel } from '../schemas/permission.schema';
|
||||||
import { RoleModel, Role } from '../schemas/role.schema';
|
import { Role, RoleModel } from '../schemas/role.schema';
|
||||||
import { UserModel } from '../schemas/user.schema';
|
import { UserModel } from '../schemas/user.schema';
|
||||||
import { InvitationService } from '../services/invitation.service';
|
import { InvitationService } from '../services/invitation.service';
|
||||||
import { PermissionService } from '../services/permission.service';
|
import { PermissionService } from '../services/permission.service';
|
||||||
@ -66,7 +67,10 @@ describe('AuthController', () => {
|
|||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
controllers: [LocalAuthController],
|
controllers: [LocalAuthController],
|
||||||
imports: [
|
imports: [
|
||||||
rootMongooseTestModule(installUserFixtures),
|
rootMongooseTestModule(async () => {
|
||||||
|
await installLanguageFixtures();
|
||||||
|
await installUserFixtures();
|
||||||
|
}),
|
||||||
MongooseModule.forFeature([
|
MongooseModule.forFeature([
|
||||||
UserModel,
|
UserModel,
|
||||||
RoleModel,
|
RoleModel,
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import { I18nService } from '@/i18n/services/i18n.service';
|
|||||||
import { LanguageService } from '@/i18n/services/language.service';
|
import { LanguageService } from '@/i18n/services/language.service';
|
||||||
import { LoggerService } from '@/logger/logger.service';
|
import { LoggerService } from '@/logger/logger.service';
|
||||||
import { IGNORED_TEST_FIELDS } from '@/utils/test/constants';
|
import { IGNORED_TEST_FIELDS } from '@/utils/test/constants';
|
||||||
|
import { installLanguageFixtures } from '@/utils/test/fixtures/language';
|
||||||
import { installPermissionFixtures } from '@/utils/test/fixtures/permission';
|
import { installPermissionFixtures } from '@/utils/test/fixtures/permission';
|
||||||
import { getUserFixtures, userFixtures } from '@/utils/test/fixtures/user';
|
import { getUserFixtures, userFixtures } from '@/utils/test/fixtures/user';
|
||||||
import { getPageQuery } from '@/utils/test/pagination';
|
import { getPageQuery } from '@/utils/test/pagination';
|
||||||
@ -45,8 +46,8 @@ import { RoleRepository } from '../repositories/role.repository';
|
|||||||
import { UserRepository } from '../repositories/user.repository';
|
import { UserRepository } from '../repositories/user.repository';
|
||||||
import { InvitationModel } from '../schemas/invitation.schema';
|
import { InvitationModel } from '../schemas/invitation.schema';
|
||||||
import { PermissionModel } from '../schemas/permission.schema';
|
import { PermissionModel } from '../schemas/permission.schema';
|
||||||
import { RoleModel, Role } from '../schemas/role.schema';
|
import { Role, RoleModel } from '../schemas/role.schema';
|
||||||
import { UserModel, User } from '../schemas/user.schema';
|
import { User, UserModel } from '../schemas/user.schema';
|
||||||
import { PasswordResetService } from '../services/passwordReset.service';
|
import { PasswordResetService } from '../services/passwordReset.service';
|
||||||
import { PermissionService } from '../services/permission.service';
|
import { PermissionService } from '../services/permission.service';
|
||||||
import { RoleService } from '../services/role.service';
|
import { RoleService } from '../services/role.service';
|
||||||
@ -71,7 +72,10 @@ describe('UserController', () => {
|
|||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
controllers: [ReadWriteUserController],
|
controllers: [ReadWriteUserController],
|
||||||
imports: [
|
imports: [
|
||||||
rootMongooseTestModule(installPermissionFixtures),
|
rootMongooseTestModule(async () => {
|
||||||
|
await installLanguageFixtures();
|
||||||
|
await installPermissionFixtures();
|
||||||
|
}),
|
||||||
MongooseModule.forFeature([
|
MongooseModule.forFeature([
|
||||||
UserModel,
|
UserModel,
|
||||||
RoleModel,
|
RoleModel,
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import {
|
|||||||
installInvitationFixtures,
|
installInvitationFixtures,
|
||||||
invitationsFixtures,
|
invitationsFixtures,
|
||||||
} from '@/utils/test/fixtures/invitation';
|
} from '@/utils/test/fixtures/invitation';
|
||||||
|
import { installLanguageFixtures } from '@/utils/test/fixtures/language';
|
||||||
import {
|
import {
|
||||||
closeInMongodConnection,
|
closeInMongodConnection,
|
||||||
rootMongooseTestModule,
|
rootMongooseTestModule,
|
||||||
@ -53,7 +54,10 @@ describe('InvitationService', () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
rootMongooseTestModule(installInvitationFixtures),
|
rootMongooseTestModule(async () => {
|
||||||
|
await installLanguageFixtures();
|
||||||
|
await installInvitationFixtures();
|
||||||
|
}),
|
||||||
MongooseModule.forFeature([
|
MongooseModule.forFeature([
|
||||||
RoleModel,
|
RoleModel,
|
||||||
PermissionModel,
|
PermissionModel,
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import { LanguageModel } from '@/i18n/schemas/language.schema';
|
|||||||
import { I18nService } from '@/i18n/services/i18n.service';
|
import { I18nService } from '@/i18n/services/i18n.service';
|
||||||
import { LanguageService } from '@/i18n/services/language.service';
|
import { LanguageService } from '@/i18n/services/language.service';
|
||||||
import { LoggerService } from '@/logger/logger.service';
|
import { LoggerService } from '@/logger/logger.service';
|
||||||
|
import { installLanguageFixtures } from '@/utils/test/fixtures/language';
|
||||||
import { installUserFixtures, users } from '@/utils/test/fixtures/user';
|
import { installUserFixtures, users } from '@/utils/test/fixtures/user';
|
||||||
import {
|
import {
|
||||||
closeInMongodConnection,
|
closeInMongodConnection,
|
||||||
@ -49,7 +50,10 @@ describe('PasswordResetService', () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
rootMongooseTestModule(installUserFixtures),
|
rootMongooseTestModule(async () => {
|
||||||
|
await installLanguageFixtures();
|
||||||
|
await installUserFixtures();
|
||||||
|
}),
|
||||||
MongooseModule.forFeature([
|
MongooseModule.forFeature([
|
||||||
UserModel,
|
UserModel,
|
||||||
RoleModel,
|
RoleModel,
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { LanguageModel } from '@/i18n/schemas/language.schema';
|
|||||||
import { I18nService } from '@/i18n/services/i18n.service';
|
import { I18nService } from '@/i18n/services/i18n.service';
|
||||||
import { LanguageService } from '@/i18n/services/language.service';
|
import { LanguageService } from '@/i18n/services/language.service';
|
||||||
import { LoggerService } from '@/logger/logger.service';
|
import { LoggerService } from '@/logger/logger.service';
|
||||||
|
import { installLanguageFixtures } from '@/utils/test/fixtures/language';
|
||||||
import { installUserFixtures, users } from '@/utils/test/fixtures/user';
|
import { installUserFixtures, users } from '@/utils/test/fixtures/user';
|
||||||
import {
|
import {
|
||||||
closeInMongodConnection,
|
closeInMongodConnection,
|
||||||
@ -44,7 +45,10 @@ describe('ValidateAccountService', () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
imports: [
|
imports: [
|
||||||
rootMongooseTestModule(installUserFixtures),
|
rootMongooseTestModule(async () => {
|
||||||
|
await installLanguageFixtures();
|
||||||
|
await installUserFixtures();
|
||||||
|
}),
|
||||||
MongooseModule.forFeature([
|
MongooseModule.forFeature([
|
||||||
UserModel,
|
UserModel,
|
||||||
RoleModel,
|
RoleModel,
|
||||||
|
|||||||
4
api/src/utils/test/fixtures/language.ts
vendored
4
api/src/utils/test/fixtures/language.ts
vendored
@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
import mongoose from 'mongoose';
|
import mongoose from 'mongoose';
|
||||||
|
|
||||||
import { LanguageUpdateDto } from '@/i18n/dto/language.dto';
|
import { LanguageCreateDto } from '@/i18n/dto/language.dto';
|
||||||
import { LanguageModel } from '@/i18n/schemas/language.schema';
|
import { LanguageModel } from '@/i18n/schemas/language.schema';
|
||||||
|
|
||||||
export const languageFixtures: LanguageUpdateDto[] = [
|
export const languageFixtures: LanguageCreateDto[] = [
|
||||||
{
|
{
|
||||||
title: 'English',
|
title: 'English',
|
||||||
code: 'en',
|
code: 'en',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user