Skip to content

Commit

Permalink
feat: 完善北大课程相关的内容
Browse files Browse the repository at this point in the history
  • Loading branch information
luch1994 committed Aug 26, 2024
1 parent 54870b5 commit 2b755e1
Show file tree
Hide file tree
Showing 91 changed files with 1,663 additions and 2,369 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ node_modules
dist

package-lock.json
yarn.lock

# local env files
.env.local
Expand All @@ -25,6 +26,8 @@ pnpm-debug.log*
*.sw?

.history

exportfile
components.d.ts

# 默认的上传文件夹
Expand Down
3 changes: 3 additions & 0 deletions nginx/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ http {
proxy_pass http://127.0.0.1:3000;
}

location /exportfile {
proxy_pass http://127.0.0.1:3000;
}
# 静态文件的默认存储文件夹
# 文件夹的配置在 server/src/modules/file/config/index.ts SERVER_LOCAL_CONFIG.FILE_KEY_PREFIX
location /userUpload {
Expand Down
5 changes: 0 additions & 5 deletions package.json

This file was deleted.

16 changes: 11 additions & 5 deletions server/.env
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
XIAOJU_SURVEY_MONGO_DB_NAME=xiaojuSurvey
XIAOJU_SURVEY_MONGO_URL=mongodb://localhost:27017
XIAOJU_SURVEY_MONGO_AUTH_SOURCE=admin
XIAOJU_SURVEY_MONGO_DB_NAME= # xiaojuSurvey
XIAOJU_SURVEY_MONGO_URL= # mongodb://localhost:27017 # 建议设置强密码
XIAOJU_SURVEY_MONGO_AUTH_SOURCE= # admin

XIAOJU_SURVEY_REDIS_HOST=
XIAOJU_SURVEY_REDIS_PORT=
XIAOJU_SURVEY_REDIS_USERNAME=
XIAOJU_SURVEY_REDIS_PASSWORD=
XIAOJU_SURVEY_REDIS_DB=

XIAOJU_SURVEY_RESPONSE_AES_ENCRYPT_SECRET_KEY=dataAesEncryptSecretKey

XIAOJU_SURVEY_RESPONSE_AES_ENCRYPT_SECRET_KEY= # dataAesEncryptSecretKey
XIAOJU_SURVEY_HTTP_DATA_ENCRYPT_TYPE=rsa

XIAOJU_SURVEY_JWT_SECRET=xiaojuSurveyJwtSecret
XIAOJU_SURVEY_JWT_EXPIRES_IN=8h

XIAOJU_SURVEY_LOGGER_FILENAME=./logs/app.log
XIAOJU_SURVEY_LOGGER_FILENAME=./logs/app.log
8 changes: 5 additions & 3 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
"@nestjs/swagger": "^7.3.0",
"@nestjs/typeorm": "^10.0.1",
"ali-oss": "^6.20.0",
"async-mutex": "^0.5.0",
"cheerio": "^1.0.0-rc.12",
"cheerio": "1.0.0-rc.12",
"crypto-js": "^4.2.0",
"dotenv": "^16.3.2",
"fs-extra": "^11.2.0",
"ioredis": "^5.4.1",
"joi": "^17.11.0",
"jsonwebtoken": "^9.0.2",
"lodash": "^4.17.21",
Expand All @@ -40,10 +40,11 @@
"moment": "^2.30.1",
"mongodb": "^5.9.2",
"nanoid": "^3.3.7",
"node-cron": "^3.0.3",
"node-fetch": "^2.7.0",
"node-forge": "^1.3.1",
"node-xlsx": "^0.24.0",
"qiniu": "^7.11.1",
"redlock": "^5.0.0-beta.2",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
"svg-captcha": "^1.4.0",
Expand Down Expand Up @@ -72,6 +73,7 @@
"jest": "^29.5.0",
"mongodb-memory-server": "^9.1.4",
"prettier": "^3.0.0",
"redis-memory-server": "^0.11.0",
"source-map-support": "^0.5.21",
"supertest": "^6.3.3",
"ts-jest": "^29.1.0",
Expand Down
13 changes: 11 additions & 2 deletions server/scripts/run-local.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { MongoMemoryServer } from 'mongodb-memory-server';
import { spawn } from 'child_process';
import { RedisMemoryServer } from 'redis-memory-server';

async function startServerAndRunScript() {
// 启动 MongoDB 内存服务器
Expand All @@ -8,12 +9,19 @@ async function startServerAndRunScript() {

console.log('MongoDB Memory Server started:', mongoUri);

const redisServer = new RedisMemoryServer();
const redisHost = await redisServer.getHost();
const redisPort = await redisServer.getPort();

// 通过 spawn 运行另一个脚本,并传递 MongoDB 连接 URL 作为环境变量
const tsnode = spawn(
'cross-env',
[
`XIAOJU_SURVEY_MONGO_URL=${mongoUri}`,
`XIAOJU_SURVEY_REDIS_HOST=${redisHost}`,
`XIAOJU_SURVEY_REDIS_PORT=${redisPort}`,
'NODE_ENV=development',
'SERVER_ENV=local',
'npm',
'run',
'start:dev',
Expand All @@ -31,9 +39,10 @@ async function startServerAndRunScript() {
console.error(data);
});

tsnode.on('close', (code) => {
tsnode.on('close', async (code) => {
console.log(`Nodemon process exited with code ${code}`);
mongod.stop(); // 停止 MongoDB 内存服务器
await mongod.stop(); // 停止 MongoDB 内存服务器
await redisServer.stop();
});
}

Expand Down
10 changes: 6 additions & 4 deletions server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ import { LoggerProvider } from './logger/logger.provider';
import { PluginManagerProvider } from './securityPlugin/pluginManager.provider';
import { LogRequestMiddleware } from './middlewares/logRequest.middleware';
import { XiaojuSurveyPluginManager } from './securityPlugin/pluginManager';
import { Logger } from './logger';
import { SurveyDownload } from './models/surveyDownload.entity';
import { XiaojuSurveyLogger } from './logger';
import { DownloadTask } from './models/downloadTask.entity';
import { Session } from './models/session.entity';

@Module({
imports: [
Expand Down Expand Up @@ -82,7 +83,8 @@ import { SurveyDownload } from './models/surveyDownload.entity';
Workspace,
WorkspaceMember,
Collaborator,
SurveyDownload,
DownloadTask,
Session,
],
};
},
Expand Down Expand Up @@ -130,7 +132,7 @@ export class AppModule {
),
new SurveyUtilPlugin(),
);
Logger.init({
XiaojuSurveyLogger.init({
filename: this.configService.get<string>('XIAOJU_SURVEY_LOGGER_FILENAME'),
});
}
Expand Down
1 change: 1 addition & 0 deletions server/src/enums/exceptionCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum EXCEPTION_CODE {
SURVEY_TYPE_ERROR = 3003, // 问卷类型错误
SURVEY_NOT_FOUND = 3004, // 问卷不存在
SURVEY_CONTENT_NOT_ALLOW = 3005, // 存在禁用内容
SURVEY_SAVE_CONFLICT = 3006, // 问卷冲突
CAPTCHA_INCORRECT = 4001, // 验证码不正确
WHITELIST_ERROR = 4002, // 白名单校验错误

Expand Down
2 changes: 2 additions & 0 deletions server/src/enums/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export enum RECORD_STATUS {
REMOVED = 'removed', // 删除
FORCE_REMOVED = 'forceRemoved', // 从回收站删除
COMOPUTETING = 'computing', // 计算中
FINISHED = 'finished', // 已完成
ERROR = 'error', // 错误
}

// 历史类型
Expand Down
94 changes: 94 additions & 0 deletions server/src/guards/session.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { get } from 'lodash';
import { NoPermissionException } from 'src/exceptions/noPermissionException';
import { SurveyNotFoundException } from 'src/exceptions/surveyNotFoundException';
import { SessionService } from 'src/modules/survey/services/session.service';
import { SurveyMetaService } from 'src/modules/survey/services/surveyMeta.service';
import { WorkspaceMemberService } from 'src/modules/workspace/services/workspaceMember.service';
import { CollaboratorService } from 'src/modules/survey/services/collaborator.service';

@Injectable()
export class SessionGuard implements CanActivate {
constructor(
private reflector: Reflector,
private readonly sessionService: SessionService,
private readonly surveyMetaService: SurveyMetaService,
private readonly workspaceMemberService: WorkspaceMemberService,
private readonly collaboratorService: CollaboratorService,
) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const user = request.user;
const sessionIdKey = this.reflector.get<string>(
'sessionId',
context.getHandler(),
);

const sessionId = get(request, sessionIdKey);

if (!sessionId) {
throw new NoPermissionException('没有权限');
}

const saveSession = await this.sessionService.findOne(sessionId);

request.saveSession = saveSession;

const surveyId = saveSession.surveyId;

const surveyMeta = await this.surveyMetaService.getSurveyById({ surveyId });

if (!surveyMeta) {
throw new SurveyNotFoundException('问卷不存在');
}

request.surveyMeta = surveyMeta;

// 兼容老的问卷没有ownerId
if (
surveyMeta.ownerId === user._id.toString() ||
surveyMeta.owner === user.username
) {
// 问卷的owner,可以访问和操作问卷
return true;
}

if (surveyMeta.workspaceId) {
const memberInfo = await this.workspaceMemberService.findOne({
workspaceId: surveyMeta.workspaceId,
userId: user._id.toString(),
});
if (!memberInfo) {
throw new NoPermissionException('没有权限');
}
return true;
}

const permissions = this.reflector.get<string[]>(
'surveyPermission',
context.getHandler(),
);

if (!Array.isArray(permissions) || permissions.length === 0) {
throw new NoPermissionException('没有权限');
}

const info = await this.collaboratorService.getCollaborator({
surveyId,
userId: user._id.toString(),
});

if (!info) {
throw new NoPermissionException('没有权限');
}
request.collaborator = info;
if (
permissions.some((permission) => info.permissions.includes(permission))
) {
return true;
}
throw new NoPermissionException('没有权限');
}
}
1 change: 0 additions & 1 deletion server/src/guards/survey.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Reflector } from '@nestjs/core';
import { get } from 'lodash';

import { WorkspaceMemberService } from 'src/modules/workspace/services/workspaceMember.service';

import { CollaboratorService } from 'src/modules/survey/services/collaborator.service';
import { SurveyMetaService } from 'src/modules/survey/services/surveyMeta.service';
import { SurveyNotFoundException } from 'src/exceptions/surveyNotFoundException';
Expand Down
1 change: 0 additions & 1 deletion server/src/interfaces/survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ export interface DataItem {
rangeConfig?: any;
starStyle?: string;
innerType?: string;
deleteRecover?: boolean;
quotaNoDisplay?: boolean;
}

Expand Down
25 changes: 14 additions & 11 deletions server/src/logger/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import * as log4js from 'log4js';
import moment from 'moment';
import { Request } from 'express';
import { Injectable, Scope } from '@nestjs/common';
const log4jsLogger = log4js.getLogger();

export class Logger {
@Injectable({ scope: Scope.REQUEST })
export class XiaojuSurveyLogger {
private static inited = false;

constructor() {}
private traceId: string;

static init(config: { filename: string }) {
if (this.inited) {
if (XiaojuSurveyLogger.inited) {
return;
}
log4js.configure({
Expand All @@ -30,25 +30,28 @@ export class Logger {
default: { appenders: ['app'], level: 'trace' },
},
});
XiaojuSurveyLogger.inited = true;
}

_log(message, options: { dltag?: string; level: string; req?: Request }) {
_log(message, options: { dltag?: string; level: string }) {
const datetime = moment().format('YYYY-MM-DD HH:mm:ss.SSS');
const level = options?.level;
const dltag = options?.dltag ? `${options.dltag}||` : '';
const traceIdStr = options?.req?.['traceId']
? `traceid=${options?.req?.['traceId']}||`
: '';
const traceIdStr = this.traceId ? `traceid=${this.traceId}||` : '';
return log4jsLogger[level](
`[${datetime}][${level.toUpperCase()}]${dltag}${traceIdStr}${message}`,
);
}

info(message, options?: { dltag?: string; req?: Request }) {
setTraceId(traceId: string) {
this.traceId = traceId;
}

info(message, options?: { dltag?: string }) {
return this._log(message, { ...options, level: 'info' });
}

error(message, options: { dltag?: string; req?: Request }) {
error(message, options?: { dltag?: string }) {
return this._log(message, { ...options, level: 'error' });
}
}
6 changes: 3 additions & 3 deletions server/src/logger/logger.provider.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Provider } from '@nestjs/common';

import { Logger } from './index';
import { XiaojuSurveyLogger } from './index';

export const LoggerProvider: Provider = {
provide: Logger,
useClass: Logger,
provide: XiaojuSurveyLogger,
useClass: XiaojuSurveyLogger,
};
4 changes: 2 additions & 2 deletions server/src/logger/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ const getCountStr = () => {

export const genTraceId = ({ ip }) => {
// ip转16位 + 当前时间戳(毫秒级)+自增序列(1000开始自增到9000)+ 当前进程id的后5位
ip = ip.replace('::ffff:', '');
ip = ip.replace('::ffff:', '').replace('::1', '');
let ipArr;
if (ip.indexOf(':') > 0) {
if (ip.indexOf(':') >= 0) {
ipArr = ip.split(':').map((segment) => {
// 将IPv6每个段转为16位,并补0到长度为4
return parseInt(segment, 16).toString(16).padStart(4, '0');
Expand Down
Loading

0 comments on commit 2b755e1

Please sign in to comment.