枫叶秋林 2 лет назад
Родитель
Сommit
385ab7e946

+ 17 - 0
prisma/migrations/20230115011842_/migration.sql

@@ -0,0 +1,17 @@
+-- DropForeignKey
+ALTER TABLE `comment` DROP FOREIGN KEY `comment_authorId_fkey`;
+
+-- DropForeignKey
+ALTER TABLE `post` DROP FOREIGN KEY `post_authorId_fkey`;
+
+-- DropForeignKey
+ALTER TABLE `userinfo` DROP FOREIGN KEY `userinfo_authId_fkey`;
+
+-- AddForeignKey
+ALTER TABLE `post` ADD CONSTRAINT `post_authorId_fkey` FOREIGN KEY (`authorId`) REFERENCES `auth`(`auth_id`) ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE `comment` ADD CONSTRAINT `comment_authorId_fkey` FOREIGN KEY (`authorId`) REFERENCES `auth`(`auth_id`) ON DELETE CASCADE ON UPDATE CASCADE;
+
+-- AddForeignKey
+ALTER TABLE `userinfo` ADD CONSTRAINT `userinfo_authId_fkey` FOREIGN KEY (`authId`) REFERENCES `auth`(`auth_id`) ON DELETE CASCADE ON UPDATE CASCADE;

+ 2 - 0
prisma/migrations/20230202121542_post_add_post/migration.sql

@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE `post` ADD COLUMN `updatedTime` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3);

+ 4 - 3
prisma/schema.prisma

