diff --git a/packages/admin/src/components/AuthorField/index.tsx b/packages/admin/src/components/AuthorField/index.tsx new file mode 100644 index 000000000..0e2f31dfb --- /dev/null +++ b/packages/admin/src/components/AuthorField/index.tsx @@ -0,0 +1,25 @@ +import { getAllCollaboratorsList } from '@/services/van-blog/api'; +import { ProFormSelect } from '@ant-design/pro-form'; +export default function () { + return ( + <> + { + const msg = await getAllCollaboratorsList(); + + return ( + msg?.data?.map((item) => ({ + label: item.nickname || item.name, + value: item.nickname || item.name, + })) || [] + ); + }} + /> + + ); +} diff --git a/packages/admin/src/components/NewArticleModal/index.jsx b/packages/admin/src/components/NewArticleModal/index.jsx index d64a56d83..be992ba34 100644 --- a/packages/admin/src/components/NewArticleModal/index.jsx +++ b/packages/admin/src/components/NewArticleModal/index.jsx @@ -7,6 +7,7 @@ import { } from '@ant-design/pro-components'; import { Button, Modal } from 'antd'; import moment from 'moment'; +import AuthorField from '../AuthorField'; export default function (props) { const { onFinish } = props; @@ -25,8 +26,7 @@ export default function (props) { if (location.hostname == 'blog-demo.mereith.com') { Modal.info({ title: '演示站禁止新建文章!', - content: - '本来是可以的,但有个人在演示站首页放黄色信息,所以关了这个权限了。', + content: '本来是可以的,但有个人在演示站首页放黄色信息,所以关了这个权限了。', }); return; } @@ -55,6 +55,7 @@ export default function (props) { placeholder="请输入标题" rules={[{ required: true, message: '这是必填项' }]} /> + + + { label="登录用户名" placeholder={'请输入登录用户名'} > + {/* */} + {/* */} diff --git a/packages/admin/src/services/van-blog/api.js b/packages/admin/src/services/van-blog/api.js index e55ba306e..999c8cff6 100644 --- a/packages/admin/src/services/van-blog/api.js +++ b/packages/admin/src/services/van-blog/api.js @@ -318,6 +318,11 @@ export async function getTags() { method: 'GET', }); } +export async function getAllCollaboratorsList() { + return request(`/api/admin/collaborator/list`, { + method: 'GET', + }); +} export async function importAll() { return request(`/api/admin/backup/import`, { method: 'POST', diff --git a/packages/server/src/controller/admin/article/article.controller.ts b/packages/server/src/controller/admin/article/article.controller.ts index 03a64493a..304d579c5 100644 --- a/packages/server/src/controller/admin/article/article.controller.ts +++ b/packages/server/src/controller/admin/article/article.controller.ts @@ -7,6 +7,7 @@ import { Post, Put, Query, + Req, UseGuards, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; @@ -16,6 +17,8 @@ import { SortOrder } from 'src/types/sort'; import { ArticleProvider } from 'src/provider/article/article.provider'; import { AdminGuard } from 'src/provider/auth/auth.guard'; import { ISRProvider } from 'src/provider/isr/isr.provider'; +import { UserProvider } from 'src/provider/user/user.provider'; +import { MetaProvider } from 'src/provider/meta/meta.provider'; @ApiTags('article') @UseGuards(...AdminGuard) @Controller('/api/admin/article') @@ -23,6 +26,8 @@ export class ArticleController { constructor( private readonly articleProvider: ArticleProvider, private readonly isrProvider: ISRProvider, + private readonly userProvider: UserProvider, + private readonly metaProvider: MetaProvider, ) {} @Get('/') @@ -87,13 +92,17 @@ export class ArticleController { } @Post() - async create(@Body() createDto: CreateArticleDto) { + async create(@Req() req: any, @Body() createDto: CreateArticleDto) { if (config.demo && config.demo == 'true') { return { statusCode: 401, message: '演示站禁止创建文章!', }; } + const author = req?.user?.nickname || undefined; + if (!createDto.author) { + createDto.author = author; + } const data = await this.articleProvider.create(createDto); this.isrProvider.activeAll('创建文章触发增量渲染!'); return { diff --git a/packages/server/src/controller/admin/collaborator/collaborator.controller.ts b/packages/server/src/controller/admin/collaborator/collaborator.controller.ts index 4fe610d13..934e4ae19 100644 --- a/packages/server/src/controller/admin/collaborator/collaborator.controller.ts +++ b/packages/server/src/controller/admin/collaborator/collaborator.controller.ts @@ -13,6 +13,7 @@ import { ApiTags } from '@nestjs/swagger'; import { config } from 'src/config'; import { AdminGuard } from 'src/provider/auth/auth.guard'; +import { MetaProvider } from 'src/provider/meta/meta.provider'; import { UserProvider } from 'src/provider/user/user.provider'; import { Collaborator } from 'src/types/collaborator'; @@ -21,7 +22,10 @@ import { Collaborator } from 'src/types/collaborator'; @UseGuards(...AdminGuard) @Controller('/api/admin/collaborator/') export class CollaboratorController { - constructor(private readonly userProvider: UserProvider) {} + constructor( + private readonly userProvider: UserProvider, + private readonly metaProvider: MetaProvider, + ) {} @Get() async getAllCollaborators() { const data = await this.userProvider.getAllCollaborators(); @@ -30,6 +34,22 @@ export class CollaboratorController { data: data || [], }; } + @Get('/list') + async getAllCollaboratorsList() { + // 管理员优先用作者名称吧 + const siteInfo = await this.metaProvider.getSiteInfo(); + const admin = await this.userProvider.getUser(true); + const adminUser = { + name: admin.name, + nickname: siteInfo.author, + id: 0, + }; + const data = await this.userProvider.getAllCollaborators(true); + return { + statusCode: 200, + data: [adminUser, ...data] || [adminUser], + }; + } @Delete('/:id') async deleteCollaboratorById(@Param('id') id: number) { if (config.demo && config.demo == 'true') { diff --git a/packages/server/src/controller/admin/draft/draft.controller.ts b/packages/server/src/controller/admin/draft/draft.controller.ts index d8bf9cec9..4e4083211 100644 --- a/packages/server/src/controller/admin/draft/draft.controller.ts +++ b/packages/server/src/controller/admin/draft/draft.controller.ts @@ -7,6 +7,7 @@ import { Post, Put, Query, + Req, UseGuards, } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; @@ -79,7 +80,11 @@ export class DraftController { } @Post() - async create(@Body() createDto: CreateDraftDto) { + async create(@Req() req: any, @Body() createDto: CreateDraftDto) { + const author = req?.user?.nickname || undefined; + if (!createDto.author) { + createDto.author = author; + } const data = await this.draftProvider.create(createDto); return { statusCode: 200, diff --git a/packages/server/src/provider/article/article.provider.ts b/packages/server/src/provider/article/article.provider.ts index 3fab76da6..c8bdfa339 100644 --- a/packages/server/src/provider/article/article.provider.ts +++ b/packages/server/src/provider/article/article.provider.ts @@ -43,6 +43,7 @@ export class ArticleProvider { visited: 1, private: 1, hidden: 1, + author: 1, }; adminView = { @@ -61,6 +62,7 @@ export class ArticleProvider { _id: 0, viewer: 1, visited: 1, + author: 1, }; listView = { @@ -77,6 +79,7 @@ export class ArticleProvider { _id: 0, viewer: 1, visited: 1, + author: 1, }; toPublic(oldArticles: Article[]) { diff --git a/packages/server/src/provider/auth/jwt.strategy.ts b/packages/server/src/provider/auth/jwt.strategy.ts index 0f76b60e5..d2accf36c 100644 --- a/packages/server/src/provider/auth/jwt.strategy.ts +++ b/packages/server/src/provider/auth/jwt.strategy.ts @@ -2,11 +2,15 @@ import { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; import { config } from 'src/config/index'; +import { MetaProvider } from '../meta/meta.provider'; import { UserProvider } from '../user/user.provider'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { - constructor(private readonly userProvider: UserProvider) { + constructor( + private readonly userProvider: UserProvider, + private readonly metaProvider: MetaProvider, + ) { super({ // 获取请求header token值 jwtFromRequest: ExtractJwt.fromHeader('token'), @@ -21,6 +25,12 @@ export class JwtStrategy extends PassportStrategy(Strategy) { if (payload.sub != 0) { const user = await this.userProvider.getCollaboratorById(payload.sub); moreDto.permissions = user.permissions; + moreDto.nickname = user.nickname; + } else { + const user = await this.userProvider.getUser(); + const siteInfo = await this.metaProvider.getSiteInfo(); + const authorName = siteInfo.author; + moreDto.nickname = authorName || user.nickname; } return { name: payload.username, id: payload.sub, ...moreDto }; } diff --git a/packages/server/src/provider/draft/draft.provider.ts b/packages/server/src/provider/draft/draft.provider.ts index f2dae74cf..e2ab7d7d2 100644 --- a/packages/server/src/provider/draft/draft.provider.ts +++ b/packages/server/src/provider/draft/draft.provider.ts @@ -24,6 +24,7 @@ export class DraftProvider { category: 1, updatedAt: 1, createdAt: 1, + author: 1, id: 1, _id: 0, }; @@ -35,6 +36,7 @@ export class DraftProvider { category: 1, updatedAt: 1, createdAt: 1, + author: 1, id: 1, _id: 0, }; @@ -45,6 +47,7 @@ export class DraftProvider { category: 1, updatedAt: 1, createdAt: 1, + author: 1, id: 1, _id: 0, }; @@ -171,6 +174,7 @@ export class DraftProvider { content: draft.content, tags: draft.tags, category: draft.category, + author: draft.author, }; for (const [k, v] of Object.entries(options || {})) { createArticleDto[k] = v; diff --git a/packages/server/src/provider/init/init.provider.ts b/packages/server/src/provider/init/init.provider.ts index aa0f82e96..4678cb62e 100644 --- a/packages/server/src/provider/init/init.provider.ts +++ b/packages/server/src/provider/init/init.provider.ts @@ -25,6 +25,7 @@ export class InitProvider { id: 0, name: user.username, password: user.password, + mickname: user?.nickname || user.username, type: 'admin', }); await this.metaModel.create({ diff --git a/packages/server/src/provider/meta/meta.provider.ts b/packages/server/src/provider/meta/meta.provider.ts index 0a8cf27a5..8d91575ae 100644 --- a/packages/server/src/provider/meta/meta.provider.ts +++ b/packages/server/src/provider/meta/meta.provider.ts @@ -150,9 +150,6 @@ export class MetaProvider { async updateSiteInfo(updateSiteInfoDto: UpdateSiteInfoDto) { // @ts-ignore eslint-disable-next-line @typescript-eslint/ban-ts-comment const { name, password, ...updateDto } = updateSiteInfoDto; - if (name && name != '') { - this.userProvider.updateUser({ name: name, password }); - } const oldSiteInfo = await this.getSiteInfo(); return this.metaModel.updateOne( {}, diff --git a/packages/server/src/provider/user/user.provider.ts b/packages/server/src/provider/user/user.provider.ts index 17e96a229..2511f2a55 100644 --- a/packages/server/src/provider/user/user.provider.ts +++ b/packages/server/src/provider/user/user.provider.ts @@ -12,7 +12,13 @@ import { Collaborator } from 'src/types/collaborator'; @Injectable() export class UserProvider { constructor(@InjectModel('User') private userModel: Model) {} - async getUser() { + async getUser(isList?: boolean) { + if (isList) { + return await this.userModel.findOne( + { id: 0 }, + { id: 1, name: 1, nickname: 1 }, + ); + } return await this.userModel.findOne({ id: 0 }).exec(); } async validateUser(name: string, password: string) { @@ -43,7 +49,13 @@ export class UserProvider { async getCollaboratorById(id: number) { return await this.userModel.findOne({ id, type: 'collaborator' }); } - async getAllCollaborators() { + async getAllCollaborators(isList?: boolean) { + if (isList) { + return await this.userModel.find( + { type: 'collaborator' }, + { id: 1, name: 1, nickname: 1 }, + ); + } return await this.userModel.find({ type: 'collaborator' }); } diff --git a/packages/server/src/scheme/article.schema.ts b/packages/server/src/scheme/article.schema.ts index 900383f83..cc6a5fa77 100644 --- a/packages/server/src/scheme/article.schema.ts +++ b/packages/server/src/scheme/article.schema.ts @@ -25,6 +25,9 @@ export class Article extends Document { @Prop({ default: false }) hidden: boolean; + @Prop() + author: string; + @Prop({ default: false }) private: boolean; diff --git a/packages/server/src/scheme/draft.schema.ts b/packages/server/src/scheme/draft.schema.ts index ee4e4d835..4b4695a2f 100644 --- a/packages/server/src/scheme/draft.schema.ts +++ b/packages/server/src/scheme/draft.schema.ts @@ -17,6 +17,9 @@ export class Draft extends Document { @Prop({ default: [] }) tags: string[]; + @Prop() + author: string; + @Prop() category: string; diff --git a/packages/server/src/types/access/access.ts b/packages/server/src/types/access/access.ts index 29cd87116..afddcea62 100644 --- a/packages/server/src/types/access/access.ts +++ b/packages/server/src/types/access/access.ts @@ -45,6 +45,7 @@ export const publicRoutes = [ 'get-/api/admin/draft/:id', 'get-/api/admin/img/all', 'get-/api/admin/img', + 'get-/api/admin/collaborator/list', 'post-/api/admin/img/upload', 'post-/api/admin/article/searchByLink', ]; diff --git a/packages/server/src/types/article.dto.ts b/packages/server/src/types/article.dto.ts index b74befa28..158e79443 100644 --- a/packages/server/src/types/article.dto.ts +++ b/packages/server/src/types/article.dto.ts @@ -11,6 +11,7 @@ export class CreateArticleDto { password?: string; updatedAt?: Date; createdAt?: Date; + author?: string; } export class UpdateArticleDto { title?: string; @@ -25,6 +26,7 @@ export class UpdateArticleDto { viewer?: number; visited?: number; updatedAt?: Date; + author?: string; } export class SearchArticleOption { page: number; @@ -40,4 +42,5 @@ export class SearchArticleOption { sortViewer?: string; toListView?: boolean; withWordCount?: boolean; + author?: string; } diff --git a/packages/server/src/types/draft.dto.ts b/packages/server/src/types/draft.dto.ts index a4a5ab0dc..4b093cb67 100644 --- a/packages/server/src/types/draft.dto.ts +++ b/packages/server/src/types/draft.dto.ts @@ -5,6 +5,8 @@ export class CreateDraftDto { content?: string; tags?: string[]; category: string; + author?: string; + draft?: string; } export class UpdateDraftDto { title?: string; @@ -12,6 +14,8 @@ export class UpdateDraftDto { tags?: string[]; category?: string; deleted?: boolean; + author?: string; + draft?: string; } export class PublishDraftDto { hidden?: boolean; diff --git a/packages/server/src/types/init.dto.ts b/packages/server/src/types/init.dto.ts index 4fffab5ca..c2a925f5c 100644 --- a/packages/server/src/types/init.dto.ts +++ b/packages/server/src/types/init.dto.ts @@ -4,6 +4,7 @@ export class InitDto { user: { username: string; password: string; + nickname: string; }; siteInfo: SiteInfo; } diff --git a/packages/server/src/types/user.dto.ts b/packages/server/src/types/user.dto.ts index 29bdcc7b1..2929f3836 100644 --- a/packages/server/src/types/user.dto.ts +++ b/packages/server/src/types/user.dto.ts @@ -2,6 +2,7 @@ export class UpdateUserDto { id?: number; name: string; password: string; + nickname?: string; } export class LoginDto { username: string; diff --git a/packages/website/types/article.ts b/packages/website/types/article.ts index 9050f1886..2e51d69e3 100644 --- a/packages/website/types/article.ts +++ b/packages/website/types/article.ts @@ -8,4 +8,5 @@ export interface Article { id: number; top?: number; private: boolean; + author?: string; } diff --git a/packages/website/utils/getPageProps.ts b/packages/website/utils/getPageProps.ts index ad5eb9c11..72166c269 100644 --- a/packages/website/utils/getPageProps.ts +++ b/packages/website/utils/getPageProps.ts @@ -168,11 +168,13 @@ export async function getPostPagesProps( ], }; const currArticleProps = await getArticleById(parseInt(curId)); + const { article } = currArticleProps; + const author = article?.author || data.meta.siteInfo.author; return { layoutProps, ...currArticleProps, ...payProps, - author: data.meta.siteInfo.author, + author, showSubMenu: layoutProps.showSubMenu, }; }