Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type I18nTranslations = {
"exception": {
"common": {
"INTERNAL_ERROR": string;
"FORBIDDEN": string;
};
"permission": {
"NOT_FOUND": string;
Expand Down
2 changes: 1 addition & 1 deletion template/nest-next/libs/shared/src/decorator/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { Permission } from './permission.decorator';
export { Permission, PERMISSION_KEYS } from './permission.decorator';
export { Reject } from './reject.decorator';
1 change: 1 addition & 0 deletions template/nest-next/libs/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './pagination';
export * from './constant';
export * from './md5';
export * from './decorator';
export * from './guard';
11 changes: 10 additions & 1 deletion template/nest-next/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { join } from 'path';
import { PermissionModule } from './permission/permission.module';
import { MikroOrmModule } from '@mikro-orm/nestjs';
import { MySqlDriver } from '@mikro-orm/mysql';
import { Permission } from './permission';
import { Permission, PermissionGuard } from './permission';
import { CqrsModule } from '@nestjs/cqrs';
import { MenuModule } from './menu/menu.module';
import { Menu } from './menu/menu.entity';
Expand All @@ -23,6 +23,7 @@ import { readFileSync } from 'fs';
import { randomBytes } from 'crypto';
import { I18Module } from './i18/i18.module';
import { I18n, Lang } from './i18';
import { RejectRequestGuard } from '@app/shared';

@Module({
imports: [
Expand Down Expand Up @@ -122,6 +123,14 @@ import { I18n, Lang } from './i18';
provide: APP_GUARD,
useClass: AuthGuard,
},
{
provide: APP_GUARD,
useClass: PermissionGuard,
},
{
provide: APP_GUARD,
useClass: RejectRequestGuard,
},
],
})
export class AppModule {}
3 changes: 2 additions & 1 deletion template/nest-next/src/i18/dto/batch-remove-i18.dto.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
import { I18nRecordId } from '../i18.entites';

export class BatchRemoveI18Records {
@ApiProperty({
description: '想要删除的国际化字段ID数组',
type: [Number],
})
ids: number[];
ids: I18nRecordId[];
}
46 changes: 46 additions & 0 deletions template/nest-next/src/i18/dto/find-all-i18n.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { ApiProperty } from '@nestjs/swagger';
import { Lang } from './lang-info.dto';
import { PaginationMeta } from '@app/shared';
import type { I18nRecordId } from '../i18.entites';

export class FindAllI18nItem {
@ApiProperty({
description: '国际化字段的自增id',
})
id: I18nRecordId;
@ApiProperty({
description: '国际化字段对应的语言信息',
type: () => Lang,
})
lang: Lang;
@ApiProperty({
description: '国际化字段的键',
})
key: string;
@ApiProperty({
description: '国际化字段的实际内容',
})
content: string;

constructor(id: I18nRecordId, lang: Lang, key: string, content: string) {
this.id = id;
this.lang = lang;
this.key = key;
this.content = content;
}
}

export class FindAllI18n {
@ApiProperty({
type: [FindAllI18nItem],
})
items: FindAllI18nItem[];
@ApiProperty({
type: PaginationMeta,
})
meta: PaginationMeta;
constructor(items: FindAllI18nItem[], meta: PaginationMeta) {
this.items = items;
this.meta = meta;
}
}
146 changes: 145 additions & 1 deletion template/nest-next/src/i18/i18.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,151 @@
import { Controller } from '@nestjs/common';
import {
Body,
Controller,
DefaultValuePipe,
Delete,
Get,
Param,
ParseArrayPipe,
ParseIntPipe,
Patch,
Post,
Query,
} from '@nestjs/common';
import { I18Service } from './i18.service';
import {
ApiCreatedResponse,
ApiOkResponse,
ApiOperation,
ApiParam,
ApiQuery,
} from '@nestjs/swagger';
import { I18 } from './dto/i18n-info.dto';
import { Permission, Reject } from '@app/shared';
import { CreateI18Dto } from './dto/create-i18.dto';
import { BatchRemoveI18Records } from './dto/batch-remove-i18.dto';
import { UpdateI18Dto } from './dto/update-i18.dto';
import type { I18nRecordId, LangId } from './i18.entites';
import { FindAllI18n } from './dto/find-all-i18n.dto';

@Controller('i18')
export class I18Controller {
constructor(private readonly i18Service: I18Service) {}

@ApiOperation({ summary: '创建一个国际化词条' })
@ApiCreatedResponse({ type: I18 })
@Permission('i18n::add')
@Post()
create(@Body() createI18Dto: CreateI18Dto) {
return this.i18Service.create(createI18Dto);
}

@ApiOperation({ summary: '获取格式化后的国际化词条树' })
@ApiOkResponse({
type: Object,
description:
'获取经过格式化后的国际化词条树. 具体签名如下`Record<lang, Record<i18-key, i18-content>>`',
})
@Get('format')
getFormat(@Query('lang') lang: string) {
return this.i18Service.getFormat(lang);
}

@ApiOperation({ summary: '查询国际化' })
@ApiQuery({ name: 'page', description: '页码' })
@ApiQuery({ name: 'limit', description: '页大小' })
@ApiQuery({
name: 'all',
description:
'是否全部获取, 如果不未0则忽略page与limit, 返回所有的国际化字段',
})
@ApiQuery({ name: 'lang', description: '语言ID' })
@ApiQuery({
name: 'key',
description: '国际化字段的键, 如果设定则表示按照键来模糊查找',
})
@ApiQuery({
name: 'content',
description: '国际化字段的值, 如果设定则表示按照值来模糊查找',
})
@ApiOkResponse({ type: FindAllI18n })
@Permission('i18n::query')
@Get()
findAll(
@Query('page', new DefaultValuePipe(1), ParseIntPipe) page?: number,
@Query('limit', new DefaultValuePipe(0), ParseIntPipe) limit?: number,
@Query('all', ParseIntPipe) all?: number,
@Query('lang', new DefaultValuePipe([]), ParseArrayPipe) lang?: LangId[],
@Query('key') key?: string,
@Query('content') content?: string,
) {
return this.i18Service.findAll(
page,
limit,
Boolean(all),
lang,
content,
key,
);
}

@ApiOperation({ summary: '根据数据库ID获取国际化字段' })
@ApiParam({
type: Number,
name: 'id',
description: '国际化字段数据库ID',
})
@ApiOkResponse({
type: I18,
})
@Permission('i18n::query')
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: I18nRecordId) {
return this.i18Service.findOne(id);
}

@ApiOperation({ summary: '根据数据库ID更新国际化字段' })
@ApiParam({
type: Number,
name: 'id',
description: '国际化字段数据库ID',
})
@ApiOkResponse({
type: I18,
})
@Reject()
@Permission('i18n::update')
@Patch(':id')
update(
@Param('id', ParseIntPipe) id: I18nRecordId,
@Body() updateI18Dto: UpdateI18Dto,
) {
return this.i18Service.update(id, updateI18Dto);
}

@ApiOperation({ summary: '根据数据库ID删除国际化字段' })
@ApiParam({
type: Number,
name: 'id',
description: '国际化字段数据库ID',
})
@ApiOkResponse({
type: I18,
})
@Reject()
@Permission('i18n::remove')
@Delete(':id')
remove(@Param('id', ParseIntPipe) id: I18nRecordId) {
return this.i18Service.remove(id);
}

@ApiOperation({ summary: '根据数据库ID批量删除国际化字段' })
@ApiCreatedResponse({
type: [I18],
})
@Reject()
@Permission('i18n::batch-remove')
@Post('/batch')
batchRemove(@Body() body: BatchRemoveI18Records) {
return this.i18Service.batchRemove(body.ids);
}
}
50 changes: 43 additions & 7 deletions template/nest-next/src/i18/i18.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
LangNotExistsError,
} from './errors';
import { UpdateI18Dto } from './dto/update-i18.dto';
import { PaginationMeta } from '@app/shared';
import { FindAllI18n, FindAllI18nItem } from './dto/find-all-i18n.dto';