@@ -21,10 +21,11 @@ model post{
   title     String
   content   String    @db.VarChar(10000)
   createdAt DateTime  @default(now())
+  updatedTime DateTime @default(now())
   updatedAt DateTime  @updatedAt
   views     Int       @default(0) @db.UnsignedInt
   authorId  Int       @db.UnsignedInt
-  author    auth      @relation(fields: [authorId], references: [auth_id])
+  author    auth      @relation(fields: [authorId], references: [auth_id], onDelete: Cascade)
   comment   comment[]
   plateId   Int       @db.UnsignedInt @default(0)
   plate     plate     @relation(fields: [plateId], references: [id])
@@ -36,7 +37,7 @@ model comment{
   createdAt DateTime  @default(now())
   updatedAt DateTime  @updatedAt
   authorId  Int       @db.UnsignedInt
-  author    auth      @relation(fields: [authorId], references: [auth_id])
+  author    auth      @relation(fields: [authorId], references: [auth_id],onDelete: Cascade)
   postId    Int       @db.UnsignedInt
   post      post      @relation(fields: [postId], references: [id])
 }
@@ -58,7 +59,7 @@ model userinfo{
   mapleCoin Int       @default(0) @db.UnsignedInt
   createdAt DateTime  @default(now())
   authId    Int       @unique @db.UnsignedInt
-  user      auth      @relation(fields: [authId], references: [auth_id])
+  user      auth      @relation(fields: [authId], references: [auth_id], onDelete: Cascade)
 
 }
 

+ 115 - 0
src/admin/admin.controller.ts

@@ -0,0 +1,115 @@
+import {
+  BadRequestException,
+  Body,
+  Controller,
+  Delete,
+  Get,
+  Patch,
+  Post,
+  Put,
+  Query,
+  Req,
+  UseGuards,
+} from '@nestjs/common'
+import { AdminService } from './admin.service'
+import { AuthGuard } from '@nestjs/passport'
+import UserInfoDto from './dto/userinfo.dto'
+
+@Controller('admin')
+@UseGuards(AuthGuard('jwt'))
+export class AdminController {
+  constructor(private readonly adminService: AdminService) {}
+  @Get('getuserlist')
+  async getuserlist(@Query('') Query, @Req() req) {
+    const { page = 1, limit = 10 } = Query
+    const isSuper = await this.adminService.verifyPermissions(req.user)
+    if (isSuper) {
+      return await this.adminService.getuserlist(+page, +limit)
+    } else {
+      throw new BadRequestException('权限不足')
+    }
+  }
+  @Patch('updateUserInfo')
+  async updateUserInfo(@Body() dto: UserInfoDto, @Req() req) {
+    const isSuper = await this.adminService.verifyPermissions(req.user)
+    if (isSuper) {
+      return await this.adminService.updateUserInfo(dto)
+    } else {
+      throw new BadRequestException('权限不足')
+    }
+  }
+  @Post('addUser')
+  async addUser(@Body() dto: UserInfoDto, @Req() req) {
+    const isSuper = await this.adminService.verifyPermissions(req.user)
+    if (isSuper) {
+      return await this.adminService.addUser(dto)
+    } else {
+      throw new BadRequestException('权限不足')
+    }
+  }
+  @Delete('deleteUser')
+  async deleteUser(@Query('') Query, @Req() req) {
+    const { authId } = Query
+    const isSuper = await this.adminService.verifyPermissions(req.user)
+    if (isSuper) {
+      return await this.adminService.deleteUser(authId)
+    } else {
+      throw new BadRequestException('权限不足')
+    }
+  }
+  //searchUser
+  @Get('searchUser')
+  async searchUser(@Query('') Query, @Req() req) {
+    const { page = 1, limit = 10, username } = Query
+    const isSuper = await this.adminService.verifyPermissions(req.user)
+    if (isSuper) {
+      return await this.adminService.searchUser(username, +page, +limit)
+    } else {
+      throw new BadRequestException('权限不足')
+    }
+  }
+  //getPostList
+  @Get('getPostList')
+  async getPostList(@Query('') Query, @Req() req) {
+    const { page = 1, limit = 10 } = Query
+    const isSuper = await this.adminService.verifyPermissions(req.user)
+    if (isSuper) {
+      return await this.adminService.getPostList(+page, +limit)
+    } else {
+      throw new BadRequestException('权限不足')
+    }
+  }
+  //searchPost
+  @Get('searchPost')
+  async searchPost(@Query('') Query, @Req() req) {
+    const { page = 1, limit = 10, search } = Query
+    const isSuper = await this.adminService.verifyPermissions(req.user)
+    if (isSuper) {
+      return await this.adminService.searchPost(search, +page, +limit)
+    } else {
+      throw new BadRequestException('权限不足')
+    }
+  }
+  //getCommentList
+  @Get('getCommentList')
+  async getCommentList(@Query('') Query, @Req() req) {
+    const { page = 1, limit = 10 } = Query
+    const isSuper = await this.adminService.verifyPermissions(req.user)
+    if (isSuper) {
+      return await this.adminService.getCommentList(+page, +limit)
+    } else {
+      throw new BadRequestException('权限不足')
+    }
+  }
+  //searchComment
+  @Get('searchComment')
+  async searchComment(@Query('') Query, @Req() req) {
+    const { page = 1, limit = 10, search } = Query
+    const isSuper = await this.adminService.verifyPermissions(req.user)
+    if (isSuper) {
+      return await this.adminService.searchComment(search, +page, +limit)
+    } else {
+      throw new BadRequestException('权限不足')
+    }
+  }
+}

+ 10 - 0
src/admin/admin.module.ts

@@ -0,0 +1,10 @@
+import { Module } from '@nestjs/common'
+import { AdminService } from './admin.service'
+import { AdminController } from './admin.controller'
+
+@Module({
+  controllers: [AdminController],
+  providers: [AdminService],
+  exports: [AdminService],
+})
+export class AdminModule {}

+ 227 - 0
src/admin/admin.service.ts

@@ -0,0 +1,227 @@
+import { AuthService } from '@/auth/auth.service'
+import { PrismaService } from '@/prisma/prisma.service'
+import { Injectable } from '@nestjs/common'
+import UserInfoDto from './dto/userinfo.dto'
+import { hash } from 'argon2'
+
+@Injectable()
+export class AdminService {
+  constructor(private prisma: PrismaService, private auth: AuthService) {}
+  async getuserlist(page: number = 1, limit: number = 10) {
+    const data = await this.prisma.userinfo.findMany({
+      skip: (page - 1) * limit,
+      take: limit,
+      include: {
+        user: true,
+      },
+    })
+    const total = await this.prisma.userinfo.count()
+    const totalPage = Math.ceil(total / limit)
+    data.forEach((item) => {
+      delete item.user.password
+      delete item.user.auth_id
+      delete item.id
+      delete item.level
+    })
+    const res = data.map((item) => {
+      const { username, email, jurisdiction } = item.user
+      delete item.user
+      return { username, email, jurisdiction, ...item }
+    })
+    return { cod: 200, msg: '获取成功', totalPage, data: res }
+  }
+  //修改用户信息
+  async updateUserInfo(dto: UserInfoDto) {
+    dto.exp = Number(dto.exp)
+    dto.mapleCoin = Number(dto.mapleCoin)
+    const { authId, username, email, jurisdiction, paw, ...data } = dto
+    await this.prisma.auth.update({
+      where: { auth_id: authId },
+      data: {
+        username: username,
+        email: email,
+        jurisdiction: this.PermissionsTonumber(jurisdiction),
+      },
+    })
+    await this.prisma.userinfo.update({
+      where: { authId },
+      data,
+    })
+    if (paw) {
+      await this.prisma.auth.update({
+        where: { auth_id: authId },
+        data: {
+          password: await hash(paw),
+        },
+      })
+    }
+
+    return { cod: 200, msg: '修改成功' }
+  }
+  //验证权限
+  async verifyPermissions(id: number) {
+    const { msg } = await this.auth.checkPermissions(id)
+    return msg === '超级管理员'
+  }
+  //权限转换
+  private PermissionsTonumber(permissions: string) {
+    switch (permissions) {
+      case '普通用户':
+        return 0
+      case '管理员':
+        return 1
+      case '超级管理员':
+        return 2
+      case '禁封用户':
+        return 3
+      default:
+        return 0
+    }
+  }
+  //添加用户
+  async addUser(dto: UserInfoDto) {
+    const { username, email, jurisdiction, paw, authId, ...data } = dto
+    if (data.exp) {
+      data.exp = Number(data.exp)
+    } else {
+      data.exp = 0
+    }
+    if (data.mapleCoin) {
+      data.mapleCoin = Number(data.mapleCoin)
+    } else {
+      data.mapleCoin = 0
+    }
+    const auth = await this.prisma.auth.create({
+      data: {
+        username: username,
+        email: email,
+        jurisdiction: this.PermissionsTonumber(jurisdiction),
+        password: await hash(paw),
+        user: {
+          create: {
+            ...data,
+            level: 0,
+            avatar: '',
+          },
+        },
+      },
+    })
+    auth.auth_id
+    return { cod: 200, msg: '添加成功' }
+  }
+  //删除用户
+  async deleteUser(authId: number) {
+    await this.prisma.auth.delete({
+      where: { auth_id: +authId },
+    })
+    return { cod: 200, msg: '删除成功' }
+  }
+  //搜索用户
+  async searchUser(name: string, page: number = 1, limit: number = 10) {
+    //根据用户名和昵称搜索
+    const data = await this.prisma.userinfo.findMany({
+      skip: (page - 1) * limit,
+      take: limit,
+      where: {
+        OR: [{ user: { username: { contains: name } } }, { nickname: { contains: name } }],
+      },
+      include: {
+        user: true,
+      },
+    })
+    const total = await this.prisma.userinfo.count()
+    const totalPage = Math.ceil(total / limit)
+    data.forEach((item) => {
+      delete item.user.password
+      delete item.user.auth_id
+      delete item.id
+      delete item.level
+    })
+    const res = data.map((item) => {
+      const { username, email, jurisdiction } = item.user
+      delete item.user
+      return { username, email, jurisdiction, ...item }
+    })
+    return { cod: 200, msg: '获取成功', totalPage, data: res }
+  }
+  //获取帖子列表
+  async getPostList(page: number = 1, limit: number = 10) {
+    const data = await this.prisma.post.findMany({
+      skip: (page - 1) * limit,
+      take: limit,
+      include: {
+        author: true,
+        plate: true,
+      },
+    })
+    const total = await this.prisma.post.count()
+    const totalPage = Math.ceil(total / limit)
+    const res = data.map((item) => {
+      return { ...item, author: item.author.username, plate: item.plate.name }
+    })
+    return { cod: 200, msg: '获取成功', totalPage, data: res }
+  }
+  //搜索帖子
+  async searchPost(name: string, page: number = 1, limit: number = 10) {
+    const data = await this.prisma.post.findMany({
+      skip: (page - 1) * limit,
+      take: limit,
+      where: {
+        OR: [{ title: { contains: name } }, { content: { contains: name } }],
+      },
+      include: {
+        author: true,
+        plate: true,
+      },
+    })
+    const total = await this.prisma.post.count({
+      where: {
+        OR: [{ title: { contains: name } }, { content: { contains: name } }],
+      },
+    })
+    const totalPage = Math.ceil(total / limit)
+    const res = data.map((item) => {
+      return { ...item, author: item.author.username, plate: item.plate.name }
+    })
+    return { cod: 200, msg: '获取成功', totalPage, data: res }
+  }
+  //获取评论
+  async getCommentList(page: number = 1, limit: number = 10) {
+    const data = await this.prisma.comment.findMany({
+      skip: (page - 1) * limit,
+      take: limit,
+      include: {
+        post: true,
+        author: true,
+      },
+    })
+    const total = await this.prisma.comment.count()
+    const totalPage = Math.ceil(total / limit)
+    const res = data.map((item) => {
+      return { id: item.id, comment: item.content, postTitle: item.post.title, username: item.author.username }
+    })
+    return { cod: 200, msg: '获取成功', totalPage, data: res }
+  }
+  //搜索评论
+  async searchComment(name: string, page: number = 1, limit: number = 10) {
+    const data = await this.prisma.comment.findMany({
+      skip: (page - 1) * limit,
+      take: limit,
+      where: {
+        OR: [
+          { post: { title: { contains: name } } },
+          { author: { username: { contains: name } }, content: { contains: name } },
+        ],
+      },
+      include: {
+        post: true,
+        author: true,
+      },
+    })
+    const totalPage = Math.ceil(data.length / limit)
+    const res = data.map((item) => {
+      return { id: item.id, comment: item.content, postTitle: item.post.title, username: item.author.username }
+    })
+    return { cod: 200, msg: '获取成功', totalPage, data: res }
+  }
+}

+ 16 - 0
src/admin/dto/userinfo.dto.ts

@@ -0,0 +1,16 @@
+import { IsNotEmpty, IsString } from 'class-validator'
+
+export default class UserInfoDto {
+  authId: number
+  paw: string
+  username: string
+  email: string
+  jurisdiction: string
+  avatar: string
+  nickname: string
+  github: string
+  QQ: string
+  signature: string
+  exp: number
+  mapleCoin: number
+}

+ 2 - 0
src/app.module.ts

@@ -9,6 +9,7 @@ import { PostModule } from './post/post.module';
 import { PlateModule } from './plate/plate.module';
 import { UploadModule } from './upload/upload.module';
 import { CommentModule } from './comment/comment.module';
+import { AdminModule } from './admin/admin.module';
 @Module({
   imports: [
     AuthModule,
@@ -23,6 +24,7 @@ import { CommentModule } from './comment/comment.module';
     PlateModule,
     UploadModule,
     CommentModule,
+    AdminModule,
   ],
   controllers: [],
   providers: [],

+ 9 - 1
src/post/post.controller.ts

@@ -5,10 +5,15 @@ import { Request } from 'express'
 import searchPostDto from './dto/search.post.dto'
 import { link } from 'fs'
 import { CodService } from '@/cod/cod.service'
+import { AdminService } from '@/admin/admin.service'
 
 @Controller('post')
 export class PostController {
-  constructor(private readonly postService: PostService, private readonly codService: CodService) {}
+  constructor(
+    private readonly postService: PostService,
+    private readonly codService: CodService,
+    private readonly adminService: AdminService,
+  ) {}
   @Get('platelist')
   async getpostlist(@Query() { plateid, page = 1, limit = 10, isTop = false }) {
     return await this.postService.getpostlist(+plateid, +page, +limit, Boolean(isTop))
@@ -21,6 +26,9 @@ export class PostController {
   @Post()
   @UseGuards(AuthGuard('jwt'))
   async post(@Req() req: Request, @Headers('code') code: string, @Body() { title, content, plateid }) {
+    if (this.adminService.verifyPermissions(req.user as number)) {
+      return await this.postService.post(req.user as number, +plateid, { title, content })
+    }
     const rescod = await this.codService.verifyCod(req.ip, code)
     if (!rescod.status) {
       return rescod

+ 2 - 1
src/post/post.module.ts

@@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'
 import { PostService } from './post.service'
 import { PostController } from './post.controller'
 import { UserinfoService } from '@/userinfo/userinfo.service'
+import { AdminService } from '@/admin/admin.service'
 
 @Module({
-  providers: [PostService, UserinfoService],
+  providers: [PostService, UserinfoService, AdminService],
   controllers: [PostController],
 })
 export class PostModule {}

+ 4 - 3
src/post/post.service.ts

@@ -32,7 +32,6 @@ export class PostService {
   async updated(userId: number, postid: number, { title, content, plateId }) {
     const post = (await this.getpost(postid)) as any
     if (post.cod !== 400) {
-      console.log(userId)
       const Permissions = (await this.auth.checkPermissions(userId)) as any
       if (userId === post.author.auth_id || Permissions.msg === '管理员' || Permissions.msg === '超级管理员') {
         const res = await this.prisma.post.update({
@@ -43,9 +42,11 @@ export class PostService {
             title,
             content,
             plateId,
+            updatedAt: new Date(),
           },
           select: { id: true },
         })
+
         return { code: 200, message: '修改成功', data: res }
       } else {
         return { code: 400, message: '没有权限' }
@@ -105,7 +106,7 @@ export class PostService {
           title: true,
           content: true,
           authorId: true,
-          updatedAt: true,
+          updatedTime: true,
           isTop: true,
           views: true,
         },
@@ -125,7 +126,7 @@ export class PostService {
           title: true,
           content: true,
           authorId: true,
-          updatedAt: true,
+          updatedTime: true,
         },
       })
       const total = await this.prisma.post.count({