From 1e8b2be76516cf24a89147c1a15aa3830f6e126e Mon Sep 17 00:00:00 2001 From: Li1304553726 <1304553726@qq.com> Date: Sun, 23 Feb 2025 16:12:18 +0800 Subject: [PATCH 1/9] 2.23 --- .vscode/extensions.json | 5 +++ .vscode/settings.json | 7 +++ apps/web/src/app/main/component/People.tsx | 51 ++++++++++++++++++++++ apps/web/src/app/main/home/page.tsx | 39 +++++++++++++---- config/nginx/conf.d/web.conf | 9 ++-- package.json | 3 +- 6 files changed, 100 insertions(+), 14 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 apps/web/src/app/main/component/People.tsx diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..c76c14f --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "marscode.marscode-extension" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..137d9f4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "marscode.chatLanguage": "cn", + "marscode.codeCompletionPro": { + "enableCodeCompletionPro": true + }, + "marscode.enableInlineCommand": true +} \ No newline at end of file diff --git a/apps/web/src/app/main/component/People.tsx b/apps/web/src/app/main/component/People.tsx new file mode 100644 index 0000000..835b87e --- /dev/null +++ b/apps/web/src/app/main/component/People.tsx @@ -0,0 +1,51 @@ +import { useEffect } from 'react'; +import { api } from '@nice/client'; + +function People() { + // 使用 useQuery 钩子从 API 获取数据,限制查询结果数量为 10 + const { data } = api.staff.findMany.useQuery({ + take: 10, // 限制查询结果数量 + }); + // 当 data 发生变化时,打印数据到控制台 + useEffect(() => { + console.log(data); + }, [data]); + + return ( +
Username | +ID | +Showname | +Password | +Phone Number | +Order | +
---|---|---|---|---|---|
{i.username} | +{i.id} | +{i.showname} | +{i.password} | +{i.phoneNumber} | +{i.order} | +
A progressive Node.js framework for building efficient and scalable server-side applications.
+ + + +## Description + +[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. + +## Installation + +```bash +$ yarn install +``` + +## Running the app + +```bash +# development +$ yarn run start + +# watch mode +$ yarn run start:dev + +# production mode +$ yarn run start:prod +``` + +## Test + +```bash +# unit tests +$ yarn run test + +# e2e tests +$ yarn run test:e2e + +# test coverage +$ yarn run test:cov +``` + +## Support + +Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). + +## Stay in touch + +- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) +- Website - [https://nestjs.com](https://nestjs.com/) +- Twitter - [@nestframework](https://twitter.com/nestframework) + +## License + +Nest is [MIT licensed](LICENSE). diff --git a/apps/server/entrypoint.sh b/apps/server/entrypoint.sh new file mode 100755 index 0000000..9ea56fa --- /dev/null +++ b/apps/server/entrypoint.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +# # 从 DATABASE_URL 环境变量中提取主机名、端口和用户名 +# DB_HOST=$(echo $DATABASE_URL | cut -d '@' -f 2 | cut -d ':' -f 1) +# DB_PORT=$(echo $DATABASE_URL | cut -d ':' -f 4 | cut -d '/' -f 1) +# DB_USER=$(echo $DATABASE_URL | cut -d '/' -f 3 | cut -d ':' -f 1) + +# # 检查数据库是否就绪 +# until pg_isready -h $DB_HOST -p $DB_PORT -U $DB_USER; do +# echo "Database is unavailable - sleeping" +# sleep 1 +# done + +# echo "Database is up" + +# # 检查标记文件是否存在,如果不存在,则执行 prisma deploy 并创建标记文件 +# # if [ ! -f "/app/prisma-deployed" ]; then +# # pnpm prisma generate +# # pnpm prisma migrate deploy +# # touch /app/prisma-deployed +# # fi + +# # 启动主应用 +# exec node apps/server/dist/main + + +# 从 DATABASE_URL 环境变量中提取主机名、端口和用户名 +DB_HOST=$(echo $DATABASE_URL | cut -d '@' -f 2 | cut -d ':' -f 1) +DB_PORT=$(echo $DATABASE_URL | cut -d ':' -f 4 | cut -d '/' -f 1) +DB_USER=$(echo $DATABASE_URL | cut -d '/' -f 3 | cut -d ':' -f 1) + +# 检查数据库是否就绪 +until nc -z $DB_HOST $DB_PORT; do + echo "Database is unavailable - sleeping" + sleep 1 +done + +echo "Database is up" + +# 启动主应用 +exec node apps/server/dist/main \ No newline at end of file diff --git a/apps/server/nest-cli.json b/apps/server/nest-cli.json new file mode 100755 index 0000000..f9aa683 --- /dev/null +++ b/apps/server/nest-cli.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { + "deleteOutDir": true + } +} diff --git a/apps/server/package.json b/apps/server/package.json new file mode 100755 index 0000000..566bfb2 --- /dev/null +++ b/apps/server/package.json @@ -0,0 +1,113 @@ +{ + "name": "server", + "version": "0.0.1", + "description": "", + "author": "", + "private": true, + "license": "UNLICENSED", + "scripts": { + "build": "nest build", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "start": "nest start", + "dev": "nest start --watch", + "start:debug": "nest start --debug --watch", + "start:prod": "node dist/main", + "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", + "test": "jest", + "test:watch": "jest --watch", + "test:cov": "jest --coverage", + "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", + "test:e2e": "jest --config ./test/jest-e2e.json" + }, + "dependencies": { + "@nestjs/bullmq": "^10.2.0", + "@nestjs/common": "^10.3.10", + "@nestjs/config": "^3.2.3", + "@nestjs/core": "^10.0.0", + "@nestjs/jwt": "^10.2.0", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/platform-socket.io": "^10.3.10", + "@nestjs/schedule": "^4.1.0", + "@nestjs/websockets": "^10.3.10", + "@nice/common": "workspace:*", + "@nice/tus": "workspace:*", + "@trpc/server": "11.0.0-rc.456", + "argon2": "^0.41.1", + "axios": "^1.7.2", + "bullmq": "^5.12.0", + "cron": "^3.1.7", + "dayjs": "^1.11.13", + "dotenv": "^16.4.7", + "exceljs": "^4.4.0", + "fluent-ffmpeg": "^2.1.3", + "ioredis": "^5.4.1", + "lib0": "^0.2.97", + "lodash": "^4.17.21", + "lodash.debounce": "^4.0.8", + "mime-types": "^2.1.35", + "minio": "^8.0.1", + "mitt": "^3.0.1", + "nanoid": "^5.0.9", + "nanoid-cjs": "^0.0.7", + "pinyin-pro": "^3.26.0", + "reflect-metadata": "^0.2.0", + "rxjs": "^7.8.1", + "sharp": "^0.33.5", + "slugify": "^1.6.6", + "socket.io": "^4.7.5", + "superjson-cjs": "^2.2.3", + "transliteration": "^2.3.5", + "tus-js-client": "^4.1.0", + "uuid": "^10.0.0", + "ws": "^8.18.0", + "y-leveldb": "^0.1.2", + "yjs": "^13.6.20", + "zod": "^3.23.8" + }, + "devDependencies": { + "@nestjs/cli": "^10.0.0", + "@nestjs/schematics": "^10.0.0", + "@nestjs/testing": "^10.0.0", + "@types/exceljs": "^1.3.0", + "@types/express": "^4.17.21", + "@types/fluent-ffmpeg": "^2.1.27", + "@types/jest": "^29.5.2", + "@types/mime-types": "^2.1.4", + "@types/multer": "^1.4.12", + "@types/node": "^20.3.1", + "@types/supertest": "^6.0.0", + "@types/uuid": "^10.0.0", + "@types/ws": "^8.5.13", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "jest": "^29.5.0", + "prettier": "^3.0.0", + "source-map-support": "^0.5.21", + "supertest": "^6.3.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.3", + "ts-node": "^10.9.1", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.5.4" + }, + "jest": { + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], + "rootDir": "src", + "testRegex": ".*\\.spec\\.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "collectCoverageFrom": [ + "**/*.(t|j)s" + ], + "coverageDirectory": "../coverage", + "testEnvironment": "node" + } +} \ No newline at end of file diff --git a/apps/server/src/app.module.ts b/apps/server/src/app.module.ts new file mode 100755 index 0000000..3bc892f --- /dev/null +++ b/apps/server/src/app.module.ts @@ -0,0 +1,52 @@ +import { Module } from '@nestjs/common'; +import { TrpcModule } from './trpc/trpc.module'; +import { QueueModule } from './queue/queue.module'; +import { AuthModule } from './auth/auth.module'; +import { TaxonomyModule } from './models/taxonomy/taxonomy.module'; +import { TasksModule } from './tasks/tasks.module'; +import { ScheduleModule } from '@nestjs/schedule'; +import { InitModule } from './tasks/init/init.module'; +import { ReminderModule } from './tasks/reminder/reminder.module'; +import { JwtModule } from '@nestjs/jwt'; +import { env } from './env'; +import { ConfigModule } from '@nestjs/config'; +import { APP_FILTER } from '@nestjs/core'; +import { MinioModule } from './utils/minio/minio.module'; +import { WebSocketModule } from './socket/websocket.module'; +import { CollaborationModule } from './socket/collaboration/collaboration.module'; +import { ExceptionsFilter } from './filters/exceptions.filter'; +import { TransformModule } from './models/transform/transform.module'; +import { RealTimeModule } from './socket/realtime/realtime.module'; +import { UploadModule } from './upload/upload.module'; + +@Module({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, // 全局可用 + envFilePath: '.env' + }), + ScheduleModule.forRoot(), + JwtModule.register({ + global: true, + secret: env.JWT_SECRET + }), + WebSocketModule, + TrpcModule, + QueueModule, + AuthModule, + TaxonomyModule, + TasksModule, + InitModule, + ReminderModule, + TransformModule, + MinioModule, + CollaborationModule, + RealTimeModule, + UploadModule + ], + providers: [{ + provide: APP_FILTER, + useClass: ExceptionsFilter, + }], +}) +export class AppModule { } diff --git a/apps/server/src/auth/auth.controller.ts b/apps/server/src/auth/auth.controller.ts new file mode 100755 index 0000000..de67161 --- /dev/null +++ b/apps/server/src/auth/auth.controller.ts @@ -0,0 +1,112 @@ +import { + Controller, + Headers, + Post, + Body, + UseGuards, + Get, + Req, + HttpException, + HttpStatus, + BadRequestException, + InternalServerErrorException, + NotFoundException, + UnauthorizedException, + Logger, +} from '@nestjs/common'; +import { AuthService } from './auth.service'; +import { AuthSchema, JwtPayload } from '@nice/common'; +import { AuthGuard } from './auth.guard'; +import { UserProfileService } from './utils'; +import { z } from 'zod'; +import { FileValidationErrorType } from './types'; +@Controller('auth') +export class AuthController { + private logger = new Logger(AuthController.name); + constructor(private readonly authService: AuthService) {} + @Get('file') + async authFileRequset( + @Headers('x-original-uri') originalUri: string, + @Headers('x-real-ip') realIp: string, + @Headers('x-original-method') method: string, + @Headers('x-query-params') queryParams: string, + @Headers('host') host: string, + @Headers('authorization') authorization: string, + ) { + try { + const fileRequest = { + originalUri, + realIp, + method, + queryParams, + host, + authorization, + }; + + const authResult = + await this.authService.validateFileRequest(fileRequest); + if (!authResult.isValid) { + // 使用枚举类型进行错误处理 + switch (authResult.error) { + case FileValidationErrorType.INVALID_URI: + throw new BadRequestException(authResult.error); + case FileValidationErrorType.RESOURCE_NOT_FOUND: + throw new NotFoundException(authResult.error); + case FileValidationErrorType.AUTHORIZATION_REQUIRED: + case FileValidationErrorType.INVALID_TOKEN: + throw new UnauthorizedException(authResult.error); + default: + throw new InternalServerErrorException( + authResult.error || FileValidationErrorType.UNKNOWN_ERROR, + ); + } + } + return { + headers: { + 'X-User-Id': authResult.userId, + 'X-Resource-Type': authResult.resourceType, + }, + }; + } catch (error: any) { + this.logger.verbose( + `File request auth failed from ${realIp} reason:${error.message}`, + ); + throw error; + } + } + @UseGuards(AuthGuard) + @Get('user-profile') + async getUserProfile(@Req() request: Request) { + const payload: JwtPayload = (request as any).user; + const { staff } = await UserProfileService.instance.getUserProfileById( + payload.sub, + ); + return staff; + } + @Post('login') + async login(@Body() body: z.infer