Skip to content

Commit

Permalink
【Feature】:北大实践课作业 (#424)
Browse files Browse the repository at this point in the history
* 【北大开源实践】增加数据导出功能 (#294)

* feat:添加了一个文件数据导出的功能和相应前端页面

* fix lint

* fix conflict

---------

Co-authored-by: dayou <[email protected]>

* fix: components.d.ts文件ignore

* feat: Update README_EN.md

* feat: Update README.md

* feat:新增预览功能 (#257)

* feat:问卷预览功能
* feat:修复样式问题

* fix: 优化预览展示

* refactor: 重构vue3组合式API写法 (#265)

* feat: 抽离题型枚举 (#272)

* feat: 抽离题型枚举

* fix: 投放的链接加时间戳去掉ifream缓存

* feat: serve端的node engines

* feat: 权限接口请求优化以及修复其他问题 (#290)

* feat: c端路由改造 (#296)

* 【北大开源实践】增加数据导出功能 (#294)

* feat:添加了一个文件数据导出的功能和相应前端页面

* fix lint

* fix conflict

---------

Co-authored-by: dayou <[email protected]>

* fix: 删除components.d.ts文件

* 【北大开源实践】- 问卷断点续答 - 前端 (#282)

* feat:增加断点续答功能

* feat:增加断点续答功能

* fix: 同步代码并且解决冲突

---------

Co-authored-by: dayou <[email protected]>

* fix: 删除components.d.ts文件最终

* 【北大开源实践】-选项限制 (#284)

* format: 代码格式化 (#160)

* feat: 选项限制

* fix: 同步代码并解决冲突

* fix conflict

* fix conflict

* fix lint

* fix server lint

---------

Co-authored-by: dayou <[email protected]>
Co-authored-by: XiaoYuan <[email protected]>

* feat: 登录失效检测 & 协作冲突检测 (#287)

Co-authored-by: Liuxinyi <[email protected]>
Co-authored-by: dayou <[email protected]>

* fix: peking分支同步develop并解决冲突

* fix: 修正颜色不统一 (#338)

* fix: 修正颜色不统一

* fix: 删除server下的lock文件

* 编辑冲突检测 (#351)

* perl: 选项配额优化

* fix: pinia改写

* feat: 完善北大课程相关的内容

* fix: 修复断点续答以及样式问题 (#420)

* feat: 修改readme

* [Feature]: 密码复杂度检测 (#407)

* feat: 密码复杂度检测

* chore: 改为服务端校验

* feat: 优化展示

* fix:修复编辑页在不同element版本下表现不一致问题 (#406)

* fix: 通过声明element最低版本来确定tab样式表现

* fix lint

* feat(选项设置扩展):选择类题型增加选项排列配置 (#403)

* build: add optimizeDeps packages

* feat(选项设置扩展):选择类题型增加选项排列配置

* feat(选项设置扩展): 验收问题修复

---------

Co-authored-by: jiangchunfu <[email protected]>

* fix: 删除多余内容

* feat: 优化登录窗口

* fix: 修复断点续答以及样式问题

fix: 修复选项引用验收bug

fix: 修复断点续答问题

fix: 修复断点续答

fix: ignore

fix: 修复投票题默认值

fix: 优化断点续答逻辑

fix: 选中图标适应高度

fix: 回退最大最小选择

fix: 修复断点续答

fix: 修复elswitch不更新问题

fix: 修复访问密码更新不生效问题

fix: 修复样式

fix: 修复多选题最大最小限制

fix: 优化断点续答问题

修复多选题命中最多选择后无法取消问题

fix: 修复服务端的富文本解析

fix:  lint

fix: min error

fix: 修复最少最多选择

fix: 修复投票问卷的最少最多选择

fix: 兼容断点续答情况下选项配额为0的情况

fix: 兼容断点续答情况下选项配额为0的情况

fix: 兼容单选题的断点续答下的选项配额

fix: 修复添加选项问题

fix: 前端提示服务的配额已满

fix: 更新填写的过程中配额减少情况

---------

Co-authored-by: sudoooooo <[email protected]>
Co-authored-by: Stahsf <[email protected]>
Co-authored-by: Jiangchunfu <[email protected]>
Co-authored-by: jiangchunfu <[email protected]>

* feat: 修改验收问题 (#421)

* fix lint

---------

Co-authored-by: Oseast <[email protected]>
Co-authored-by: sudoooooo <[email protected]>
Co-authored-by: chaorenluo <[email protected]>
Co-authored-by: Realabiha <[email protected]>
Co-authored-by: shiyiting763 <[email protected]>
Co-authored-by: yiyeah <[email protected]>
Co-authored-by: XiaoYuan <[email protected]>
Co-authored-by: Xinyi Liu <[email protected]>
Co-authored-by: Liuxinyi <[email protected]>
Co-authored-by: nil <[email protected]>
Co-authored-by: 王晓聪 <[email protected]>
Co-authored-by: taoshuang <[email protected]>
Co-authored-by: luch1994 <[email protected]>
Co-authored-by: Stahsf <[email protected]>
Co-authored-by: Jiangchunfu <[email protected]>
Co-authored-by: jiangchunfu <[email protected]>
Co-authored-by: luch <[email protected]>
  • Loading branch information
18 people authored Sep 12, 2024
1 parent 43001a1 commit b749cfa
Show file tree
Hide file tree
Showing 99 changed files with 2,924 additions and 485 deletions.
4 changes: 4 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,7 +26,10 @@ pnpm-debug.log*
*.sw?

.history

components.d.ts

# 默认的上传文件夹
userUpload
exportfile
yarn.lock
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
12 changes: 9 additions & 3 deletions server/.env
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
XIAOJU_SURVEY_MONGO_DB_NAME=xiaojuSurvey
XIAOJU_SURVEY_MONGO_URL=mongodb://localhost:27017
XIAOJU_SURVEY_MONGO_AUTH_SOURCE=admin
XIAOJU_SURVEY_MONGO_URL= # mongodb://127.0.0.1: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
Expand Down
5 changes: 4 additions & 1 deletion server/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
yarn.lock

# OS
.DS_Store
Expand All @@ -37,4 +38,6 @@ lerna-debug.log*
!.vscode/launch.json
!.vscode/extensions.json

tmp
tmp
exportfile
userUpload
9 changes: 7 additions & 2 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
"@nestjs/swagger": "^7.3.0",
"@nestjs/typeorm": "^10.0.1",
"ali-oss": "^6.20.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 @@ -41,11 +42,14 @@
"nanoid": "^3.3.7",
"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",
"typeorm": "^0.3.19"
"typeorm": "^0.3.19",
"xss": "^1.0.15"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand All @@ -70,6 +74,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
8 changes: 6 additions & 2 deletions server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +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 { XiaojuSurveyLogger } from './logger';
import { DownloadTask } from './models/downloadTask.entity';
import { Session } from './models/session.entity';

@Module({
imports: [
Expand Down Expand Up @@ -81,6 +83,8 @@ import { Logger } from './logger';
Workspace,
WorkspaceMember,
Collaborator,
DownloadTask,
Session,
],
};
},
Expand Down Expand Up @@ -128,7 +132,7 @@ export class AppModule {
),
new SurveyUtilPlugin(),
);
Logger.init({
XiaojuSurveyLogger.init({
filename: this.configService.get<string>('XIAOJU_SURVEY_LOGGER_FILENAME'),
});
}
Expand Down
21 changes: 21 additions & 0 deletions server/src/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const mongo = {
url: process.env.XIAOJU_SURVEY_MONGO_URL || 'mongodb://localhost:27017',
dbName: process.env.XIAOJU_SURVER_MONGO_DBNAME || 'xiaojuSurvey',
};

const session = {
expireTime:
parseInt(process.env.XIAOJU_SURVEY_JWT_EXPIRES_IN) || 8 * 3600 * 1000,
};

const encrypt = {
type: process.env.XIAOJU_SURVEY_ENCRYPT_TYPE || 'aes',
aesCodelength: parseInt(process.env.XIAOJU_SURVEY_ENCRYPT_TYPE_LEN) || 10, //aes密钥长度
};

const jwt = {
secret: process.env.XIAOJU_SURVEY_JWT_SECRET || 'xiaojuSurveyJwtSecret',
expiresIn: process.env.XIAOJU_SURVEY_JWT_EXPIRES_IN || '8h',
};

export { mongo, session, encrypt, jwt };
1 change: 1 addition & 0 deletions server/src/enums/exceptionCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,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
3 changes: 3 additions & 0 deletions server/src/enums/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ export enum RECORD_STATUS {
PUBLISHED = 'published', // 发布
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
2 changes: 2 additions & 0 deletions server/src/interfaces/survey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export interface DataItem {
rangeConfig?: any;
starStyle?: string;
innerType?: string;
quotaNoDisplay?: boolean;
}

export interface Option {
Expand All @@ -69,6 +70,7 @@ export interface Option {
othersKey?: string;
placeholderDesc: string;
hash: string;
quota?: number;
}

export interface DataConf {
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,
};
Loading

0 comments on commit b749cfa

Please sign in to comment.