Skip to content

Commit c809238

Browse files
authored
Merge pull request #1637 from line/dev
release: 7.2522.91
2 parents d5deb69 + 958cad5 commit c809238

File tree

248 files changed

+9126
-6625
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

248 files changed

+9126
-6625
lines changed

.github/workflows/integration-test.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ jobs:
3636
image: opensearchproject/opensearch:2.17.1
3737
env:
3838
discovery.type: single-node
39-
bootstrap.memory_lock: "true"
40-
plugins.security.disabled: "true"
41-
OPENSEARCH_INITIAL_ADMIN_PASSWORD: "UserFeedback123!@#"
39+
bootstrap.memory_lock: 'true'
40+
plugins.security.disabled: 'true'
41+
OPENSEARCH_INITIAL_ADMIN_PASSWORD: 'UserFeedback123!@#'
4242
options: >-
4343
--health-cmd="curl -s http://localhost:9200/_cluster/health | grep -q '\"status\":\"green\"'"
4444
--health-interval=10s
@@ -54,6 +54,7 @@ jobs:
5454
- name: Setup integration test (with opensearch)
5555
run: |
5656
npm install -g corepack@latest
57+
corepack enable
5758
pnpm install --frozen-lockfile
5859
pnpm build
5960
echo "BASE_URL=http://localhost:3000" >> ./apps/api/.env

.npmrc

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
node-linker=hoisted
2-
hoist-pattern[]=!bcrypt
3-
# hoist-pattern[]=!*typeorm*
4-
# hoist-pattern[]=!*nestjs*
1+
node-linker=hoisted

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
22.14.0
1+
22.16.0