@Injectable()
export class I18Service {
Expand Down Expand Up @@ -81,15 +83,49 @@ export class I18Service {
if (key) {
where.key = { $like: key };
}
let items: FindAllI18nItem[];
let total = 0;
if (all) {
return this.i18.findAll({ where, populate: ['lang'] });
items = await this.i18
.findAll({ where, populate: ['lang'] })
.then((items) => {
return items.map((item) => {
return new FindAllI18nItem(
item.id,
item.lang,
item.key,
item.content,
);
});
});
total = items.length;
} else {
items = await this.i18
.findAll({
where,
offset: page && limit ? (page - 1) * limit : 0,
limit,
populate: ['lang'],
})
.then((items) => {
return items.map((item) => {
return new FindAllI18nItem(
item.id,
item.lang,
item.key,
item.content,
);
});
});
total = await this.i18.count(where);
}
return this.i18.findAll({
where,
offset: page && limit ? (page - 1) * limit : 0,
limit,
populate: ['lang'],
});
const meta = new PaginationMeta(
items.length,
total,
limit || items.length,
page || 1,
);
return new FindAllI18n(items, meta);
}
async findOne(id: I18nRecordId) {
const item = await this.i18.findOne(
Expand Down
3 changes: 2 additions & 1 deletion template/nest-next/src/i18n/enUS/exception.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"common":{
"INTERNAL_ERROR": "Internal Error"
"INTERNAL_ERROR": "Internal Error",
"FORBIDDEN": "Forbidden"
},
"permission":{
"NOT_FOUND": "Permission not found"
Expand Down
Loading
Loading