Skip to content

Commit 9acfa91

Browse files
committed
add api for channel
1 parent 7da89a8 commit 9acfa91

File tree

21 files changed

+414
-75
lines changed

21 files changed

+414
-75
lines changed

server/.vscode/settings.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55
},
66
"editor.formatOnSave": true,
77
"editor.defaultFormatter": "esbenp.prettier-vscode",
8-
"editor.formatOnSaveMode": "file"
8+
"editor.formatOnSaveMode": "file",
9+
"[typescript]": {
10+
"editor.defaultFormatter": "vscode.typescript-language-features"
11+
}
912
}

server/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"lodash": "^4.17.21",
5151
"mime": "^4.0.1",
5252
"mime-types": "^2.1.35",
53+
"moment": "^2.30.1",
5354
"morgan": "^1.10.0",
5455
"multer": "1.4.5-lts.1",
5556
"nodemailer": "^6.9.8",

server/src/constants/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ export const ENDPOINTS = {
2525
SINGLE: '/upload/single',
2626
MULTIPLE: '/upload/multiple',
2727
},
28-
CHANNEL: '/channel',
28+
CHANNEL: {
29+
INDEX: '/channel',
30+
DELETE: '/channel/delete',
31+
DELETES: '/channel/deletes',
32+
}
2933
};
3034

3135
export const LOCALE_KEY = 'lang';
Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,50 @@
1+
import { LOCALE_KEY } from "@/constants";
2+
import { PagingDTO } from "@/dtos/paging.dto";
3+
import { LocaleService } from "@/i18n/ctx";
14
import { ChannelService } from "@/services/channels.service";
25
import { catchAsync } from "@/utils/catch-async";
6+
import { plainToClass } from "class-transformer";
7+
import { validateOrReject } from "class-validator";
38
import { StatusCodes } from "http-status-codes";
49
import Container from "typedi";
510

611
export class ChannelController {
712
public channelService = Container.get(ChannelService);
13+
public localeService = Container.get<LocaleService>(LOCALE_KEY);
814

915
public createChannel = catchAsync(async (req, res) => {
10-
const data = await this.channelService.create(req.body);
16+
await this.channelService.create(req.body);
1117
res.status(StatusCodes.OK).json({
12-
message: 'Tạo channel thành công',
13-
data,
18+
message: this.localeService.i18n().CHANNEL.CREATE_SUCCESS(),
1419
});
1520
});
1621

22+
public updateChannel = catchAsync(async (req, res) => {
23+
await this.channelService.updateById(req.params.id, req.body);
24+
res.status(StatusCodes.OK).json({
25+
message: this.localeService.i18n().CHANNEL.UPDATE_SUCCESS(),
26+
});
27+
})
28+
29+
public deleteChannel = catchAsync(async (req, res) => {
30+
await this.channelService.deleteById(req.params.id);
31+
res.status(StatusCodes.OK).json({
32+
message: this.localeService.i18n().CHANNEL.DELETE_CHANNEL_SUCCESS(),
33+
});
34+
})
35+
36+
public deleteMultipleChannel = catchAsync(async (req, res) => {
37+
await this.channelService.deleteByIds(req.body.id);
38+
res.status(StatusCodes.OK).json({
39+
message: this.localeService.i18n().CHANNEL.DELETE_MULTIPLE_CHANNELS_SUCCESS(),
40+
});
41+
})
42+
43+
public getChannelsPaging = catchAsync(async (req, res) => {
44+
const paging = plainToClass(PagingDTO, req.query);
45+
await validateOrReject(paging);
46+
47+
const result = await this.channelService.getChannelsPaging(paging);
48+
res.status(StatusCodes.OK).json({ result });
49+
})
1750
}

server/src/database/migrations/meta/_journal.json

Whitespace-only changes.

server/src/database/schema.ts

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,15 @@
1+
import { createId } from '@paralleldrive/cuid2';
2+
import { relations } from 'drizzle-orm';
13
import {
2-
integer,
4+
boolean,
35
pgEnum,
46
pgTable,
57
text,
68
timestamp,
7-
varchar,
8-
doublePrecision,
9-
index,
109
uniqueIndex,
11-
primaryKey,
12-
json,
13-
boolean,
14-
serial,
10+
varchar
1511
} from 'drizzle-orm/pg-core';
16-
import { createId } from '@paralleldrive/cuid2';
1712
import { MAX_ID_LENGTH } from '../constants';
18-
import { relations } from 'drizzle-orm';
1913

2014
export const roles = pgEnum('roles', ['ADMIN', 'USER']);
2115

@@ -43,27 +37,35 @@ export const users = pgTable(
4337
);
4438

4539
export const channelTypes = pgTable(
46-
'channel_types', // cho nay minh theo conversation channel_types nha
40+
'channel_types',
4741
{
48-
id: serial('id')
49-
.primaryKey(),
42+
id: varchar('id', {
43+
length: MAX_ID_LENGTH,
44+
})
45+
.primaryKey()
46+
.$defaultFn(() => createId()),
5047
name: text('name').unique().notNull(),
5148
description: text('description').unique().notNull(),
49+
deleted: boolean('deleted').default(false),
5250
}
5351
)
5452