apps/api/integration-test/test-specs/feedback.integration-spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ describe('FeedbackController (integration)', () => {
385385
{
386386
key: 'createdAt',
387387
value: {
388-
gte: DateTime.fromJSDate(new Date(0)).toFormat('yyyy-MM-dd'),
388+
gte: DateTime.now().minus({ years: 1 }).toFormat('yyyy-MM-dd'),
389389
lt: DateTime.now().toFormat('yyyy-MM-dd'),
390390
},
391391
condition: QueryV2ConditionsEnum.BETWEEN,

apps/api/integration-test/test-specs/tenant.integration-spec.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ import {
3232
import type { GetTenantResponseDto } from '@/domains/admin/tenant/dtos/responses';
3333
import { TenantEntity } from '@/domains/admin/tenant/tenant.entity';
3434
import { UserEntity } from '@/domains/admin/user/entities/user.entity';
35-
import { clearAllEntities, signInTestUser } from '@/test-utils/util-functions';
35+
import {
36+
clearAllEntities,
37+
clearEntities,
38+
signInTestUser,
39+
} from '@/test-utils/util-functions';
3640
import { HttpStatusCode } from '@/types/http-status';
3741

3842
describe('TenantController (integration)', () => {
@@ -102,7 +106,7 @@ describe('TenantController (integration)', () => {
102106
});
103107

104108
afterAll(async () => {
105-
await tenantRepo.delete({});
109+
await clearEntities([tenantRepo]);
106110
});
107111
});
108112

@@ -137,7 +141,7 @@ describe('TenantController (integration)', () => {
137141
});
138142
});
139143
it('should fail to find a tenant', async () => {
140-
await tenantRepo.delete({});
144+
await clearEntities([tenantRepo]);
141145

142146
const dto = new UpdateTenantRequestDto();
143147

@@ -166,8 +170,7 @@ describe('TenantController (integration)', () => {
166170
describe('/admin/tenants (GET)', () => {
167171
const dto = new SetupTenantRequestDto();
168172
beforeEach(async () => {
169-
await tenantRepo.delete({});
170-
await userRepo.delete({});
173+
await clearEntities([tenantRepo, userRepo]);
171174
dto.siteName = faker.string.sample();
172175
dto.password = '12345678';
173176

apps/api/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,20 @@
4040
"@nestjs/passport": "^11.0.0",
4141
"@nestjs/platform-express": "^11.0.0",
4242
"@nestjs/platform-fastify": "^11.0.0",
43-
"@nestjs/schedule": "^5.0.0",
43+
"@nestjs/schedule": "^6.0.0",
4444
"@nestjs/swagger": "^11.0.0",
4545
"@nestjs/terminus": "^11.0.0",
4646
"@nestjs/typeorm": "^11.0.0",
4747
"@opensearch-project/opensearch": "^3.0.0",
48-
"@swc/cli": "^0.6.0",
49-
"@swc/helpers": "^0.5.10",
5048
"@types/passport-jwt": "^4.0.1",
5149
"@types/passport-local": "^1.0.38",
5250
"@ufb/shared": "workspace:*",
5351
"@willsoto/nestjs-prometheus": "^6.0.0",
5452
"axios": "^1.7.2",
55-
"bcrypt": "^5.1.1",
53+
"bcrypt": "^6.0.0",
5654
"class-transformer": "^0.5.1",
5755
"class-validator": "^0.14.1",
58-
"cron": "^3.5.0",
56+
"cron": "^4.3.0",
5957
"dotenv": "^16.4.5",
6058
"exceljs": "^4.4.0",
6159
"fast-csv": "^5.0.1",
@@ -67,7 +65,7 @@
6765
"nestjs-cls": "^5.0.0",
6866
"nestjs-pino": "^4.0.0",
6967
"nestjs-typeorm-paginate": "^4.0.4",
70-
"nodemailer": "^6.9.13",
68+
"nodemailer": "^7.0.0",
7169
"passport": "^0.7.0",
7270
"passport-custom": "^1.1.1",
7371
"passport-jwt": "^4.0.1",
@@ -89,12 +87,14 @@
8987
"@nestjs/schematics": "^11.0.0",
9088
"@nestjs/testing": "^11.0.0",
9189
"@swc-node/jest": "^1.8.0",
90+
"@swc/cli": "0.7.7",
9291
"@swc/core": "^1.4.16",
92+
"@swc/helpers": "^0.5.10",
9393
"@types/bcrypt": "^5.0.2",
9494
"@types/express": "^5.0.0",
9595
"@types/jest": "^29.5.12",
9696
"@types/luxon": "^3.4.2",
97-
"@types/node": "22.14.0",
97+
"@types/node": "22.15.23",
9898
"@types/nodemailer": "^6.4.15",
9999
"@types/passport-jwt": "*",
100100
"@types/supertest": "^6.0.2",

apps/api/src/common/repositories/opensearch.repository.ts

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ import {
2121
Inject,
2222
Injectable,
2323
InternalServerErrorException,
24+
Logger,
2425
NotFoundException,
2526
} from '@nestjs/common';
2627
import { Client, errors } from '@opensearch-project/opensearch';
28+
import { Indices_PutMapping_Response } from '@opensearch-project/opensearch/api';
2729

2830
import type {
2931
CreateDataDto,
@@ -38,38 +40,55 @@ import { LargeWindowException } from './large-window.exception';
3840

3941
@Injectable()
4042
export class OpensearchRepository {
43+
private logger = new Logger(OpensearchRepository.name);
4144
private opensearchClient: Client;
4245
constructor(@Inject('OPENSEARCH_CLIENT') opensearchClient: Client) {
4346
this.opensearchClient = opensearchClient;
4447
}
4548

4649
async createIndex({ index }: CreateIndexDto) {
4750
const indexName = 'channel_' + index;
48-
await this.opensearchClient.indices.create({
49-
index: indexName,
50-
body: {
51-
settings: {
52-
index: { max_ngram_diff: 1 },
53-
analysis: {
54-
analyzer: {
55-
ngram_analyzer: {
56-
type: 'custom',
57-
filter: ['lowercase', 'asciifolding', 'cjk_width'],
58-
tokenizer: 'ngram_tokenizer',
51+
try {
52+
const response = await this.opensearchClient.indices.create({
53+
index: indexName,
54+
body: {
55+
settings: {
56+
index: { max_ngram_diff: 1 },
57+
analysis: {
58+
analyzer: {
59+
ngram_analyzer: {
60+
type: 'custom',
61+
filter: ['lowercase', 'asciifolding', 'cjk_width'],
62+
tokenizer: 'ngram_tokenizer',
63+
},
5964
},
60-
},
61-
tokenizer: {
62-
ngram_tokenizer: {
63-
type: 'ngram',
64-
min_gram: 1,
65-
max_gram: 2,
66-
token_chars: ['letter', 'digit', 'punctuation', 'symbol'],
65+
tokenizer: {
66+
ngram_tokenizer: {
67+
type: 'ngram',
68+
min_gram: 1,
69+
max_gram: 2,
70+
token_chars: ['letter', 'digit', 'punctuation', 'symbol'],
71+
},
6772
},
6873
},
6974
},
7075
},
71-
},
72-
});
76+
});
77+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
78+
if (response) {
79+
this.logger.log(
80+
`Index created successfully: ${JSON.stringify(response.body, null, 2)}`,
81+
);
82+
}
83+
} catch (error) {
84+
this.logger.log(`Error creating index: ${error}`);
85+
if (error?.meta?.body) {
86+
this.logger.log(
87+
`OpenSearch error details:${JSON.stringify(error.meta.body, null, 2)}`,
88+
);
89+
}
90+
throw error;
91+
}
7392
await this.opensearchClient.indices.putAlias({
7493
index: indexName,
7594
name: index,
@@ -82,10 +101,23 @@ export class OpensearchRepository {
82101
});
83102
if (statusCode !== 200) throw new NotFoundException('index is not found');
84103

85-
return await this.opensearchClient.indices.putMapping({
86-
index,
87-
body: { properties: mappings },
88-
});
104+
let response: Indices_PutMapping_Response;
105+
try {
106+
response = await this.opensearchClient.indices.putMapping({
107+
index,
108+
body: { properties: mappings },
109+
});
110+
} catch (error) {
111+
this.logger.log(`Error put mapping: ${error}`);
112+
if (error?.meta?.body) {
113+
this.logger.log(
114+
`OpenSearch error details:${JSON.stringify(error.meta.body, null, 2)}`,
115+
);
116+
}
117+
throw error;
118+
}
119+
120+
return response;
89121
}
90122

91123
async createData({ id, index, data }: CreateDataDto) {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright 2025 LY Corporation
3+
*
4+
* LY Corporation licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
import type { MigrationInterface, QueryRunner } from 'typeorm';
17+
18+
export class AddSearchMaxDaysOnChannel1746153314386
19+
implements MigrationInterface
20+
{
21+
name = 'AddSearchMaxDaysOnChannel1746153314386';
22+
23+
public async up(queryRunner: QueryRunner): Promise<void> {
24+
await queryRunner.query(
25+
`ALTER TABLE \`channels\` ADD \`feedback_search_max_days\` int NOT NULL DEFAULT '365'`,
26+
);
27+
}
28+
29+
public async down(queryRunner: QueryRunner): Promise<void> {
30+
await queryRunner.query(
31+
`ALTER TABLE \`channels\` DROP COLUMN \`feedback_search_max_days\``,
32+
);
33+
}
34+
}

apps/api/src/domains/admin/channel/channel/channel.controller.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ describe('ChannelController', () => {
5454
const dto = new CreateChannelRequestDto();
5555
dto.name = faker.string.sample();
5656
dto.description = faker.string.sample();
57+
dto.feedbackSearchMaxDays = faker.number.int();
5758
dto.fields = [];
5859

5960
await channelController.create(projectId, dto);

apps/api/src/domains/admin/channel/channel/channel.entity.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ export class ChannelEntity extends CommonEntity {
5353
@Column({ type: 'json', nullable: true })
5454
imageConfig: ImageConfig | null;
5555

56+
@Column('int', { default: 365 })
57+
feedbackSearchMaxDays: number;
58+
5659
@ManyToOne(() => ProjectEntity, (project) => project.channels, {
5760
onDelete: 'CASCADE',
5861
})
@@ -87,6 +90,7 @@ export class ChannelEntity extends CommonEntity {
8790
description: string | null,
8891
projectId: number,
8992
imageConfig: ImageConfig | null,
93+
feedbackSearchMaxDays: number,
9094
) {
9195
const channel = new ChannelEntity();
9296
channel.name = name;
@@ -98,6 +102,7 @@ export class ChannelEntity extends CommonEntity {
98102
}
99103
channel.project = new ProjectEntity();
100104
channel.project.id = projectId;
105+
channel.feedbackSearchMaxDays = feedbackSearchMaxDays;
101106

102107
return channel;
103108
}

0 commit comments

Comments
 (0)