mirror of https://github.com/fantasticit/think.git
refactor: use guard
This commit is contained in:
parent
dffbc3e464
commit
52329d92f0
|
@ -1,2 +1,7 @@
|
||||||
|
/// <reference types="node" />
|
||||||
export declare const DEFAULT_WIKI_AVATAR = "https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default0-96.png";
|
export declare const DEFAULT_WIKI_AVATAR = "https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default0-96.png";
|
||||||
export declare const WIKI_AVATARS: string[];
|
export declare const WIKI_AVATARS: string[];
|
||||||
|
export declare const EMPTY_DOCUMNENT: {
|
||||||
|
content: string;
|
||||||
|
state: Buffer;
|
||||||
|
};
|
||||||
|
|
|
@ -1,19 +1,37 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.WIKI_AVATARS = exports.DEFAULT_WIKI_AVATAR = void 0;
|
exports.EMPTY_DOCUMNENT = exports.WIKI_AVATARS = exports.DEFAULT_WIKI_AVATAR = void 0;
|
||||||
exports.DEFAULT_WIKI_AVATAR = "https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default0-96.png";
|
exports.DEFAULT_WIKI_AVATAR = 'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default0-96.png';
|
||||||
exports.WIKI_AVATARS = [
|
exports.WIKI_AVATARS = [
|
||||||
exports.DEFAULT_WIKI_AVATAR,
|
exports.DEFAULT_WIKI_AVATAR,
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default2-96.png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default2-96.png',
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default7-96.png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default7-96.png',
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default8-96.png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default8-96.png',
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default14-96.png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default14-96.png',
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default21-96.png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default21-96.png',
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default23-96.png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default23-96.png',
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default1-96%20(1).png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default1-96%20(1).png',
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default4-96.png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default4-96.png',
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default12-96.png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default12-96.png',
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default17-96.png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default17-96.png',
|
||||||
"https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default18-96.png",
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default18-96.png',
|
||||||
];
|
];
|
||||||
|
exports.EMPTY_DOCUMNENT = {
|
||||||
|
content: JSON.stringify({
|
||||||
|
default: {
|
||||||
|
type: 'doc',
|
||||||
|
content: [{ type: 'title', content: [{ type: 'text', text: '未命名文档' }] }],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
state: Buffer.from(new Uint8Array([
|
||||||
|
1, 14, 204, 224, 154, 225, 13, 0, 7, 1, 7, 100, 101, 102, 97, 117, 108, 116, 3, 5, 116, 105, 116, 108, 101, 1, 0,
|
||||||
|
204, 224, 154, 225, 13, 0, 1, 0, 1, 135, 204, 224, 154, 225, 13, 0, 3, 9, 112, 97, 114, 97, 103, 114, 97, 112,
|
||||||
|
104, 40, 0, 204, 224, 154, 225, 13, 3, 6, 105, 110, 100, 101, 110, 116, 1, 125, 0, 40, 0, 204, 224, 154, 225, 13,
|
||||||
|
3, 9, 116, 101, 120, 116, 65, 108, 105, 103, 110, 1, 119, 4, 108, 101, 102, 116, 0, 4, 71, 204, 224, 154, 225, 13,
|
||||||
|
1, 6, 1, 0, 204, 224, 154, 225, 13, 10, 3, 132, 204, 224, 154, 225, 13, 13, 3, 230, 156, 170, 129, 204, 224, 154,
|
||||||
|
225, 13, 14, 6, 132, 204, 224, 154, 225, 13, 20, 6, 229, 145, 189, 229, 144, 141, 129, 204, 224, 154, 225, 13, 22,
|
||||||
|
5, 132, 204, 224, 154, 225, 13, 27, 6, 230, 150, 135, 230, 161, 163, 1, 204, 224, 154, 225, 13, 5, 1, 2, 6, 4, 11,
|
||||||
|
3, 15, 6, 23, 5,
|
||||||
|
])),
|
||||||
|
};
|
||||||
//# sourceMappingURL=index.js.map
|
//# sourceMappingURL=index.js.map
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAa,QAAA,mBAAmB,GAC9B,sEAAsE,CAAC;AAE5D,QAAA,YAAY,GAAG;IAC1B,2BAAmB;IACnB,sEAAsE;IACtE,sEAAsE;IACtE,sEAAsE;IACtE,uEAAuE;IACvE,uEAAuE;IACvE,uEAAuE;IACvE,4EAA4E;IAC5E,sEAAsE;IACtE,uEAAuE;IACvE,uEAAuE;IACvE,uEAAuE;CACxE,CAAC"}
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAa,QAAA,mBAAmB,GAAG,sEAAsE,CAAC;AAE7F,QAAA,YAAY,GAAG;IAC1B,2BAAmB;IACnB,sEAAsE;IACtE,sEAAsE;IACtE,sEAAsE;IACtE,uEAAuE;IACvE,uEAAuE;IACvE,uEAAuE;IACvE,4EAA4E;IAC5E,sEAAsE;IACtE,uEAAuE;IACvE,uEAAuE;IACvE,uEAAuE;CACxE,CAAC;AAEW,QAAA,eAAe,GAAG;IAC7B,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;QACtB,OAAO,EAAE;YACP,IAAI,EAAE,KAAK;YACX,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;SACzE;KACF,CAAC;IACF,KAAK,EAAE,MAAM,CAAC,IAAI,CAChB,IAAI,UAAU,CAAC;QACb,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;QAChH,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG;QAC7G,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAChH,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QACjH,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG;QAChH,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE;QACjH,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;QACjH,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;KAChB,CAAC,CACH;CACF,CAAC"}
|
|
@ -14,3 +14,24 @@ export const WIKI_AVATARS = [
|
||||||
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default17-96.png',
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default17-96.png',
|
||||||
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default18-96.png',
|
'https://wipi.oss-cn-shanghai.aliyuncs.com/2022-02-01/default18-96.png',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const EMPTY_DOCUMNENT = {
|
||||||
|
content: JSON.stringify({
|
||||||
|
default: {
|
||||||
|
type: 'doc',
|
||||||
|
content: [{ type: 'title', content: [{ type: 'text', text: '未命名文档' }] }],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
state: Buffer.from(
|
||||||
|
new Uint8Array([
|
||||||
|
1, 14, 204, 224, 154, 225, 13, 0, 7, 1, 7, 100, 101, 102, 97, 117, 108, 116, 3, 5, 116, 105, 116, 108, 101, 1, 0,
|
||||||
|
204, 224, 154, 225, 13, 0, 1, 0, 1, 135, 204, 224, 154, 225, 13, 0, 3, 9, 112, 97, 114, 97, 103, 114, 97, 112,
|
||||||
|
104, 40, 0, 204, 224, 154, 225, 13, 3, 6, 105, 110, 100, 101, 110, 116, 1, 125, 0, 40, 0, 204, 224, 154, 225, 13,
|
||||||
|
3, 9, 116, 101, 120, 116, 65, 108, 105, 103, 110, 1, 119, 4, 108, 101, 102, 116, 0, 4, 71, 204, 224, 154, 225, 13,
|
||||||
|
1, 6, 1, 0, 204, 224, 154, 225, 13, 10, 3, 132, 204, 224, 154, 225, 13, 13, 3, 230, 156, 170, 129, 204, 224, 154,
|
||||||
|
225, 13, 14, 6, 132, 204, 224, 154, 225, 13, 20, 6, 229, 145, 189, 229, 144, 141, 129, 204, 224, 154, 225, 13, 22,
|
||||||
|
5, 132, 204, 224, 154, 225, 13, 27, 6, 230, 150, 135, 230, 161, 163, 1, 204, 224, 154, 225, 13, 5, 1, 2, 6, 4, 11,
|
||||||
|
3, 15, 6, 23, 5,
|
||||||
|
])
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
|
@ -14,6 +14,9 @@ import {
|
||||||
Delete,
|
Delete,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { JwtGuard } from '@guard/jwt.guard';
|
import { JwtGuard } from '@guard/jwt.guard';
|
||||||
|
import { DocumentAuthorityGuard, CheckDocumentAuthority } from '@guard/document-auth.guard';
|
||||||
|
import { DocumentStatusGuard, CheckDocumentStatus } from '@guard/document-status.guard';
|
||||||
|
import { DocumentStatus } from '@think/domains';
|
||||||
import { DocumentService } from '@services/document.service';
|
import { DocumentService } from '@services/document.service';
|
||||||
import { DocAuthDto } from '@dtos/doc-auth.dto';
|
import { DocAuthDto } from '@dtos/doc-auth.dto';
|
||||||
import { CreateDocumentDto } from '@dtos/create-document.dto';
|
import { CreateDocumentDto } from '@dtos/create-document.dto';
|
||||||
|
@ -21,6 +24,8 @@ import { UpdateDocumentDto } from '@dtos/update-document.dto';
|
||||||
import { ShareDocumentDto } from '@dtos/share-document.dto';
|
import { ShareDocumentDto } from '@dtos/share-document.dto';
|
||||||
|
|
||||||
@Controller('document')
|
@Controller('document')
|
||||||
|
@UseGuards(DocumentAuthorityGuard)
|
||||||
|
@UseGuards(DocumentStatusGuard)
|
||||||
export class DocumentController {
|
export class DocumentController {
|
||||||
constructor(private readonly documentService: DocumentService) {}
|
constructor(private readonly documentService: DocumentService) {}
|
||||||
|
|
||||||
|
@ -32,54 +37,104 @@ export class DocumentController {
|
||||||
return await this.documentService.createDocument(req.user, dto);
|
return await this.documentService.createDocument(req.user, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文档详情
|
||||||
|
* @param req
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('detail/:id')
|
@Get('detail/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckDocumentAuthority('readable')
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async getDocumentDetail(@Request() req, @Param('id') documentId) {
|
async getDocumentDetail(@Request() req, @Param('id') documentId) {
|
||||||
return await this.documentService.getDocumentDetail(req.user, documentId, req.headers['user-agent']);
|
return await this.documentService.getDocumentDetail(req.user, documentId, req.headers['user-agent']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新文档
|
||||||
|
* @param req
|
||||||
|
* @param documentId
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('update/:id')
|
@Post('update/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckDocumentAuthority('editable')
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async updateDocument(@Request() req, @Param('id') documentId, @Body() dto: UpdateDocumentDto) {
|
async updateDocument(@Request() req, @Param('id') documentId, @Body() dto: UpdateDocumentDto) {
|
||||||
return await this.documentService.updateDocument(req.user, documentId, dto);
|
return await this.documentService.updateDocument(req.user, documentId, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文档版本记录
|
||||||
|
* @param req
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('version/:id')
|
@Get('version/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckDocumentAuthority('readable')
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async getDocumentVersion(@Request() req, @Param('id') documentId) {
|
async getDocumentVersion(@Request() req, @Param('id') documentId) {
|
||||||
return await this.documentService.getDocumentVersion(req.user, documentId);
|
return await this.documentService.getDocumentVersion(req.user, documentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文档下的子文档
|
||||||
|
* @param req
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('children')
|
@Post('children')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckDocumentAuthority('readable')
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async getChildrenDocuments(@Request() req, @Body() data) {
|
async getChildrenDocuments(@Request() req, @Body() data) {
|
||||||
return await this.documentService.getChildrenDocuments(req.user, data);
|
return await this.documentService.getChildrenDocuments(req.user, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文档
|
||||||
|
* @param req
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Delete('delete/:id')
|
@Delete('delete/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckDocumentAuthority('createUser')
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async deleteDocument(@Request() req, @Param('id') documentId) {
|
async deleteDocument(@Request() req, @Param('id') documentId) {
|
||||||
return await this.documentService.deleteDocument(req.user, documentId);
|
return await this.documentService.deleteDocument(req.user, documentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享(或关闭分享)文档
|
||||||
|
* @param req
|
||||||
|
* @param documentId
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('share/:id')
|
@Post('share/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckDocumentAuthority('editable')
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async shareDocument(@Request() req, @Param('id') documentId, @Body() dto: ShareDocumentDto) {
|
async shareDocument(@Request() req, @Param('id') documentId, @Body() dto: ShareDocumentDto) {
|
||||||
return await this.documentService.shareDocument(req.user, documentId, dto);
|
return await this.documentService.shareDocument(req.user, documentId, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索文档
|
||||||
|
* @param req
|
||||||
|
* @param keyword
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('search')
|
@Get('search')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@ -88,52 +143,74 @@ export class DocumentController {
|
||||||
return await this.documentService.search(req.user, keyword);
|
return await this.documentService.search(req.user, keyword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文档成员
|
||||||
|
* @param req
|
||||||
|
* @param documentId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('user/:id')
|
@Get('user/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckDocumentAuthority('readable')
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async getDocUsers(@Request() req, @Param('id') documentId) {
|
async getDocUsers(@Request() req, @Param('id') documentId) {
|
||||||
return await this.documentService.getDocUsers(req.user, documentId);
|
return await this.documentService.getDocUsers(req.user, documentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加文档成员
|
||||||
|
* 只有文档创建着才可操作
|
||||||
|
* @param req
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('user/:id/add')
|
@Post('user/:id/add')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckDocumentAuthority('createUser')
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async addDocUser(@Request() req, @Body() dto: DocAuthDto) {
|
async addDocUser(@Request() req, @Body() dto: DocAuthDto) {
|
||||||
return await this.documentService.addDocUser(req.user, dto);
|
return await this.documentService.addDocUser(req.user, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改文档成员(一般是权限操作)
|
||||||
|
* 只有文档创建着才可操作
|
||||||
|
* @param req
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('user/:id/update')
|
@Post('user/:id/update')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckDocumentAuthority('createUser')
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async updateDocUser(@Request() req, @Body() dto: DocAuthDto) {
|
async updateDocUser(@Request() req, @Body() dto: DocAuthDto) {
|
||||||
return await this.documentService.updateDocUser(req.user, dto);
|
return await this.documentService.updateDocUser(req.user, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文档成员
|
||||||
|
* 只有文档创建着才可操作
|
||||||
|
* @param req
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('user/:id/delete')
|
@Post('user/:id/delete')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckDocumentAuthority('createUser')
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async deleteDocUser(@Request() req, @Body() dto: DocAuthDto) {
|
async deleteDocUser(@Request() req, @Body() dto: DocAuthDto) {
|
||||||
return await this.documentService.deleteDocUser(req.user, dto);
|
return await this.documentService.deleteDocUser(req.user, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
/**
|
||||||
@Post('public/detail/:id')
|
* 获取用户最近访问的文档
|
||||||
@HttpCode(HttpStatus.OK)
|
* @param req
|
||||||
async getShareDocumentDetail(@Request() req, @Param('id') documentId, @Body() dto: ShareDocumentDto) {
|
* @returns
|
||||||
return await this.documentService.getPublicDocumentDetail(documentId, dto, req.headers['user-agent']);
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
|
||||||
@Post('public/children')
|
|
||||||
@HttpCode(HttpStatus.OK)
|
|
||||||
async getShareChildrenDocuments(@Body() data) {
|
|
||||||
return await this.documentService.getShareChildrenDocuments(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('recent')
|
@Get('recent')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@ -141,4 +218,32 @@ export class DocumentController {
|
||||||
async getWorkspaceDocuments(@Request() req) {
|
async getWorkspaceDocuments(@Request() req) {
|
||||||
return await this.documentService.getRecentDocuments(req.user);
|
return await this.documentService.getRecentDocuments(req.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公开文档详情
|
||||||
|
* @param req
|
||||||
|
* @param documentId
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
|
@Post('public/detail/:id')
|
||||||
|
@CheckDocumentStatus(DocumentStatus.public)
|
||||||
|
@HttpCode(HttpStatus.OK)
|
||||||
|
async getShareDocumentDetail(@Request() req, @Param('id') documentId, @Body() dto: ShareDocumentDto) {
|
||||||
|
return await this.documentService.getPublicDocumentDetail(documentId, dto, req.headers['user-agent']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公开文档的子文档
|
||||||
|
* @param data
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
|
@Post('public/children')
|
||||||
|
@CheckDocumentStatus(DocumentStatus.public)
|
||||||
|
@HttpCode(HttpStatus.OK)
|
||||||
|
async getShareChildrenDocuments(@Body() data) {
|
||||||
|
return await this.documentService.getShareChildrenDocuments(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@ import {
|
||||||
Delete,
|
Delete,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { JwtGuard } from '@guard/jwt.guard';
|
import { JwtGuard } from '@guard/jwt.guard';
|
||||||
import { IPagination } from '@think/domains';
|
import { IPagination, WikiUserRole, WikiStatus } from '@think/domains';
|
||||||
|
import { WikiUserRoleGuard, CheckWikiUserRole } from '@guard/wiki-user.guard';
|
||||||
|
import { WikiStatusGuard, CheckWikiStatus } from '@guard/wiki-status.guard';
|
||||||
import { WikiService } from '@services/wiki.service';
|
import { WikiService } from '@services/wiki.service';
|
||||||
import { WikiUserDto } from '@dtos/wiki-user.dto';
|
import { WikiUserDto } from '@dtos/wiki-user.dto';
|
||||||
import { CreateWikiDto } from '@dtos/create-wiki.dto';
|
import { CreateWikiDto } from '@dtos/create-wiki.dto';
|
||||||
|
@ -23,9 +25,17 @@ import { UpdateWikiDto } from '@dtos/update-wiki.dto';
|
||||||
import { ShareWikiDto } from '@dtos/share-wiki.dto';
|
import { ShareWikiDto } from '@dtos/share-wiki.dto';
|
||||||
|
|
||||||
@Controller('wiki')
|
@Controller('wiki')
|
||||||
|
@UseGuards(WikiUserRoleGuard)
|
||||||
|
@UseGuards(WikiStatusGuard)
|
||||||
export class WikiController {
|
export class WikiController {
|
||||||
constructor(private readonly wikiService: WikiService) {}
|
constructor(private readonly wikiService: WikiService) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新建知识库
|
||||||
|
* @param req
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('create')
|
@Post('create')
|
||||||
@HttpCode(HttpStatus.CREATED)
|
@HttpCode(HttpStatus.CREATED)
|
||||||
|
@ -34,6 +44,12 @@ export class WikiController {
|
||||||
return await this.wikiService.createWiki(req.user, dto);
|
return await this.wikiService.createWiki(req.user, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户所有知识库(创建的、参与的)
|
||||||
|
* @param req
|
||||||
|
* @param pagination
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('list/all')
|
@Get('list/all')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@ -42,6 +58,12 @@ export class WikiController {
|
||||||
return await this.wikiService.getAllWikis(req.user, pagination);
|
return await this.wikiService.getAllWikis(req.user, pagination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户拥有的知识库(一般是创建的,尚未实现知识库转移)
|
||||||
|
* @param req
|
||||||
|
* @param pagination
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('list/own')
|
@Get('list/own')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@ -50,6 +72,12 @@ export class WikiController {
|
||||||
return await this.wikiService.getOwnWikis(req.user, pagination);
|
return await this.wikiService.getOwnWikis(req.user, pagination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户参与的知识库
|
||||||
|
* @param req
|
||||||
|
* @param pagination
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('list/join')
|
@Get('list/join')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@ -58,123 +86,244 @@ export class WikiController {
|
||||||
return await this.wikiService.getJoinWikis(req.user, pagination);
|
return await this.wikiService.getJoinWikis(req.user, pagination);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取知识库详情
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('detail/:id')
|
@Get('detail/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole()
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async getWikiDetail(@Request() req, @Param('id') wikiId) {
|
async getWikiDetail(@Request() req, @Param('id') wikiId) {
|
||||||
return await this.wikiService.getWikiDetail(req.user, wikiId);
|
return await this.wikiService.getWikiDetail(req.user, wikiId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取知识库首页文档(首页文档为自动创建)
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('homedoc/:id')
|
@Get('homedoc/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole()
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async getWikiHomeDocument(@Request() req, @Param('id') wikiId) {
|
async getWikiHomeDocument(@Request() req, @Param('id') wikiId) {
|
||||||
return await this.wikiService.getWikiHomeDocument(req.user, wikiId);
|
return await this.wikiService.getWikiHomeDocument(req.user, wikiId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改知识库
|
||||||
|
* 只有管理员可操作
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Patch('update/:id')
|
@Patch('update/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole(WikiUserRole.admin)
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async updateWiki(@Request() req, @Param('id') wikiId, @Body() dto: UpdateWikiDto) {
|
async updateWiki(@Request() req, @Param('id') wikiId, @Body() dto: UpdateWikiDto) {
|
||||||
return await this.wikiService.updateWiki(req.user, wikiId, dto);
|
return await this.wikiService.updateWiki(req.user, wikiId, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除知识库
|
||||||
|
* 只有管理员可操作
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Delete('delete/:id')
|
@Delete('delete/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole(WikiUserRole.admin)
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async deleteWiki(@Request() req, @Param('id') wikiId) {
|
async deleteWiki(@Request() req, @Param('id') wikiId) {
|
||||||
return await this.wikiService.deleteWiki(req.user, wikiId);
|
return await this.wikiService.deleteWiki(req.user, wikiId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查看知识库成员
|
||||||
|
* 只有管理员可操作
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('user/:id')
|
@Get('user/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole(WikiUserRole.admin)
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async getWikiUsers(@Request() req, @Param('id') wikiId) {
|
async getWikiUsers(@Param('id') wikiId) {
|
||||||
return await this.wikiService.getWikiUsers({ userId: req.user.id, wikiId });
|
return await this.wikiService.getWikiUsers(wikiId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加知识库成员
|
||||||
|
* 只有管理员可操作
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('user/:id/add')
|
@Post('user/:id/add')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole(WikiUserRole.admin)
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async addWikiUser(@Request() req, @Param('id') wikiId, @Body() dto: WikiUserDto) {
|
async addWikiUser(@Request() req, @Param('id') wikiId, @Body() dto: WikiUserDto) {
|
||||||
return await this.wikiService.addWikiUser(req.user, wikiId, dto);
|
return await this.wikiService.addWikiUser(req.user, wikiId, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新知识库成员(一般为角色操作)
|
||||||
|
* 只有管理员可操作
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('user/:id/update')
|
@Post('user/:id/update')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole(WikiUserRole.admin)
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async updateWikiUser(@Request() req, @Param('id') wikiId, @Body() dto: WikiUserDto) {
|
async updateWikiUser(@Request() req, @Param('id') wikiId, @Body() dto: WikiUserDto) {
|
||||||
return await this.wikiService.updateWikiUser(req.user, wikiId, dto);
|
return await this.wikiService.updateWikiUser(req.user, wikiId, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除知识库成员
|
||||||
|
* 只有管理员可操作
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('user/:id/delete')
|
@Post('user/:id/delete')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole(WikiUserRole.admin)
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async deleteWikiUser(@Request() req, @Param('id') wikiId, @Body() dto: WikiUserDto) {
|
async deleteWikiUser(@Request() req, @Param('id') wikiId, @Body() dto: WikiUserDto) {
|
||||||
return await this.wikiService.deleteWikiUser(req.user, wikiId, dto);
|
return await this.wikiService.deleteWikiUser(req.user, wikiId, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分享(或关闭分享)知识库
|
||||||
|
* 只有管理员可操作
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('share/:id')
|
@Post('share/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole(WikiUserRole.admin)
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async toggleWorkspaceStatus(@Request() req, @Param('id') wikiId, @Body() dto: ShareWikiDto) {
|
async toggleWorkspaceStatus(@Request() req, @Param('id') wikiId, @Body() dto: ShareWikiDto) {
|
||||||
return await this.wikiService.shareWiki(req.user, wikiId, dto);
|
return await this.wikiService.shareWiki(req.user, wikiId, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取知识库目录
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('tocs/:id')
|
@Get('tocs/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole()
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async getWikiTocs(@Request() req, @Param('id') wikiId) {
|
async getWikiTocs(@Request() req, @Param('id') wikiId) {
|
||||||
return await this.wikiService.getWikiTocs(req.user, wikiId);
|
return await this.wikiService.getWikiTocs(req.user, wikiId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新知识库目录(排序、父子关系)
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @param relations
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('tocs/:id/update')
|
@Post('tocs/:id/update')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole()
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async orderWikiTocs(@Request() req, @Param('id') wikiId, @Body() relations) {
|
async orderWikiTocs(@Body() relations) {
|
||||||
return await this.wikiService.orderWikiTocs(req.user, wikiId, relations);
|
return await this.wikiService.orderWikiTocs(relations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取知识库所有文档
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('docs/:id')
|
@Get('docs/:id')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
@CheckWikiUserRole()
|
||||||
@UseGuards(JwtGuard)
|
@UseGuards(JwtGuard)
|
||||||
async getWikiDocs(@Request() req, @Param('id') wikiId) {
|
async getWikiDocs(@Request() req, @Param('id') wikiId) {
|
||||||
return await this.wikiService.getWikiDocs(req.user, wikiId);
|
return await this.wikiService.getWikiDocs(req.user, wikiId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公开知识库首页文档
|
||||||
|
* @param req
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('public/homedoc/:id')
|
@Get('public/homedoc/:id')
|
||||||
|
@CheckWikiStatus(WikiStatus.public)
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
async getWikiPublicHomeDocument(@Request() req, @Param('id') wikiId) {
|
async getWikiPublicHomeDocument(@Request() req, @Param('id') wikiId) {
|
||||||
return await this.wikiService.getWikiPublicHomeDocument(wikiId, req.headers['user-agent']);
|
return await this.wikiService.getPublicWikiHomeDocument(wikiId, req.headers['user-agent']);
|
||||||
}
|
|
||||||
|
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
|
||||||
@Post('public/tocs/:id')
|
|
||||||
@HttpCode(HttpStatus.OK)
|
|
||||||
async getPublicWikiTocs(@Param('id') wikiId) {
|
|
||||||
return await this.wikiService.getPublicWikiTocs(wikiId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公开知识库详情
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Post('public/detail/:id')
|
@Post('public/detail/:id')
|
||||||
|
@CheckWikiStatus(WikiStatus.public)
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
async getPublicWorkspaceDetail(@Param('id') wikiId) {
|
async getPublicWorkspaceDetail(@Param('id') wikiId) {
|
||||||
return await this.wikiService.getPublicWikiDetail(wikiId);
|
return await this.wikiService.getPublicWikiDetail(wikiId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公开知识库目录
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
|
@Post('public/tocs/:id')
|
||||||
|
@CheckWikiStatus(WikiStatus.public)
|
||||||
|
@HttpCode(HttpStatus.OK)
|
||||||
|
async getPublicWikiTocs(@Param('id') wikiId) {
|
||||||
|
return await this.wikiService.getPublicWikiTocs(wikiId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有公开知识库
|
||||||
|
* @param pagination
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
@UseInterceptors(ClassSerializerInterceptor)
|
@UseInterceptors(ClassSerializerInterceptor)
|
||||||
@Get('public/wikis')
|
@Get('public/wikis')
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { CanActivate, ExecutionContext, Injectable, SetMetadata, HttpException, HttpStatus } from '@nestjs/common';
|
||||||
|
import { JwtService } from '@nestjs/jwt';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
import { IUser } from '@think/domains';
|
||||||
|
import { DocumentService } from '@services/document.service';
|
||||||
|
|
||||||
|
const KEY = 'DocumentAuthority';
|
||||||
|
export const CheckDocumentAuthority = (auth: 'readable' | 'editable' | 'createUser' | null) => SetMetadata(KEY, auth);
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DocumentAuthorityGuard implements CanActivate {
|
||||||
|
constructor(
|
||||||
|
private readonly reflector: Reflector,
|
||||||
|
private readonly jwtService: JwtService,
|
||||||
|
private readonly documentService: DocumentService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
const needAuth = this.reflector.get<string>(KEY, context.getHandler());
|
||||||
|
|
||||||
|
if (!needAuth) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = context.switchToHttp().getRequest();
|
||||||
|
|
||||||
|
let token = request.headers.authorization;
|
||||||
|
|
||||||
|
if (/Bearer/.test(token)) {
|
||||||
|
token = token.split(' ').pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = this.jwtService.decode(token) as IUser;
|
||||||
|
const { params, query, body } = request;
|
||||||
|
const documentId = params.id || params.documentId || query.id || query.documentId || body.documentId;
|
||||||
|
let document = null;
|
||||||
|
|
||||||
|
if (documentId) {
|
||||||
|
document = await this.documentService.findById(documentId);
|
||||||
|
} else {
|
||||||
|
if (body.wikiId) {
|
||||||
|
document = await this.documentService.findWikiHomeDocument(body.wikiId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!document) {
|
||||||
|
throw new HttpException('文档不存在', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needAuth === 'createUser') {
|
||||||
|
if (document.createUserId !== user.id) {
|
||||||
|
throw new HttpException('您不是该文档的创建者,无法删除', HttpStatus.FORBIDDEN);
|
||||||
|
}
|
||||||
|
} else if (needAuth) {
|
||||||
|
const authority = await this.documentService.getDocumentAuthority(documentId, user.id);
|
||||||
|
if (!authority || !authority[needAuth]) {
|
||||||
|
throw new HttpException('您无权查看此文档', HttpStatus.FORBIDDEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { CanActivate, ExecutionContext, Injectable, SetMetadata, HttpException, HttpStatus } from '@nestjs/common';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
import { DocumentStatus } from '@think/domains';
|
||||||
|
import { DocumentService } from '@services/document.service';
|
||||||
|
|
||||||
|
const KEY = 'DocumentStatus';
|
||||||
|
export const CheckDocumentStatus = (status: DocumentStatus) => SetMetadata(KEY, status);
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DocumentStatusGuard implements CanActivate {
|
||||||
|
constructor(private readonly reflector: Reflector, private readonly documentService: DocumentService) {}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
const targetStatus = this.reflector.get<DocumentStatus>(KEY, context.getHandler());
|
||||||
|
|
||||||
|
if (!targetStatus) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = context.switchToHttp().getRequest();
|
||||||
|
const { params, query, body } = request;
|
||||||
|
const documentId = params.id || params.documentId || query.id || query.documentId || body.documentId;
|
||||||
|
|
||||||
|
let document = null;
|
||||||
|
|
||||||
|
if (documentId) {
|
||||||
|
document = await this.documentService.findById(documentId);
|
||||||
|
} else {
|
||||||
|
if (body.wikiId) {
|
||||||
|
document = await this.documentService.findWikiHomeDocument(body.wikiId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!document) {
|
||||||
|
throw new HttpException('文档不存在', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.status !== targetStatus) {
|
||||||
|
throw new HttpException(
|
||||||
|
targetStatus === DocumentStatus.private
|
||||||
|
? '私有文档,无法查看内容'
|
||||||
|
: '公共文档,无法查看内容,请提 issue 到 GitHub 仓库反馈',
|
||||||
|
HttpStatus.FORBIDDEN
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { CanActivate, ExecutionContext, Injectable, SetMetadata, HttpException, HttpStatus } from '@nestjs/common';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
import { WikiStatus } from '@think/domains';
|
||||||
|
import { WikiService } from '@services/wiki.service';
|
||||||
|
|
||||||
|
const KEY = 'WikiStatus';
|
||||||
|
export const CheckWikiStatus = (status: WikiStatus) => SetMetadata(KEY, status);
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WikiStatusGuard implements CanActivate {
|
||||||
|
constructor(private readonly reflector: Reflector, private readonly wikiService: WikiService) {}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
const targetStatus = this.reflector.get<WikiStatus>(KEY, context.getHandler());
|
||||||
|
|
||||||
|
if (!targetStatus) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = context.switchToHttp().getRequest();
|
||||||
|
const { params, query, body } = request;
|
||||||
|
const wikiId = params.id || params.wikiId || query.id || query.wikiId || body.wikiId;
|
||||||
|
|
||||||
|
const wiki = await this.wikiService.findById(wikiId);
|
||||||
|
|
||||||
|
if (!wiki) {
|
||||||
|
throw new HttpException('目标知识库不存在', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
if (wiki.status !== targetStatus) {
|
||||||
|
throw new HttpException(
|
||||||
|
targetStatus === WikiStatus.private
|
||||||
|
? '私有知识库,无法查看内容'
|
||||||
|
: '公共知识库,无法查看内容,请提 issue 到 GitHub 仓库反馈',
|
||||||
|
HttpStatus.FORBIDDEN
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { CanActivate, ExecutionContext, Injectable, SetMetadata, HttpException, HttpStatus } from '@nestjs/common';
|
||||||
|
import { JwtService } from '@nestjs/jwt';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
import { IUser, WikiUserRole } from '@think/domains';
|
||||||
|
import { WikiService } from '@services/wiki.service';
|
||||||
|
|
||||||
|
const KEY = 'WIKI_USER_ROLE';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 知识库成员角色检测
|
||||||
|
* @param role 不传意味只要是成员即可
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const CheckWikiUserRole = (role: WikiUserRole | null = null) => SetMetadata(KEY, role);
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WikiUserRoleGuard implements CanActivate {
|
||||||
|
constructor(
|
||||||
|
private readonly reflector: Reflector,
|
||||||
|
private readonly jwtService: JwtService,
|
||||||
|
private readonly wikiService: WikiService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
const targetUserRole = this.reflector.get<WikiUserRole | null>(KEY, context.getHandler());
|
||||||
|
|
||||||
|
const request = context.switchToHttp().getRequest();
|
||||||
|
|
||||||
|
let token = request.headers.authorization;
|
||||||
|
|
||||||
|
if (/Bearer/.test(token)) {
|
||||||
|
token = token.split(' ').pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = this.jwtService.decode(token) as IUser;
|
||||||
|
|
||||||
|
const { params, query, body } = request;
|
||||||
|
const wikiId = params.id || params.wikiId || query.id || query.wikiId || body.wikiId;
|
||||||
|
|
||||||
|
const wiki = await this.wikiService.findById(wikiId);
|
||||||
|
|
||||||
|
if (!wiki) {
|
||||||
|
throw new HttpException('目标知识库不存在', HttpStatus.NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
const wikiUser = await this.wikiService.findWikiUser(wikiId, user.id);
|
||||||
|
|
||||||
|
if (!wikiUser && targetUserRole && wikiUser.userRole !== targetUserRole) {
|
||||||
|
throw new HttpException('您无权查看该知识库', HttpStatus.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import { UserModule } from '@modules/user.module';
|
||||||
import { DocumentModule } from '@modules/document.module';
|
import { DocumentModule } from '@modules/document.module';
|
||||||
import { MessageModule } from '@modules/message.module';
|
import { MessageModule } from '@modules/message.module';
|
||||||
import { CollectorModule } from '@modules/collector.module';
|
import { CollectorModule } from '@modules/collector.module';
|
||||||
|
import { ViewModule } from '@modules/view.module';
|
||||||
import { WikiEntity } from '@entities/wiki.entity';
|
import { WikiEntity } from '@entities/wiki.entity';
|
||||||
import { WikiUserEntity } from '@entities/wiki-user.entity';
|
import { WikiUserEntity } from '@entities/wiki-user.entity';
|
||||||
import { WikiController } from '@controllers/wiki.controller';
|
import { WikiController } from '@controllers/wiki.controller';
|
||||||
|
@ -15,6 +16,7 @@ import { WikiService } from '@services/wiki.service';
|
||||||
forwardRef(() => UserModule),
|
forwardRef(() => UserModule),
|
||||||
forwardRef(() => DocumentModule),
|
forwardRef(() => DocumentModule),
|
||||||
forwardRef(() => MessageModule),
|
forwardRef(() => MessageModule),
|
||||||
|
forwardRef(() => ViewModule),
|
||||||
forwardRef(() => CollectorModule),
|
forwardRef(() => CollectorModule),
|
||||||
],
|
],
|
||||||
providers: [WikiService],
|
providers: [WikiService],
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { Injectable, HttpException, HttpStatus, Inject, forwardRef } from '@nestjs/common';
|
import { Injectable, HttpException, HttpStatus, Inject, forwardRef } from '@nestjs/common';
|
||||||
import { DocumentStatus } from '@think/domains';
|
|
||||||
import { getConfig } from '@think/config';
|
import { getConfig } from '@think/config';
|
||||||
import * as Y from 'yjs';
|
import * as Y from 'yjs';
|
||||||
import { TiptapTransformer } from '@hocuspocus/transformer';
|
import { TiptapTransformer } from '@hocuspocus/transformer';
|
||||||
|
@ -77,57 +76,31 @@ export class CollaborationService {
|
||||||
async onAuthenticate({ connection, token, requestParameters }: onAuthenticatePayload) {
|
async onAuthenticate({ connection, token, requestParameters }: onAuthenticatePayload) {
|
||||||
const targetId = requestParameters.get('targetId');
|
const targetId = requestParameters.get('targetId');
|
||||||
const docType = requestParameters.get('docType');
|
const docType = requestParameters.get('docType');
|
||||||
|
const user = await this.userService.decodeToken(token);
|
||||||
|
|
||||||
|
if (!user || !user.id) {
|
||||||
|
throw new HttpException('您无权查看', HttpStatus.UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
switch (docType) {
|
switch (docType) {
|
||||||
case 'document': {
|
case 'document': {
|
||||||
const documentId = targetId;
|
const authority = await this.documentService.getDocumentAuthority(targetId, user.id);
|
||||||
if (token === 'anoy') {
|
if (!authority.readable) {
|
||||||
const document = await this.documentService.findById(documentId);
|
throw new HttpException('您无权查看此文档', HttpStatus.FORBIDDEN);
|
||||||
if (document.status === DocumentStatus.public) {
|
|
||||||
connection.readOnly = true;
|
|
||||||
return {
|
|
||||||
user: { name: 'anoymouse' },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const user = await this.userService.decodeToken(token);
|
|
||||||
|
|
||||||
if (!user || !user.id) {
|
|
||||||
throw new HttpException('您无权查看此文档', HttpStatus.UNAUTHORIZED);
|
|
||||||
}
|
|
||||||
|
|
||||||
const authority = await this.documentService.getDocumentAuthority(documentId, user.id);
|
|
||||||
|
|
||||||
if (!authority.readable) {
|
|
||||||
throw new HttpException('您无权查看此文档', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!authority.editable) {
|
|
||||||
connection.readOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
user,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
break;
|
if (!authority.editable) {
|
||||||
|
connection.readOnly = true;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
user,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'template': {
|
case 'template': {
|
||||||
const templateId = targetId;
|
const template = await this.templateService.findById(targetId);
|
||||||
|
|
||||||
const user = await this.userService.decodeToken(token);
|
|
||||||
|
|
||||||
if (!user || !user.id) {
|
|
||||||
throw new HttpException('您无权查看此模板', HttpStatus.UNAUTHORIZED);
|
|
||||||
}
|
|
||||||
|
|
||||||
const template = await this.templateService.findById(templateId);
|
|
||||||
|
|
||||||
if (template.createUserId !== user.id) {
|
if (template.createUserId !== user.id) {
|
||||||
throw new HttpException('您无权查看此模板', HttpStatus.FORBIDDEN);
|
throw new HttpException('您无权查看此模板', HttpStatus.FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
user,
|
user,
|
||||||
};
|
};
|
||||||
|
@ -148,34 +121,32 @@ export class CollaborationService {
|
||||||
const targetId = requestParameters.get('targetId');
|
const targetId = requestParameters.get('targetId');
|
||||||
const docType = requestParameters.get('docType');
|
const docType = requestParameters.get('docType');
|
||||||
|
|
||||||
|
let state = null;
|
||||||
|
|
||||||
switch (docType) {
|
switch (docType) {
|
||||||
case 'document': {
|
case 'document': {
|
||||||
const documentId = targetId;
|
const res = await this.documentService.findById(targetId);
|
||||||
const { state } = await this.documentService.findById(documentId);
|
state = res.state;
|
||||||
const unit8 = new Uint8Array(state);
|
break;
|
||||||
|
|
||||||
if (unit8.byteLength) {
|
|
||||||
Y.applyUpdate(document, unit8);
|
|
||||||
}
|
|
||||||
|
|
||||||
return document;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'template': {
|
case 'template': {
|
||||||
const templateId = targetId;
|
const res = await this.templateService.findById(targetId);
|
||||||
const { state } = await this.templateService.findById(templateId);
|
state = res.state;
|
||||||
const unit8 = new Uint8Array(state);
|
break;
|
||||||
|
|
||||||
if (unit8.byteLength) {
|
|
||||||
Y.applyUpdate(document, unit8);
|
|
||||||
}
|
|
||||||
|
|
||||||
return document;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error('未知类型');
|
throw new Error('未知类型');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unit8 = new Uint8Array(state);
|
||||||
|
|
||||||
|
if (unit8.byteLength) {
|
||||||
|
Y.applyUpdate(document, unit8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return document;
|
||||||
}
|
}
|
||||||
|
|
||||||
async onChange(data: onChangePayload) {
|
async onChange(data: onChangePayload) {
|
||||||
|
@ -194,9 +165,9 @@ export class CollaborationService {
|
||||||
this.debounceTime * 2
|
this.debounceTime * 2
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
const updateTemplate = this.templateService.updateTemplate.bind(this.templateService);
|
||||||
|
|
||||||
const updateHandler =
|
const updateHandler = docType === 'document' ? updateDocument : updateTemplate;
|
||||||
docType === 'document' ? updateDocument : this.templateService.updateTemplate.bind(this.templateService);
|
|
||||||
|
|
||||||
this.debounce(`onStoreDocument-${targetId}`, () => {
|
this.debounce(`onStoreDocument-${targetId}`, () => {
|
||||||
this.onStoreDocument(updateHandler, data).catch((error) => {
|
this.onStoreDocument(updateHandler, data).catch((error) => {
|
||||||
|
@ -208,13 +179,12 @@ export class CollaborationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
async onStoreDocument(updateHandler, data: onChangePayload) {
|
async onStoreDocument(updateHandler, data: onChangePayload) {
|
||||||
const { requestParameters, context } = data;
|
const { requestParameters } = data;
|
||||||
const targetId = requestParameters.get('targetId');
|
const targetId = requestParameters.get('targetId');
|
||||||
const userId = requestParameters.get('userId');
|
const userId = requestParameters.get('userId');
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
console.error('COLLABORATION: can not get user info');
|
throw new HttpException('无用户信息,拒绝存储文档数据变更', HttpStatus.FORBIDDEN);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const node = TiptapTransformer.fromYdoc(data.document);
|
const node = TiptapTransformer.fromYdoc(data.document);
|
||||||
|
@ -233,33 +203,24 @@ export class CollaborationService {
|
||||||
const docType = requestParameters.get('docType');
|
const docType = requestParameters.get('docType');
|
||||||
const userId = requestParameters.get('userId');
|
const userId = requestParameters.get('userId');
|
||||||
|
|
||||||
switch (docType) {
|
if (docType === 'document') {
|
||||||
case 'document': {
|
const data = await this.documentService.findById(targetId);
|
||||||
const documentId = targetId;
|
if (data && !data.title) {
|
||||||
const ret = await this.documentService.findById(documentId);
|
await this.documentService.updateDocument({ id: userId } as OutUser, targetId, {
|
||||||
|
title: '未命名文档',
|
||||||
if (ret && !ret.title) {
|
});
|
||||||
await this.documentService.updateDocument({ id: userId } as OutUser, targetId, {
|
|
||||||
title: '未命名文档',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
case 'template': {
|
if (docType === 'template') {
|
||||||
const templateId = targetId;
|
const data = await this.templateService.findById(targetId);
|
||||||
const ret = await this.templateService.findById(templateId);
|
if (data && !data.title) {
|
||||||
|
await this.templateService.updateTemplate({ id: userId } as OutUser, targetId, {
|
||||||
if (ret && !ret.title) {
|
title: '未命名模板',
|
||||||
await this.templateService.updateTemplate({ id: userId } as OutUser, targetId, {
|
});
|
||||||
title: '未命名模板',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
default:
|
|
||||||
throw new Error('未知类型');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import { IDocument } from '@think/domains';
|
||||||
import { getConfig } from '@think/config';
|
import { getConfig } from '@think/config';
|
||||||
import * as lodash from 'lodash';
|
import * as lodash from 'lodash';
|
||||||
|
|
||||||
|
type VerisonDataItem = { version: string; data: string };
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DocumentVersionService {
|
export class DocumentVersionService {
|
||||||
private redis: Redis;
|
private redis: Redis;
|
||||||
|
@ -14,7 +16,7 @@ export class DocumentVersionService {
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
private versionDataToArray(data: Record<string, string>): Array<{ version: string; data: string }> {
|
private versionDataToArray(data: Record<string, string>): Array<VerisonDataItem> {
|
||||||
return Object.keys(data)
|
return Object.keys(data)
|
||||||
.sort((a, b) => +b - +a)
|
.sort((a, b) => +b - +a)
|
||||||
.map((key) => ({ version: key, data: data[key] }));
|
.map((key) => ({ version: key, data: data[key] }));
|
||||||
|
@ -88,7 +90,7 @@ export class DocumentVersionService {
|
||||||
* @param documentId
|
* @param documentId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async getDocumentVersions(documentId: IDocument['id']): Promise<Array<{ version: string; data: string }>> {
|
public async getDocumentVersions(documentId: IDocument['id']): Promise<Array<VerisonDataItem>> {
|
||||||
if (this.error || !this.redis) {
|
if (this.error || !this.redis) {
|
||||||
throw new HttpException(this.error, HttpStatus.NOT_IMPLEMENTED);
|
throw new HttpException(this.error, HttpStatus.NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Injectable, HttpException, HttpStatus, Inject, forwardRef } from '@nest
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
import { instanceToPlain } from 'class-transformer';
|
import { instanceToPlain } from 'class-transformer';
|
||||||
|
import { EMPTY_DOCUMNENT } from '@think/constants';
|
||||||
import { DocumentStatus, IDocument, WikiUserRole } from '@think/domains';
|
import { DocumentStatus, IDocument, WikiUserRole } from '@think/domains';
|
||||||
import { DocumentAuthorityEntity } from '@entities/document-authority.entity';
|
import { DocumentAuthorityEntity } from '@entities/document-authority.entity';
|
||||||
import { DocumentEntity } from '@entities/document.entity';
|
import { DocumentEntity } from '@entities/document.entity';
|
||||||
|
@ -12,33 +13,11 @@ import { CollaborationService } from '@services/collaboration.service';
|
||||||
import { DocumentVersionService } from '@services/document-version.service';
|
import { DocumentVersionService } from '@services/document-version.service';
|
||||||
import { TemplateService } from '@services/template.service';
|
import { TemplateService } from '@services/template.service';
|
||||||
import { ViewService } from '@services/view.service';
|
import { ViewService } from '@services/view.service';
|
||||||
import { array2tree } from '@helpers/tree.helper';
|
|
||||||
import { DocAuthDto } from '@dtos/doc-auth.dto';
|
import { DocAuthDto } from '@dtos/doc-auth.dto';
|
||||||
import { CreateDocumentDto } from '@dtos/create-document.dto';
|
import { CreateDocumentDto } from '@dtos/create-document.dto';
|
||||||
import { UpdateDocumentDto } from '@dtos/update-document.dto';
|
import { UpdateDocumentDto } from '@dtos/update-document.dto';
|
||||||
import { ShareDocumentDto } from '@dtos/share-document.dto';
|
import { ShareDocumentDto } from '@dtos/share-document.dto';
|
||||||
|
|
||||||
const EMPTY_DOCUMNENT = {
|
|
||||||
content: JSON.stringify({
|
|
||||||
default: {
|
|
||||||
type: 'doc',
|
|
||||||
content: [{ type: 'title', content: [{ type: 'text', text: '未命名文档' }] }],
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
state: Buffer.from(
|
|
||||||
new Uint8Array([
|
|
||||||
1, 14, 204, 224, 154, 225, 13, 0, 7, 1, 7, 100, 101, 102, 97, 117, 108, 116, 3, 5, 116, 105, 116, 108, 101, 1, 0,
|
|
||||||
204, 224, 154, 225, 13, 0, 1, 0, 1, 135, 204, 224, 154, 225, 13, 0, 3, 9, 112, 97, 114, 97, 103, 114, 97, 112,
|
|
||||||
104, 40, 0, 204, 224, 154, 225, 13, 3, 6, 105, 110, 100, 101, 110, 116, 1, 125, 0, 40, 0, 204, 224, 154, 225, 13,
|
|
||||||
3, 9, 116, 101, 120, 116, 65, 108, 105, 103, 110, 1, 119, 4, 108, 101, 102, 116, 0, 4, 71, 204, 224, 154, 225, 13,
|
|
||||||
1, 6, 1, 0, 204, 224, 154, 225, 13, 10, 3, 132, 204, 224, 154, 225, 13, 13, 3, 230, 156, 170, 129, 204, 224, 154,
|
|
||||||
225, 13, 14, 6, 132, 204, 224, 154, 225, 13, 20, 6, 229, 145, 189, 229, 144, 141, 129, 204, 224, 154, 225, 13, 22,
|
|
||||||
5, 132, 204, 224, 154, 225, 13, 27, 6, 230, 150, 135, 230, 161, 163, 1, 204, 224, 154, 225, 13, 5, 1, 2, 6, 4, 11,
|
|
||||||
3, 15, 6, 23, 5,
|
|
||||||
])
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DocumentService {
|
export class DocumentService {
|
||||||
private collaborationService: CollaborationService;
|
private collaborationService: CollaborationService;
|
||||||
|
@ -46,17 +25,23 @@ export class DocumentService {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(DocumentAuthorityEntity)
|
@InjectRepository(DocumentAuthorityEntity)
|
||||||
private readonly documentAuthorityRepo: Repository<DocumentAuthorityEntity>,
|
public readonly documentAuthorityRepo: Repository<DocumentAuthorityEntity>,
|
||||||
|
|
||||||
@InjectRepository(DocumentEntity)
|
@InjectRepository(DocumentEntity)
|
||||||
private readonly documentRepo: Repository<DocumentEntity>,
|
public readonly documentRepo: Repository<DocumentEntity>,
|
||||||
|
|
||||||
@Inject(forwardRef(() => MessageService))
|
@Inject(forwardRef(() => MessageService))
|
||||||
private readonly messageService: MessageService,
|
private readonly messageService: MessageService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => UserService))
|
@Inject(forwardRef(() => UserService))
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => WikiService))
|
@Inject(forwardRef(() => WikiService))
|
||||||
private readonly wikiService: WikiService,
|
private readonly wikiService: WikiService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => TemplateService))
|
@Inject(forwardRef(() => TemplateService))
|
||||||
private readonly templateService: TemplateService,
|
private readonly templateService: TemplateService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => ViewService))
|
@Inject(forwardRef(() => ViewService))
|
||||||
private readonly viewService: ViewService
|
private readonly viewService: ViewService
|
||||||
) {
|
) {
|
||||||
|
@ -91,6 +76,15 @@ export class DocumentService {
|
||||||
return documents.map((doc) => instanceToPlain(doc));
|
return documents.map((doc) => instanceToPlain(doc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取知识库首页文档
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public async findWikiHomeDocument(wikiId) {
|
||||||
|
return await this.documentRepo.findOne({ wikiId, isWikiHome: true });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户在指定文档的权限
|
* 获取用户在指定文档的权限
|
||||||
* @param documentId
|
* @param documentId
|
||||||
|
@ -176,11 +170,8 @@ export class DocumentService {
|
||||||
*/
|
*/
|
||||||
async addDocUser(user: OutUser, dto: DocAuthDto) {
|
async addDocUser(user: OutUser, dto: DocAuthDto) {
|
||||||
const doc = await this.documentRepo.findOne(dto.documentId);
|
const doc = await this.documentRepo.findOne(dto.documentId);
|
||||||
if (!doc) {
|
|
||||||
throw new HttpException('文档不存在', HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetUser = await this.userService.findOne({ name: dto.userName });
|
const targetUser = await this.userService.findOne({ name: dto.userName });
|
||||||
|
|
||||||
if (!targetUser) {
|
if (!targetUser) {
|
||||||
throw new HttpException('用户不存在', HttpStatus.BAD_REQUEST);
|
throw new HttpException('用户不存在', HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
@ -226,16 +217,6 @@ export class DocumentService {
|
||||||
*/
|
*/
|
||||||
async deleteDocUser(user: OutUser, dto: DocAuthDto): Promise<void> {
|
async deleteDocUser(user: OutUser, dto: DocAuthDto): Promise<void> {
|
||||||
const doc = await this.documentRepo.findOne({ id: dto.documentId });
|
const doc = await this.documentRepo.findOne({ id: dto.documentId });
|
||||||
if (!doc) {
|
|
||||||
throw new HttpException('文档不存在', HttpStatus.BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
const isCurrentUserCreator = user.id === doc.createUserId;
|
|
||||||
|
|
||||||
if (!isCurrentUserCreator) {
|
|
||||||
throw new HttpException('您无权限进行该操作', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetUser = await this.userService.findOne({ name: dto.userName });
|
const targetUser = await this.userService.findOne({ name: dto.userName });
|
||||||
|
|
||||||
if (targetUser.id === doc.createUserId) {
|
if (targetUser.id === doc.createUserId) {
|
||||||
|
@ -249,7 +230,7 @@ export class DocumentService {
|
||||||
|
|
||||||
await this.messageService.notify(targetUser, {
|
await this.messageService.notify(targetUser, {
|
||||||
title: `您已被移出文档「${doc.title}」`,
|
title: `您已被移出文档「${doc.title}」`,
|
||||||
message: `管理员已将您从文档「${doc.title}」移出!`,
|
message: `${user.name}已将您从文档「${doc.title}」移出!`,
|
||||||
url: `/wiki/${doc.wikiId}/document/${doc.id}`,
|
url: `/wiki/${doc.wikiId}/document/${doc.id}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -332,7 +313,7 @@ export class DocumentService {
|
||||||
const document = await this.documentRepo.save(res);
|
const document = await this.documentRepo.save(res);
|
||||||
|
|
||||||
// 知识库成员权限继承
|
// 知识库成员权限继承
|
||||||
const wikiUsers = await this.wikiService.getWikiUsers({ userId: user.id, wikiId: dto.wikiId }, true);
|
const wikiUsers = await this.wikiService.getWikiUsers(dto.wikiId);
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
await this.operateDocumentAuth({
|
await this.operateDocumentAuth({
|
||||||
|
@ -376,12 +357,6 @@ export class DocumentService {
|
||||||
*/
|
*/
|
||||||
async deleteDocument(user: OutUser, documentId) {
|
async deleteDocument(user: OutUser, documentId) {
|
||||||
const document = await this.documentRepo.findOne(documentId);
|
const document = await this.documentRepo.findOne(documentId);
|
||||||
if (!document) {
|
|
||||||
throw new HttpException('文档不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
if (document.createUserId !== user.id) {
|
|
||||||
throw new HttpException('您不是该文档的创建者,无法删除', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
if (document.isWikiHome) {
|
if (document.isWikiHome) {
|
||||||
throw new HttpException('该文档作为知识库首页使用,无法删除', HttpStatus.FORBIDDEN);
|
throw new HttpException('该文档作为知识库首页使用,无法删除', HttpStatus.FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
@ -414,49 +389,11 @@ export class DocumentService {
|
||||||
*/
|
*/
|
||||||
public async updateDocument(user: OutUser, documentId: string, dto: UpdateDocumentDto) {
|
public async updateDocument(user: OutUser, documentId: string, dto: UpdateDocumentDto) {
|
||||||
const document = await this.documentRepo.findOne(documentId);
|
const document = await this.documentRepo.findOne(documentId);
|
||||||
if (!document) {
|
|
||||||
throw new HttpException('文档不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
const authority = await this.documentAuthorityRepo.findOne({
|
|
||||||
documentId,
|
|
||||||
userId: user.id,
|
|
||||||
});
|
|
||||||
if (!authority || !authority.editable) {
|
|
||||||
throw new HttpException('您无权编辑此文档', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
const res = await this.documentRepo.create({ ...document, ...dto });
|
const res = await this.documentRepo.create({ ...document, ...dto });
|
||||||
const ret = await this.documentRepo.save(res);
|
const ret = await this.documentRepo.save(res);
|
||||||
return instanceToPlain(ret);
|
return instanceToPlain(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取知识库首页文档
|
|
||||||
* @param user
|
|
||||||
* @param wikiId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async getWikiHomeDocument(user: OutUser, wikiId) {
|
|
||||||
const res = await this.documentRepo.findOne({ wikiId, isWikiHome: true });
|
|
||||||
return instanceToPlain(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取公开知识库首页文档
|
|
||||||
* @param user
|
|
||||||
* @param wikiId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async getWikiPublicHomeDocument(wikiId, userAgent) {
|
|
||||||
const res = await this.documentRepo.findOne({ wikiId, isWikiHome: true });
|
|
||||||
await this.viewService.create({
|
|
||||||
userId: 'public',
|
|
||||||
documentId: res.id,
|
|
||||||
userAgent,
|
|
||||||
});
|
|
||||||
const views = await this.viewService.getDocumentTotalViews(res.id);
|
|
||||||
return { ...instanceToPlain(res), views };
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取文档详情
|
* 获取文档详情
|
||||||
* @param user
|
* @param user
|
||||||
|
@ -464,27 +401,20 @@ export class DocumentService {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async getDocumentDetail(user: OutUser, documentId: string, userAgent) {
|
public async getDocumentDetail(user: OutUser, documentId: string, userAgent) {
|
||||||
|
// 1. 记录访问
|
||||||
|
await this.viewService.create({ userId: user.id, documentId, userAgent });
|
||||||
|
// 2. 查询文档
|
||||||
const document = await this.documentRepo.findOne(documentId);
|
const document = await this.documentRepo.findOne(documentId);
|
||||||
|
// 3. 查询权限
|
||||||
if (!document) {
|
|
||||||
throw new HttpException('文档不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
const authority = await this.documentAuthorityRepo.findOne({
|
const authority = await this.documentAuthorityRepo.findOne({
|
||||||
documentId,
|
documentId,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
|
// 4. 查询访问
|
||||||
if (!authority || !authority.readable) {
|
|
||||||
throw new HttpException('您无权查看此文档', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.viewService.create({ userId: user.id, documentId, userAgent });
|
|
||||||
const views = await this.viewService.getDocumentTotalViews(documentId);
|
const views = await this.viewService.getDocumentTotalViews(documentId);
|
||||||
|
// 5. 生成响应
|
||||||
const doc = instanceToPlain(document);
|
const doc = instanceToPlain(document);
|
||||||
const createUser = await this.userService.findById(doc.createUserId);
|
const createUser = await this.userService.findById(doc.createUserId);
|
||||||
|
|
||||||
return { document: { ...doc, views, createUser }, authority };
|
return { document: { ...doc, views, createUser }, authority };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,21 +425,6 @@ export class DocumentService {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public async getDocumentVersion(user: OutUser, documentId: string) {
|
public async getDocumentVersion(user: OutUser, documentId: string) {
|
||||||
const document = await this.documentRepo.findOne(documentId);
|
|
||||||
|
|
||||||
if (!document) {
|
|
||||||
throw new HttpException('文档不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
const authority = await this.documentAuthorityRepo.findOne({
|
|
||||||
documentId,
|
|
||||||
userId: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!authority || !authority.readable) {
|
|
||||||
throw new HttpException('您无权查看此文档', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await this.documentVersionService.getDocumentVersions(documentId);
|
const data = await this.documentVersionService.getDocumentVersions(documentId);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
@ -520,19 +435,6 @@ export class DocumentService {
|
||||||
*/
|
*/
|
||||||
async shareDocument(user: OutUser, documentId, dto: ShareDocumentDto, nextStatus = null) {
|
async shareDocument(user: OutUser, documentId, dto: ShareDocumentDto, nextStatus = null) {
|
||||||
const document = await this.documentRepo.findOne(documentId);
|
const document = await this.documentRepo.findOne(documentId);
|
||||||
if (!document) {
|
|
||||||
throw new HttpException('文档不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
const authority = await this.documentAuthorityRepo.findOne({
|
|
||||||
documentId,
|
|
||||||
userId: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!authority || !authority.editable) {
|
|
||||||
throw new HttpException('您无权编辑此文档', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
nextStatus = !nextStatus
|
nextStatus = !nextStatus
|
||||||
? document.status === DocumentStatus.private
|
? document.status === DocumentStatus.private
|
||||||
? DocumentStatus.public
|
? DocumentStatus.public
|
||||||
|
@ -553,14 +455,6 @@ export class DocumentService {
|
||||||
async getPublicDocumentDetail(documentId, dto: ShareDocumentDto, userAgent) {
|
async getPublicDocumentDetail(documentId, dto: ShareDocumentDto, userAgent) {
|
||||||
const document = await this.documentRepo.findOne(documentId);
|
const document = await this.documentRepo.findOne(documentId);
|
||||||
|
|
||||||
if (!document) {
|
|
||||||
throw new HttpException('文档不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.status !== DocumentStatus.public) {
|
|
||||||
throw new HttpException('私有文档,无法查看内容', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.sharePassword && !dto.sharePassword) {
|
if (document.sharePassword && !dto.sharePassword) {
|
||||||
throw new HttpException('输入密码后查看内容', HttpStatus.BAD_REQUEST);
|
throw new HttpException('输入密码后查看内容', HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
@ -596,21 +490,8 @@ export class DocumentService {
|
||||||
? await this.documentRepo.findOne(documentId)
|
? await this.documentRepo.findOne(documentId)
|
||||||
: await this.documentRepo.findOne({ wikiId, isWikiHome: true });
|
: await this.documentRepo.findOne({ wikiId, isWikiHome: true });
|
||||||
|
|
||||||
if (!document) {
|
|
||||||
throw new HttpException('文档不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
let unSortDocuments = [];
|
let unSortDocuments = [];
|
||||||
|
|
||||||
const authority = await this.documentAuthorityRepo.findOne({
|
|
||||||
documentId: document.id,
|
|
||||||
userId: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!authority || !authority.readable) {
|
|
||||||
throw new HttpException('您无权查看该文档下的子文档', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.isWikiHome) {
|
if (document.isWikiHome) {
|
||||||
unSortDocuments = await this.documentRepo.find({
|
unSortDocuments = await this.documentRepo.find({
|
||||||
wikiId: document.wikiId,
|
wikiId: document.wikiId,
|
||||||
|
@ -661,16 +542,8 @@ export class DocumentService {
|
||||||
? await this.documentRepo.findOne(documentId)
|
? await this.documentRepo.findOne(documentId)
|
||||||
: await this.documentRepo.findOne({ wikiId, isWikiHome: true });
|
: await this.documentRepo.findOne({ wikiId, isWikiHome: true });
|
||||||
|
|
||||||
if (!document) {
|
|
||||||
throw new HttpException('文档不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
let unSortDocuments = [];
|
let unSortDocuments = [];
|
||||||
|
|
||||||
if (document.status !== DocumentStatus.public) {
|
|
||||||
throw new HttpException('私有文档,无法查看内容', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.isWikiHome) {
|
if (document.isWikiHome) {
|
||||||
unSortDocuments = await this.documentRepo.find({
|
unSortDocuments = await this.documentRepo.find({
|
||||||
wikiId: document.wikiId,
|
wikiId: document.wikiId,
|
||||||
|
@ -717,153 +590,6 @@ export class DocumentService {
|
||||||
return docsWithCreateUser;
|
return docsWithCreateUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取知识库的文档目录
|
|
||||||
* @param user
|
|
||||||
* @param dto
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
public async getWikiTocs(user: OutUser, wikiId: string) {
|
|
||||||
const ONE_DAY_TIME = 24 * 60 * 60 * 1000;
|
|
||||||
await this.wikiService.getWikiDetail(user, wikiId);
|
|
||||||
// @ts-ignore
|
|
||||||
const records = await this.documentAuthorityRepo.find({
|
|
||||||
userId: user.id,
|
|
||||||
wikiId,
|
|
||||||
});
|
|
||||||
|
|
||||||
const ids = records.map((record) => record.documentId);
|
|
||||||
const documents = await this.documentRepo.findByIds(ids, {
|
|
||||||
order: { createdAt: 'ASC' },
|
|
||||||
});
|
|
||||||
documents.sort((a, b) => a.index - b.index);
|
|
||||||
|
|
||||||
documents.forEach((doc) => {
|
|
||||||
delete doc.state;
|
|
||||||
});
|
|
||||||
|
|
||||||
const docs = documents
|
|
||||||
.filter((doc) => !doc.isWikiHome)
|
|
||||||
.map((doc) => {
|
|
||||||
const res = instanceToPlain(doc);
|
|
||||||
res.key = res.id;
|
|
||||||
res.label = res.title;
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
|
|
||||||
const docsWithCreateUser = await Promise.all(
|
|
||||||
docs.map(async (doc) => {
|
|
||||||
const createUser = await this.userService.findById(doc.createUserId);
|
|
||||||
return { ...doc, createUser };
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return array2tree(docsWithCreateUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重排知识库目录
|
|
||||||
* @param user
|
|
||||||
* @param wikiId
|
|
||||||
* @param relations
|
|
||||||
*/
|
|
||||||
public async orderWikiTocs(
|
|
||||||
user: OutUser,
|
|
||||||
wikiId: string,
|
|
||||||
relations: Array<{ id: string; parentDocumentId?: string; index: number }>
|
|
||||||
) {
|
|
||||||
await this.wikiService.getWikiDetail(user, wikiId);
|
|
||||||
await Promise.all(
|
|
||||||
relations.map(async (relation) => {
|
|
||||||
const { id, parentDocumentId, index } = relation;
|
|
||||||
const doc = await this.documentRepo.findOne(id);
|
|
||||||
|
|
||||||
if (doc) {
|
|
||||||
const newData = await this.documentRepo.merge(doc, {
|
|
||||||
parentDocumentId,
|
|
||||||
index,
|
|
||||||
});
|
|
||||||
await this.documentRepo.save(newData);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取知识库公开的文档目录
|
|
||||||
* @param user
|
|
||||||
* @param dto
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
public async getPublicWikiTocs(wikiId: string) {
|
|
||||||
await this.wikiService.getPublicWikiDetail(wikiId);
|
|
||||||
// @ts-ignore
|
|
||||||
const unSortDocuments = await this.documentRepo.find({
|
|
||||||
wikiId,
|
|
||||||
status: DocumentStatus.public,
|
|
||||||
});
|
|
||||||
|
|
||||||
const documents = await this.documentRepo.findByIds(
|
|
||||||
unSortDocuments.map((d) => d.id),
|
|
||||||
{
|
|
||||||
order: { createdAt: 'ASC' },
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
documents.sort((a, b) => a.index - b.index);
|
|
||||||
|
|
||||||
const docs = documents
|
|
||||||
.filter((doc) => !doc.isWikiHome)
|
|
||||||
.map((doc) => {
|
|
||||||
const res = instanceToPlain(doc);
|
|
||||||
res.key = res.id;
|
|
||||||
res.label = res.title;
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
|
|
||||||
docs.forEach((doc) => {
|
|
||||||
delete doc.state;
|
|
||||||
});
|
|
||||||
|
|
||||||
return array2tree(docs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取知识库所有的文档
|
|
||||||
* @param user
|
|
||||||
* @param dto
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
public async getWikiDocs(user: OutUser, wikiId: string) {
|
|
||||||
this.wikiService.getWikiDetail(user, wikiId);
|
|
||||||
const records = await this.documentAuthorityRepo.find({
|
|
||||||
userId: user.id,
|
|
||||||
wikiId,
|
|
||||||
});
|
|
||||||
const ids = records.map((record) => record.documentId);
|
|
||||||
const documents = await this.documentRepo.findByIds(ids);
|
|
||||||
documents.forEach((doc) => {
|
|
||||||
delete doc.state;
|
|
||||||
});
|
|
||||||
|
|
||||||
const docs = documents
|
|
||||||
.filter((doc) => !doc.isWikiHome)
|
|
||||||
.map((doc) => {
|
|
||||||
const res = instanceToPlain(doc);
|
|
||||||
res.key = res.id;
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
|
|
||||||
const docsWithCreateUser = await Promise.all(
|
|
||||||
docs.map(async (doc) => {
|
|
||||||
const createUser = await this.userService.findById(doc.createUserId);
|
|
||||||
return { ...doc, createUser };
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return docsWithCreateUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户最近更新的10篇文档
|
* 获取用户最近更新的10篇文档
|
||||||
* @param user
|
* @param user
|
||||||
|
|
|
@ -17,8 +17,7 @@ export class FileService {
|
||||||
* @param file
|
* @param file
|
||||||
*/
|
*/
|
||||||
async uploadFile(file) {
|
async uploadFile(file) {
|
||||||
console.log('upload', file);
|
const { originalname, buffer } = file;
|
||||||
const { originalname, mimetype, size, buffer } = file;
|
|
||||||
const filename = `/${dateFormat(new Date(), 'yyyy-MM-dd')}/${uniqueid()}/${originalname}`;
|
const filename = `/${dateFormat(new Date(), 'yyyy-MM-dd')}/${uniqueid()}/${originalname}`;
|
||||||
const url = await this.ossClient.putFile(filename, buffer);
|
const url = await this.ossClient.putFile(filename, buffer);
|
||||||
return url;
|
return url;
|
||||||
|
|
|
@ -12,6 +12,7 @@ export class TemplateService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(TemplateEntity)
|
@InjectRepository(TemplateEntity)
|
||||||
private readonly templateRepo: Repository<TemplateEntity>,
|
private readonly templateRepo: Repository<TemplateEntity>,
|
||||||
|
|
||||||
@Inject(forwardRef(() => UserService))
|
@Inject(forwardRef(() => UserService))
|
||||||
private readonly userService: UserService
|
private readonly userService: UserService
|
||||||
) {}
|
) {}
|
||||||
|
|
|
@ -20,32 +20,21 @@ export class UserService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(UserEntity)
|
@InjectRepository(UserEntity)
|
||||||
private readonly userRepo: Repository<UserEntity>,
|
private readonly userRepo: Repository<UserEntity>,
|
||||||
|
|
||||||
private readonly confifgService: ConfigService,
|
private readonly confifgService: ConfigService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => JwtService))
|
@Inject(forwardRef(() => JwtService))
|
||||||
private readonly jwtService: JwtService,
|
private readonly jwtService: JwtService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => MessageService))
|
@Inject(forwardRef(() => MessageService))
|
||||||
private readonly messageService: MessageService,
|
private readonly messageService: MessageService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => CollectorService))
|
@Inject(forwardRef(() => CollectorService))
|
||||||
private readonly collectorService: CollectorService,
|
private readonly collectorService: CollectorService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => WikiService))
|
@Inject(forwardRef(() => WikiService))
|
||||||
private readonly wikiService: WikiService
|
private readonly wikiService: WikiService
|
||||||
) {
|
) {}
|
||||||
this.createSuperAdmin();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async createSuperAdmin() {
|
|
||||||
const superadmin = this.confifgService.get('superadmin');
|
|
||||||
if (!superadmin) return;
|
|
||||||
if (!(await this.userRepo.findOne({ name: superadmin.name }))) {
|
|
||||||
const res = await this.userRepo.create({
|
|
||||||
...superadmin,
|
|
||||||
confirmPassword: superadmin.password,
|
|
||||||
role: UserRole.superadmin,
|
|
||||||
});
|
|
||||||
await this.userRepo.save(res);
|
|
||||||
}
|
|
||||||
console.info('已注册超管用户,请及时修改默认密码');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据 id 查询用户
|
* 根据 id 查询用户
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
import { Injectable, HttpException, HttpStatus, Inject, forwardRef } from '@nestjs/common';
|
import { Injectable, HttpException, HttpStatus, Inject, forwardRef } from '@nestjs/common';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
import { instanceToPlain } from 'class-transformer';
|
||||||
import { WikiStatus, WikiUserRole, DocumentStatus, IPagination } from '@think/domains';
|
import { WikiStatus, WikiUserRole, DocumentStatus, IPagination } from '@think/domains';
|
||||||
|
import { array2tree } from '@helpers/tree.helper';
|
||||||
import { WikiEntity } from '@entities/wiki.entity';
|
import { WikiEntity } from '@entities/wiki.entity';
|
||||||
import { WikiUserEntity } from '@entities/wiki-user.entity';
|
import { WikiUserEntity } from '@entities/wiki-user.entity';
|
||||||
import { UserService } from '@services/user.service';
|
import { UserService } from '@services/user.service';
|
||||||
import { MessageService } from '@services/message.service';
|
import { MessageService } from '@services/message.service';
|
||||||
import { CollectorService } from '@services/collector.service';
|
import { CollectorService } from '@services/collector.service';
|
||||||
import { OutUser } from '@services/user.service';
|
import { OutUser } from '@services/user.service';
|
||||||
|
import { ViewService } from '@services/view.service';
|
||||||
import { DocumentService } from '@services/document.service';
|
import { DocumentService } from '@services/document.service';
|
||||||
import { WikiUserDto } from '@dtos/wiki-user.dto';
|
import { WikiUserDto } from '@dtos/wiki-user.dto';
|
||||||
import { CreateWikiDto } from '@dtos/create-wiki.dto';
|
import { CreateWikiDto } from '@dtos/create-wiki.dto';
|
||||||
|
@ -19,18 +22,36 @@ export class WikiService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(WikiEntity)
|
@InjectRepository(WikiEntity)
|
||||||
private readonly wikiRepo: Repository<WikiEntity>,
|
private readonly wikiRepo: Repository<WikiEntity>,
|
||||||
|
|
||||||
@InjectRepository(WikiUserEntity)
|
@InjectRepository(WikiUserEntity)
|
||||||
private readonly wikiUserRepo: Repository<WikiUserEntity>,
|
private readonly wikiUserRepo: Repository<WikiUserEntity>,
|
||||||
|
|
||||||
@Inject(forwardRef(() => MessageService))
|
@Inject(forwardRef(() => MessageService))
|
||||||
private readonly messageService: MessageService,
|
private readonly messageService: MessageService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => CollectorService))
|
@Inject(forwardRef(() => CollectorService))
|
||||||
private readonly collectorService: CollectorService,
|
private readonly collectorService: CollectorService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => DocumentService))
|
@Inject(forwardRef(() => DocumentService))
|
||||||
private readonly documentService: DocumentService,
|
private readonly documentService: DocumentService,
|
||||||
|
|
||||||
@Inject(forwardRef(() => UserService))
|
@Inject(forwardRef(() => UserService))
|
||||||
private readonly userService: UserService
|
private readonly userService: UserService,
|
||||||
|
|
||||||
|
@Inject(forwardRef(() => ViewService))
|
||||||
|
private readonly viewService: ViewService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 id 查取知识库
|
||||||
|
* @param user
|
||||||
|
* @param dto
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public async findById(id: string) {
|
||||||
|
return await this.wikiRepo.findOne(id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按 id 查取一组知识库
|
* 按 id 查取一组知识库
|
||||||
* @param user
|
* @param user
|
||||||
|
@ -42,6 +63,19 @@ export class WikiService {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取知识库成员信息
|
||||||
|
* @param wikiId
|
||||||
|
* @param userId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public async findWikiUser(wikiId: string, userId: string) {
|
||||||
|
return await this.wikiUserRepo.findOne({
|
||||||
|
userId,
|
||||||
|
wikiId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 操作知识库成员(添加、修改角色)
|
* 操作知识库成员(添加、修改角色)
|
||||||
* @param param0
|
* @param param0
|
||||||
|
@ -133,6 +167,7 @@ export class WikiService {
|
||||||
}
|
}
|
||||||
|
|
||||||
const homeDoc = await this.getWikiHomeDocument(user, wikiId);
|
const homeDoc = await this.getWikiHomeDocument(user, wikiId);
|
||||||
|
|
||||||
await this.documentService.operateDocumentAuth({
|
await this.documentService.operateDocumentAuth({
|
||||||
currentUserId: user.id,
|
currentUserId: user.id,
|
||||||
documentId: homeDoc.id,
|
documentId: homeDoc.id,
|
||||||
|
@ -140,6 +175,7 @@ export class WikiService {
|
||||||
readable: true,
|
readable: true,
|
||||||
editable: dto.userRole === WikiUserRole.admin,
|
editable: dto.userRole === WikiUserRole.admin,
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.operateWikiUser({
|
return this.operateWikiUser({
|
||||||
wikiId,
|
wikiId,
|
||||||
currentUserId: user.id,
|
currentUserId: user.id,
|
||||||
|
@ -177,17 +213,6 @@ export class WikiService {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async deleteWikiUser(user: OutUser, wikiId, dto: WikiUserDto): Promise<void> {
|
async deleteWikiUser(user: OutUser, wikiId, dto: WikiUserDto): Promise<void> {
|
||||||
const currentWikiUserRole = (
|
|
||||||
await this.wikiUserRepo.findOne({
|
|
||||||
wikiId,
|
|
||||||
userId: user.id,
|
|
||||||
})
|
|
||||||
).userRole;
|
|
||||||
|
|
||||||
if (currentWikiUserRole !== WikiUserRole.admin) {
|
|
||||||
throw new HttpException('您无权限进行该操作', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetUser = await this.userService.findOne({ name: dto.userName });
|
const targetUser = await this.userService.findOne({ name: dto.userName });
|
||||||
|
|
||||||
if (!targetUser) {
|
if (!targetUser) {
|
||||||
|
@ -207,7 +232,7 @@ export class WikiService {
|
||||||
|
|
||||||
await this.messageService.notify(targetUser, {
|
await this.messageService.notify(targetUser, {
|
||||||
title: `您已被移出知识库「${wiki.name}」`,
|
title: `您已被移出知识库「${wiki.name}」`,
|
||||||
message: `管理员已将您从知识库「${wiki.name}」移出!`,
|
message: `${user.name}已将您从知识库「${wiki.name}」移出!`,
|
||||||
url: `/wiki/${wiki.id}`,
|
url: `/wiki/${wiki.id}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -218,15 +243,8 @@ export class WikiService {
|
||||||
* 获取知识库成员
|
* 获取知识库成员
|
||||||
* @param userId
|
* @param userId
|
||||||
* @param wikiId
|
* @param wikiId
|
||||||
* @param internalInvoke 是否为内部调用,内部调用忽略权限检查
|
|
||||||
*/
|
*/
|
||||||
async getWikiUsers({ userId, wikiId }, internalInvoke = false) {
|
async getWikiUsers(wikiId) {
|
||||||
const currenWikiUser = await this.getWikiUserDetail({ userId, wikiId });
|
|
||||||
|
|
||||||
if (currenWikiUser.userRole !== WikiUserRole.admin && !internalInvoke) {
|
|
||||||
throw new HttpException('您无权限查看', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
const records = await this.wikiUserRepo.find({ wikiId });
|
const records = await this.wikiUserRepo.find({ wikiId });
|
||||||
const ids = records.map((record) => record.userId);
|
const ids = records.map((record) => record.userId);
|
||||||
const users = await this.userService.findByIds(ids);
|
const users = await this.userService.findByIds(ids);
|
||||||
|
@ -382,21 +400,7 @@ export class WikiService {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async getWikiDetail(user: OutUser, wikiId: string) {
|
async getWikiDetail(user: OutUser, wikiId: string) {
|
||||||
const wikiUser = await this.wikiUserRepo.findOne({
|
|
||||||
userId: user.id,
|
|
||||||
wikiId,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!wikiUser) {
|
|
||||||
throw new HttpException('您无权查看该知识库', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
const wiki = await this.wikiRepo.findOne(wikiId);
|
const wiki = await this.wikiRepo.findOne(wikiId);
|
||||||
|
|
||||||
if (!wiki) {
|
|
||||||
throw new HttpException('访问的知识库不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
const createUser = await this.userService.findById(wiki.createUserId);
|
const createUser = await this.userService.findById(wiki.createUserId);
|
||||||
return { ...wiki, createUser };
|
return { ...wiki, createUser };
|
||||||
}
|
}
|
||||||
|
@ -408,48 +412,8 @@ export class WikiService {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async getWikiHomeDocument(user: OutUser, wikiId) {
|
async getWikiHomeDocument(user: OutUser, wikiId) {
|
||||||
await this.getWikiUserDetail({ wikiId, userId: user.id });
|
const res = await this.documentService.documentRepo.findOne({ wikiId, isWikiHome: true });
|
||||||
return this.documentService.getWikiHomeDocument(user, wikiId);
|
return instanceToPlain(res);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取公开知识库首页文档(首页文档由系统自动创建)
|
|
||||||
* @param user
|
|
||||||
* @param wikiId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async getWikiPublicHomeDocument(wikiId, userAgent) {
|
|
||||||
const wiki = await this.wikiRepo.findOne(wikiId);
|
|
||||||
|
|
||||||
if (!wiki) {
|
|
||||||
throw new HttpException('目标知识库不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wiki.status !== WikiStatus.public) {
|
|
||||||
throw new HttpException('私有文档,无法查看内容', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.documentService.getWikiPublicHomeDocument(wikiId, userAgent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取公开知识库详情
|
|
||||||
* @param wikiId
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
async getPublicWikiDetail(wikiId: string) {
|
|
||||||
const wiki = await this.wikiRepo.findOne(wikiId);
|
|
||||||
|
|
||||||
if (!wiki) {
|
|
||||||
throw new HttpException('目标知识库不存在', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wiki.status !== WikiStatus.public) {
|
|
||||||
throw new HttpException('私有文档,无法查看内容', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
const createUser = await this.userService.findById(wiki.createUserId);
|
|
||||||
return { ...wiki, createUser };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -460,15 +424,6 @@ export class WikiService {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async updateWiki(user: OutUser, wikiId, dto: UpdateWikiDto) {
|
async updateWiki(user: OutUser, wikiId, dto: UpdateWikiDto) {
|
||||||
const workspaceUser = await this.getWikiUserDetail({
|
|
||||||
wikiId,
|
|
||||||
userId: user.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (workspaceUser.userRole !== WikiUserRole.admin) {
|
|
||||||
throw new HttpException('您没有权限更新该知识库信息', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldData = await this.wikiRepo.findOne(wikiId);
|
const oldData = await this.wikiRepo.findOne(wikiId);
|
||||||
if (!oldData) {
|
if (!oldData) {
|
||||||
throw new HttpException('目标知识库不存在', HttpStatus.NOT_FOUND);
|
throw new HttpException('目标知识库不存在', HttpStatus.NOT_FOUND);
|
||||||
|
@ -488,10 +443,6 @@ export class WikiService {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async deleteWiki(user: OutUser, wikiId) {
|
async deleteWiki(user: OutUser, wikiId) {
|
||||||
const wikiUser = await this.getWikiUserDetail({ wikiId, userId: user.id });
|
|
||||||
if (wikiUser.userRole !== WikiUserRole.admin) {
|
|
||||||
throw new HttpException('您没有权限操作该知识库', HttpStatus.FORBIDDEN);
|
|
||||||
}
|
|
||||||
const wiki = await this.wikiRepo.findOne(wikiId);
|
const wiki = await this.wikiRepo.findOne(wikiId);
|
||||||
if (user.id !== wiki.createUserId) {
|
if (user.id !== wiki.createUserId) {
|
||||||
throw new HttpException('您不是创建者,无法删除该知识库', HttpStatus.FORBIDDEN);
|
throw new HttpException('您不是创建者,无法删除该知识库', HttpStatus.FORBIDDEN);
|
||||||
|
@ -565,7 +516,38 @@ export class WikiService {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async getWikiTocs(user: OutUser, wikiId) {
|
async getWikiTocs(user: OutUser, wikiId) {
|
||||||
return await this.documentService.getWikiTocs(user, wikiId);
|
const records = await this.documentService.documentAuthorityRepo.find({
|
||||||
|
userId: user.id,
|
||||||
|
wikiId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const ids = records.map((record) => record.documentId);
|
||||||
|
const documents = await this.documentService.documentRepo.findByIds(ids, {
|
||||||
|
order: { createdAt: 'ASC' },
|
||||||
|
});
|
||||||
|
documents.sort((a, b) => a.index - b.index);
|
||||||
|
|
||||||
|
documents.forEach((doc) => {
|
||||||
|
delete doc.state;
|
||||||
|
});
|
||||||
|
|
||||||
|
const docs = documents
|
||||||
|
.filter((doc) => !doc.isWikiHome)
|
||||||
|
.map((doc) => {
|
||||||
|
const res = instanceToPlain(doc);
|
||||||
|
res.key = res.id;
|
||||||
|
res.label = res.title;
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
|
||||||
|
const docsWithCreateUser = await Promise.all(
|
||||||
|
docs.map(async (doc) => {
|
||||||
|
const createUser = await this.userService.findById(doc.createUserId);
|
||||||
|
return { ...doc, createUser };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return array2tree(docsWithCreateUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -574,22 +556,59 @@ export class WikiService {
|
||||||
* @param wikiId
|
* @param wikiId
|
||||||
* @param relations
|
* @param relations
|
||||||
*/
|
*/
|
||||||
public async orderWikiTocs(
|
public async orderWikiTocs(relations: Array<{ id: string; parentDocumentId?: string; index: number }>) {
|
||||||
user: OutUser,
|
await Promise.all(
|
||||||
wikiId: string,
|
relations.map(async (relation) => {
|
||||||
relations: Array<{ id: string; parentDocumentId?: string; index: number }>
|
const { id, parentDocumentId, index } = relation;
|
||||||
) {
|
const doc = await this.documentService.documentRepo.findOne(id);
|
||||||
return await this.documentService.orderWikiTocs(user, wikiId, relations);
|
|
||||||
|
if (doc) {
|
||||||
|
const newData = await this.documentService.documentRepo.merge(doc, {
|
||||||
|
parentDocumentId,
|
||||||
|
index,
|
||||||
|
});
|
||||||
|
await this.documentService.documentRepo.save(newData);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取知识库目录
|
* 获取知识库所有文档(无结构嵌套)
|
||||||
* @param user
|
* @param user
|
||||||
* @param wikiId
|
* @param wikiId
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async getWikiDocs(user: OutUser, wikiId) {
|
async getWikiDocs(user: OutUser, wikiId) {
|
||||||
return await this.documentService.getWikiDocs(user, wikiId);
|
// 通过文档成员表获取当前用户可查阅的所有文档
|
||||||
|
const records = await this.documentService.documentAuthorityRepo.find({
|
||||||
|
userId: user.id,
|
||||||
|
wikiId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const ids = records.map((record) => record.documentId);
|
||||||
|
|
||||||
|
const documents = await this.documentService.documentRepo.findByIds(ids);
|
||||||
|
documents.forEach((doc) => {
|
||||||
|
delete doc.state;
|
||||||
|
});
|
||||||
|
|
||||||
|
const docs = documents
|
||||||
|
.filter((doc) => !doc.isWikiHome)
|
||||||
|
.map((doc) => {
|
||||||
|
const res = instanceToPlain(doc);
|
||||||
|
res.key = res.id;
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
|
||||||
|
const docsWithCreateUser = await Promise.all(
|
||||||
|
docs.map(async (doc) => {
|
||||||
|
const createUser = await this.userService.findById(doc.createUserId);
|
||||||
|
return { ...doc, createUser };
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return docsWithCreateUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -598,11 +617,67 @@ export class WikiService {
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async getPublicWikiTocs(wikiId) {
|
async getPublicWikiTocs(wikiId) {
|
||||||
return await this.documentService.getPublicWikiTocs(wikiId);
|
const unSortDocuments = await this.documentService.documentRepo.find({
|
||||||
|
wikiId,
|
||||||
|
status: DocumentStatus.public,
|
||||||
|
});
|
||||||
|
|
||||||
|
const documents = await this.documentService.documentRepo.findByIds(
|
||||||
|
unSortDocuments.map((d) => d.id),
|
||||||
|
{
|
||||||
|
order: { createdAt: 'ASC' },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
documents.sort((a, b) => a.index - b.index);
|
||||||
|
|
||||||
|
const docs = documents
|
||||||
|
.filter((doc) => !doc.isWikiHome)
|
||||||
|
.map((doc) => {
|
||||||
|
const res = instanceToPlain(doc);
|
||||||
|
res.key = res.id;
|
||||||
|
res.label = res.title;
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
|
||||||
|
docs.forEach((doc) => {
|
||||||
|
delete doc.state;
|
||||||
|
});
|
||||||
|
|
||||||
|
return array2tree(docs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前用户所有知识库
|
* 获取公开知识库首页文档(首页文档由系统自动创建)
|
||||||
|
* @param user
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async getPublicWikiHomeDocument(wikiId, userAgent) {
|
||||||
|
const res = await this.documentService.documentRepo.findOne({ wikiId, isWikiHome: true });
|
||||||
|
|
||||||
|
await this.viewService.create({
|
||||||
|
userId: 'public',
|
||||||
|
documentId: res.id,
|
||||||
|
userAgent,
|
||||||
|
});
|
||||||
|
const views = await this.viewService.getDocumentTotalViews(res.id);
|
||||||
|
return { ...instanceToPlain(res), views };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取公开知识库详情
|
||||||
|
* @param wikiId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async getPublicWikiDetail(wikiId: string) {
|
||||||
|
const wiki = await this.wikiRepo.findOne(wikiId);
|
||||||
|
const createUser = await this.userService.findById(wiki.createUserId);
|
||||||
|
return { ...wiki, createUser };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有公开知识库
|
||||||
* @param user
|
* @param user
|
||||||
* @param pagination
|
* @param pagination
|
||||||
* @returns
|
* @returns
|
||||||
|
|
Loading…
Reference in New Issue