5553
export const channels = pgTable(
5654
'channels',
5755
{
58-
id: serial('id')
59-
.primaryKey(),
56+
id: varchar('id', {
57+
length: MAX_ID_LENGTH,
58+
})
59+
.primaryKey()
60+
.$defaultFn(() => createId()),
6061
contactId: text('contact_id').unique().notNull(),
6162
contactName: text('contact_name').notNull(),
6263
credentials: text('credentials'),
6364
active: boolean('active'),
64-
channelTypeId: integer('channel_type_id').notNull(),
65+
deleted: boolean('deleted').default(false),
66+
channelTypeId: text('channel_type_id').notNull(),
6567
createdAt: timestamp('created_at').defaultNow(),
66-
updatedAt: timestamp('update_at').defaultNow(),
68+
updatedAt: timestamp('updated_at'),
6769
}
6870
)
6971

server/src/database/seed.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import * as bcrypt from 'bcrypt';
12
import { db } from "./db";
2-
import { channelTypes } from "./schema";
3+
import { channelTypes, users } from "./schema";
34

45
async function seedChannelTypes() {
56
try {
@@ -15,4 +16,14 @@ async function seedChannelTypes() {
1516
}
1617
}
1718

18-
seedChannelTypes();
19+
async function seedDefaultAccount() {
20+
try {
21+
const hashedPassword = await bcrypt.hash("Hello@123", 10);
22+
await db.insert(users).values({email: "[email protected]", password: hashedPassword, name: "admin",});
23+
} catch (error) {
24+
console.error(`Can't create default account`);
25+
}
26+
}
27+
28+
seedChannelTypes();
29+
seedDefaultAccount();

server/src/dtos/channels.dto.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,37 @@
1-
import { IsBoolean, IsNotEmpty, IsNumber, IsString } from "class-validator";
1+
import { getCurrentLocale } from '@/i18n/get-current';
2+
import { Transform } from "class-transformer";
3+
import { IsArray, IsBoolean, IsNotEmpty, IsString } from "class-validator";
24

3-
export class channelDTO {
5+
export class ChannelDTO {
46
@IsString()
57
@IsNotEmpty({
6-
message: 'ContactID không được bỏ trống',
8+
message: () => getCurrentLocale().VALIDATE.REQUIRED({ field: 'ContactId' }),
79
})
10+
@Transform(({ value }) => value.trim())
811
contactId: string;
912

1013
@IsString()
1114
@IsNotEmpty({
12-
message: 'Contact name không được bỏ trống',
15+
message: () => getCurrentLocale().VALIDATE.REQUIRED({ field: 'Contact name' }),
1316
})
17+
@Transform(({ value }) => value.trim())
1418
contactName: string;
1519

16-
@IsNumber()
20+
@IsString()
1721
@IsNotEmpty({
18-
message: 'Channel type không được bỏ trống',
22+
message: () => getCurrentLocale().VALIDATE.REQUIRED({ field: 'Channel type' }),
1923
})
20-
channelTypeId: number;
24+
channelTypeId: string;
2125

2226
@IsString()
2327
credentials: string;
2428

2529
@IsBoolean()
2630
active: boolean | false;
31+
}
32+
33+
export class DeleteChannelDTO {
34+
@IsArray()
35+
@Transform(({ value }) => value ?? [])
36+
id: string[];
2737
}

server/src/dtos/paging.dto.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Transform, Type } from "class-transformer";
2+
import { IsNumber, IsOptional, IsString } from "class-validator";
3+
4+
export class PagingDTO {
5+
@IsNumber()
6+
@Type(() => Number)
7+
@Transform(({ value }) => parseInt(value) ?? 1)
8+
@IsOptional()
9+
page: number | 0;
10+
11+
@IsNumber()
12+
@Type(() => Number)
13+
@Transform(({ value }) => parseInt(value) ?? 20)
14+
@IsOptional()
15+
limit: number | 20;
16+
17+
@IsString()
18+
@IsOptional()
19+
orderBy: string;
20+
21+
@IsString()
22+
@Transform(({ value }) => value ?? 'asc')
23+
@IsOptional()
24+
sortType: 'asc' | 'desc';
25+
26+
@IsString()
27+
@IsOptional()
28+
q: string;
29+
}

server/src/i18n/en/channel.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const CHANNEL = {
2+
CREATE_FAILED: 'Create channel failed!',
3+
CREATE_SUCCESS: 'Create channel success!',
4+
CONTACTID_EXISTED: 'ContactId existed!',
5+
NOT_FOUND: "Can not find channel!",
6+
UPDATE_SUCCESS: 'Update channel success!',
7+
UPDATE_FAILED: 'Update channel failed!',
8+
DELETE_CHANNEL_SUCCESS: 'Delete channel success!',
9+
DELETE_MULTIPLE_CHANNELS_SUCCESS: 'Delete multiple channels success!',
10+
};

0 commit comments

Comments
 (0)