feat: 修改导出和登录状态检测代码CR问题 (#431)
This commit is contained in:
parent
cdb8b6532a
commit
54a86e1501
@ -1,6 +1,6 @@
|
|||||||
XIAOJU_SURVEY_MONGO_DB_NAME=xiaojuSurvey
|
XIAOJU_SURVEY_MONGO_DB_NAME=xiaojuSurvey
|
||||||
XIAOJU_SURVEY_MONGO_URL= # mongodb://127.0.0.1:27017 # 建议设置强密码
|
XIAOJU_SURVEY_MONGO_URL=#mongodb://127.0.0.1:27017 # 建议设置强密码,放开注释不能有空格
|
||||||
XIAOJU_SURVEY_MONGO_AUTH_SOURCE= # admin
|
XIAOJU_SURVEY_MONGO_AUTH_SOURCE=admin
|
||||||
|
|
||||||
XIAOJU_SURVEY_REDIS_HOST=
|
XIAOJU_SURVEY_REDIS_HOST=
|
||||||
XIAOJU_SURVEY_REDIS_PORT=
|
XIAOJU_SURVEY_REDIS_PORT=
|
||||||
|
@ -39,8 +39,8 @@ import { Collaborator } from './models/collaborator.entity';
|
|||||||
import { LoggerProvider } from './logger/logger.provider';
|
import { LoggerProvider } from './logger/logger.provider';
|
||||||
import { PluginManagerProvider } from './securityPlugin/pluginManager.provider';
|
import { PluginManagerProvider } from './securityPlugin/pluginManager.provider';
|
||||||
import { LogRequestMiddleware } from './middlewares/logRequest.middleware';
|
import { LogRequestMiddleware } from './middlewares/logRequest.middleware';
|
||||||
import { XiaojuSurveyPluginManager } from './securityPlugin/pluginManager';
|
import { PluginManager } from './securityPlugin/pluginManager';
|
||||||
import { XiaojuSurveyLogger } from './logger';
|
import { Logger } from './logger';
|
||||||
import { DownloadTask } from './models/downloadTask.entity';
|
import { DownloadTask } from './models/downloadTask.entity';
|
||||||
import { Session } from './models/session.entity';
|
import { Session } from './models/session.entity';
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ import { Session } from './models/session.entity';
|
|||||||
export class AppModule {
|
export class AppModule {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
private readonly pluginManager: XiaojuSurveyPluginManager,
|
private readonly pluginManager: PluginManager,
|
||||||
) {}
|
) {}
|
||||||
configure(consumer: MiddlewareConsumer) {
|
configure(consumer: MiddlewareConsumer) {
|
||||||
consumer.apply(LogRequestMiddleware).forRoutes('*');
|
consumer.apply(LogRequestMiddleware).forRoutes('*');
|
||||||
@ -132,7 +132,7 @@ export class AppModule {
|
|||||||
),
|
),
|
||||||
new SurveyUtilPlugin(),
|
new SurveyUtilPlugin(),
|
||||||
);
|
);
|
||||||
XiaojuSurveyLogger.init({
|
Logger.init({
|
||||||
filename: this.configService.get<string>('XIAOJU_SURVEY_LOGGER_FILENAME'),
|
filename: this.configService.get<string>('XIAOJU_SURVEY_LOGGER_FILENAME'),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
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 };
|
|
68
server/src/guards/__test/session.guard.spec.ts
Normal file
68
server/src/guards/__test/session.guard.spec.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { ExecutionContext } from '@nestjs/common';
|
||||||
|
import { Reflector } from '@nestjs/core';
|
||||||
|
import { SessionService } from 'src/modules/survey/services/session.service';
|
||||||
|
import { SessionGuard } from '../session.guard';
|
||||||
|
import { NoPermissionException } from 'src/exceptions/noPermissionException';
|
||||||
|
|
||||||
|
describe('SessionGuard', () => {
|
||||||
|
let sessionGuard: SessionGuard;
|
||||||
|
let reflector: Reflector;
|
||||||
|
let sessionService: SessionService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
reflector = new Reflector();
|
||||||
|
sessionService = {
|
||||||
|
findOne: jest.fn(),
|
||||||
|
} as unknown as SessionService;
|
||||||
|
sessionGuard = new SessionGuard(reflector, sessionService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return true when sessionId exists and sessionService returns sessionInfo', async () => {
|
||||||
|
const mockSessionId = '12345';
|
||||||
|
const mockSessionInfo = { id: mockSessionId, name: 'test session' };
|
||||||
|
|
||||||
|
const context = {
|
||||||
|
switchToHttp: jest.fn().mockReturnThis(),
|
||||||
|
getRequest: jest.fn().mockReturnValue({
|
||||||
|
sessionId: mockSessionId,
|
||||||
|
}),
|
||||||
|
getHandler: jest.fn(),
|
||||||
|
} as unknown as ExecutionContext;
|
||||||
|
|
||||||
|
jest.spyOn(reflector, 'get').mockReturnValue('sessionId');
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(sessionService, 'findOne')
|
||||||
|
.mockResolvedValue(mockSessionInfo as any);
|
||||||
|
|
||||||
|
const result = await sessionGuard.canActivate(context);
|
||||||
|
|
||||||
|
const request = context.switchToHttp().getRequest();
|
||||||
|
|
||||||
|
expect(result).toBe(true);
|
||||||
|
expect(reflector.get).toHaveBeenCalledWith(
|
||||||
|
'sessionId',
|
||||||
|
context.getHandler(),
|
||||||
|
);
|
||||||
|
expect(sessionService.findOne).toHaveBeenCalledWith(mockSessionId);
|
||||||
|
expect(request.sessionInfo).toEqual(mockSessionInfo);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NoPermissionException when sessionId is missing', async () => {
|
||||||
|
const context = {
|
||||||
|
switchToHttp: jest.fn().mockReturnThis(),
|
||||||
|
getRequest: jest.fn().mockReturnValue({}),
|
||||||
|
getHandler: jest.fn(),
|
||||||
|
} as unknown as ExecutionContext;
|
||||||
|
|
||||||
|
jest.spyOn(reflector, 'get').mockReturnValue('sessionId');
|
||||||
|
|
||||||
|
await expect(sessionGuard.canActivate(context)).rejects.toThrow(
|
||||||
|
NoPermissionException,
|
||||||
|
);
|
||||||
|
expect(reflector.get).toHaveBeenCalledWith(
|
||||||
|
'sessionId',
|
||||||
|
context.getHandler(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -4,12 +4,12 @@ import { Injectable, Scope } from '@nestjs/common';
|
|||||||
const log4jsLogger = log4js.getLogger();
|
const log4jsLogger = log4js.getLogger();
|
||||||
|
|
||||||
@Injectable({ scope: Scope.REQUEST })
|
@Injectable({ scope: Scope.REQUEST })
|
||||||
export class XiaojuSurveyLogger {
|
export class Logger {
|
||||||
private static inited = false;
|
private static inited = false;
|
||||||
private traceId: string;
|
private traceId: string;
|
||||||
|
|
||||||
static init(config: { filename: string }) {
|
static init(config: { filename: string }) {
|
||||||
if (XiaojuSurveyLogger.inited) {
|
if (Logger.inited) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log4js.configure({
|
log4js.configure({
|
||||||
@ -30,7 +30,7 @@ export class XiaojuSurveyLogger {
|
|||||||
default: { appenders: ['app'], level: 'trace' },
|
default: { appenders: ['app'], level: 'trace' },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
XiaojuSurveyLogger.inited = true;
|
Logger.inited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_log(message, options: { dltag?: string; level: string }) {
|
_log(message, options: { dltag?: string; level: string }) {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Provider } from '@nestjs/common';
|
import { Provider } from '@nestjs/common';
|
||||||
|
|
||||||
import { XiaojuSurveyLogger } from './index';
|
import { Logger } from './index';
|
||||||
|
|
||||||
export const LoggerProvider: Provider = {
|
export const LoggerProvider: Provider = {
|
||||||
provide: XiaojuSurveyLogger,
|
provide: Logger,
|
||||||
useClass: XiaojuSurveyLogger,
|
useClass: Logger,
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
// logger.middleware.ts
|
|
||||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Request, Response, NextFunction } from 'express';
|
||||||
import { XiaojuSurveyLogger } from '../logger/index'; // 替换为你实际的logger路径
|
import { Logger } from '../logger/index'; // 替换为你实际的logger路径
|
||||||
import { genTraceId } from '../logger/util';
|
import { genTraceId } from '../logger/util';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LogRequestMiddleware implements NestMiddleware {
|
export class LogRequestMiddleware implements NestMiddleware {
|
||||||
constructor(private readonly logger: XiaojuSurveyLogger) {}
|
constructor(private readonly logger: Logger) {}
|
||||||
|
|
||||||
use(req: Request, res: Response, next: NextFunction) {
|
use(req: Request, res: Response, next: NextFunction) {
|
||||||
const { method, originalUrl, ip } = req;
|
const { method, originalUrl, ip } = req;
|
||||||
|
@ -19,7 +19,11 @@ export class DownloadTask extends BaseEntity {
|
|||||||
|
|
||||||
// 任务创建人
|
// 任务创建人
|
||||||
@Column()
|
@Column()
|
||||||
ownerId: string;
|
creatorId: string;
|
||||||
|
|
||||||
|
// 任务创建人
|
||||||
|
@Column()
|
||||||
|
creator: string;
|
||||||
|
|
||||||
// 文件名
|
// 文件名
|
||||||
@Column()
|
@Column()
|
||||||
|
@ -27,11 +27,11 @@ export class SurveyResponse extends BaseEntity {
|
|||||||
|
|
||||||
@BeforeInsert()
|
@BeforeInsert()
|
||||||
async onDataInsert() {
|
async onDataInsert() {
|
||||||
return await pluginManager.triggerHook('beforeResponseDataCreate', this);
|
return await pluginManager.triggerHook('encryptResponseData', this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterLoad()
|
@AfterLoad()
|
||||||
async onDataLoaded() {
|
async onDataLoaded() {
|
||||||
return await pluginManager.triggerHook('afterResponseDataReaded', this);
|
return await pluginManager.triggerHook('decryptResponseData', this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
import { Controller, Post, Body, HttpCode, Get, Query } from '@nestjs/common';
|
import {
|
||||||
|
Controller,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
HttpCode,
|
||||||
|
Get,
|
||||||
|
Query,
|
||||||
|
Request,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { UserService } from '../services/user.service';
|
import { UserService } from '../services/user.service';
|
||||||
import { CaptchaService } from '../services/captcha.service';
|
import { CaptchaService } from '../services/captcha.service';
|
||||||
@ -214,4 +222,28 @@ export class AuthController {
|
|||||||
data: 'Weak',
|
data: 'Weak',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('/verifyToken')
|
||||||
|
@HttpCode(200)
|
||||||
|
async verifyToken(@Request() req) {
|
||||||
|
const token = req.headers.authorization?.split(' ')[1];
|
||||||
|
if (!token) {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
data: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.authService.verifyToken(token);
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
data: true,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
data: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,17 +14,17 @@ export class FileService {
|
|||||||
configKey,
|
configKey,
|
||||||
file,
|
file,
|
||||||
pathPrefix,
|
pathPrefix,
|
||||||
keepOriginFilename,
|
filename,
|
||||||
}: {
|
}: {
|
||||||
configKey: string;
|
configKey: string;
|
||||||
file: Express.Multer.File;
|
file: Express.Multer.File;
|
||||||
pathPrefix: string;
|
pathPrefix: string;
|
||||||
keepOriginFilename?: boolean;
|
filename?: string;
|
||||||
}) {
|
}) {
|
||||||
const handler = this.getHandler(configKey);
|
const handler = this.getHandler(configKey);
|
||||||
const { key } = await handler.upload(file, {
|
const { key } = await handler.upload(file, {
|
||||||
pathPrefix,
|
pathPrefix,
|
||||||
keepOriginFilename,
|
filename,
|
||||||
});
|
});
|
||||||
const url = await handler.getUrl(key);
|
const url = await handler.getUrl(key);
|
||||||
return {
|
return {
|
||||||
|
@ -12,11 +12,11 @@ export class LocalHandler implements FileUploadHandler {
|
|||||||
|
|
||||||
async upload(
|
async upload(
|
||||||
file: Express.Multer.File,
|
file: Express.Multer.File,
|
||||||
options?: { pathPrefix?: string; keepOriginFilename?: boolean },
|
options?: { pathPrefix?: string; filename?: string },
|
||||||
): Promise<{ key: string }> {
|
): Promise<{ key: string }> {
|
||||||
let filename;
|
let filename;
|
||||||
if (options?.keepOriginFilename) {
|
if (options?.filename) {
|
||||||
filename = file.originalname;
|
filename = file.filename;
|
||||||
} else {
|
} else {
|
||||||
filename = await generateUniqueFilename(file.originalname);
|
filename = await generateUniqueFilename(file.originalname);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { CollaboratorController } from '../controllers/collaborator.controller';
|
import { CollaboratorController } from '../controllers/collaborator.controller';
|
||||||
import { CollaboratorService } from '../services/collaborator.service';
|
import { CollaboratorService } from '../services/collaborator.service';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { CreateCollaboratorDto } from '../dto/createCollaborator.dto';
|
import { CreateCollaboratorDto } from '../dto/createCollaborator.dto';
|
||||||
import { Collaborator } from 'src/models/collaborator.entity';
|
import { Collaborator } from 'src/models/collaborator.entity';
|
||||||
@ -25,7 +25,7 @@ jest.mock('src/guards/workspace.guard');
|
|||||||
describe('CollaboratorController', () => {
|
describe('CollaboratorController', () => {
|
||||||
let controller: CollaboratorController;
|
let controller: CollaboratorController;
|
||||||
let collaboratorService: CollaboratorService;
|
let collaboratorService: CollaboratorService;
|
||||||
let logger: XiaojuSurveyLogger;
|
let logger: Logger;
|
||||||
let userService: UserService;
|
let userService: UserService;
|
||||||
let surveyMetaService: SurveyMetaService;
|
let surveyMetaService: SurveyMetaService;
|
||||||
let workspaceMemberServie: WorkspaceMemberService;
|
let workspaceMemberServie: WorkspaceMemberService;
|
||||||
@ -50,7 +50,7 @@ describe('CollaboratorController', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: XiaojuSurveyLogger,
|
provide: Logger,
|
||||||
useValue: {
|
useValue: {
|
||||||
error: jest.fn(),
|
error: jest.fn(),
|
||||||
info: jest.fn(),
|
info: jest.fn(),
|
||||||
@ -84,7 +84,7 @@ describe('CollaboratorController', () => {
|
|||||||
|
|
||||||
controller = module.get<CollaboratorController>(CollaboratorController);
|
controller = module.get<CollaboratorController>(CollaboratorController);
|
||||||
collaboratorService = module.get<CollaboratorService>(CollaboratorService);
|
collaboratorService = module.get<CollaboratorService>(CollaboratorService);
|
||||||
logger = module.get<XiaojuSurveyLogger>(XiaojuSurveyLogger);
|
logger = module.get<Logger>(Logger);
|
||||||
userService = module.get<UserService>(UserService);
|
userService = module.get<UserService>(UserService);
|
||||||
surveyMetaService = module.get<SurveyMetaService>(SurveyMetaService);
|
surveyMetaService = module.get<SurveyMetaService>(SurveyMetaService);
|
||||||
workspaceMemberServie = module.get<WorkspaceMemberService>(
|
workspaceMemberServie = module.get<WorkspaceMemberService>(
|
||||||
|
@ -3,13 +3,13 @@ import { CollaboratorService } from '../services/collaborator.service';
|
|||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
import { Collaborator } from 'src/models/collaborator.entity';
|
import { Collaborator } from 'src/models/collaborator.entity';
|
||||||
import { MongoRepository } from 'typeorm';
|
import { MongoRepository } from 'typeorm';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { InsertManyResult, ObjectId } from 'mongodb';
|
import { InsertManyResult, ObjectId } from 'mongodb';
|
||||||
|
|
||||||
describe('CollaboratorService', () => {
|
describe('CollaboratorService', () => {
|
||||||
let service: CollaboratorService;
|
let service: CollaboratorService;
|
||||||
let repository: MongoRepository<Collaborator>;
|
let repository: MongoRepository<Collaborator>;
|
||||||
let logger: XiaojuSurveyLogger;
|
let logger: Logger;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
@ -20,7 +20,7 @@ describe('CollaboratorService', () => {
|
|||||||
useClass: MongoRepository,
|
useClass: MongoRepository,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: XiaojuSurveyLogger,
|
provide: Logger,
|
||||||
useValue: {
|
useValue: {
|
||||||
info: jest.fn(),
|
info: jest.fn(),
|
||||||
},
|
},
|
||||||
@ -32,7 +32,7 @@ describe('CollaboratorService', () => {
|
|||||||
repository = module.get<MongoRepository<Collaborator>>(
|
repository = module.get<MongoRepository<Collaborator>>(
|
||||||
getRepositoryToken(Collaborator),
|
getRepositoryToken(Collaborator),
|
||||||
);
|
);
|
||||||
logger = module.get<XiaojuSurveyLogger>(XiaojuSurveyLogger);
|
logger = module.get<Logger>(Logger);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('create', () => {
|
describe('create', () => {
|
||||||
|
@ -8,8 +8,8 @@ import { SurveyMetaService } from '../services/surveyMeta.service';
|
|||||||
import { ResponseSchemaService } from '../../surveyResponse/services/responseScheme.service';
|
import { ResponseSchemaService } from '../../surveyResponse/services/responseScheme.service';
|
||||||
|
|
||||||
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
||||||
import { XiaojuSurveyPluginManager } from 'src/securityPlugin/pluginManager';
|
import { PluginManager } from 'src/securityPlugin/pluginManager';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
|
|
||||||
import { UserService } from 'src/modules/auth/services/user.service';
|
import { UserService } from 'src/modules/auth/services/user.service';
|
||||||
import { ResponseSecurityPlugin } from 'src/securityPlugin/responseSecurityPlugin';
|
import { ResponseSecurityPlugin } from 'src/securityPlugin/responseSecurityPlugin';
|
||||||
@ -27,8 +27,8 @@ describe('DataStatisticController', () => {
|
|||||||
let controller: DataStatisticController;
|
let controller: DataStatisticController;
|
||||||
let dataStatisticService: DataStatisticService;
|
let dataStatisticService: DataStatisticService;
|
||||||
let responseSchemaService: ResponseSchemaService;
|
let responseSchemaService: ResponseSchemaService;
|
||||||
let pluginManager: XiaojuSurveyPluginManager;
|
let pluginManager: PluginManager;
|
||||||
let logger: XiaojuSurveyLogger;
|
let logger: Logger;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
@ -56,7 +56,7 @@ describe('DataStatisticController', () => {
|
|||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: XiaojuSurveyLogger,
|
provide: Logger,
|
||||||
useValue: {
|
useValue: {
|
||||||
error: jest.fn(),
|
error: jest.fn(),
|
||||||
},
|
},
|
||||||
@ -70,10 +70,8 @@ describe('DataStatisticController', () => {
|
|||||||
responseSchemaService = module.get<ResponseSchemaService>(
|
responseSchemaService = module.get<ResponseSchemaService>(
|
||||||
ResponseSchemaService,
|
ResponseSchemaService,
|
||||||
);
|
);
|
||||||
pluginManager = module.get<XiaojuSurveyPluginManager>(
|
pluginManager = module.get<PluginManager>(PluginManager);
|
||||||
XiaojuSurveyPluginManager,
|
logger = module.get<Logger>(Logger);
|
||||||
);
|
|
||||||
logger = module.get<XiaojuSurveyLogger>(XiaojuSurveyLogger);
|
|
||||||
|
|
||||||
pluginManager.registerPlugin(
|
pluginManager.registerPlugin(
|
||||||
new ResponseSecurityPlugin('dataAesEncryptSecretKey'),
|
new ResponseSecurityPlugin('dataAesEncryptSecretKey'),
|
||||||
@ -90,7 +88,7 @@ describe('DataStatisticController', () => {
|
|||||||
const mockRequest = {
|
const mockRequest = {
|
||||||
query: {
|
query: {
|
||||||
surveyId,
|
surveyId,
|
||||||
isDesensitive: false,
|
isMasked: false,
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
},
|
},
|
||||||
@ -131,12 +129,12 @@ describe('DataStatisticController', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return data table with isDesensitive', async () => {
|
it('should return data table with isMasked', async () => {
|
||||||
const surveyId = new ObjectId().toString();
|
const surveyId = new ObjectId().toString();
|
||||||
const mockRequest = {
|
const mockRequest = {
|
||||||
query: {
|
query: {
|
||||||
surveyId,
|
surveyId,
|
||||||
isDesensitive: true,
|
isMasked: true,
|
||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
},
|
},
|
||||||
|
@ -11,7 +11,7 @@ import { cloneDeep } from 'lodash';
|
|||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_STATUS } from 'src/enums';
|
||||||
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
||||||
import { XiaojuSurveyPluginManager } from 'src/securityPlugin/pluginManager';
|
import { PluginManager } from 'src/securityPlugin/pluginManager';
|
||||||
import { ResponseSecurityPlugin } from 'src/securityPlugin/responseSecurityPlugin';
|
import { ResponseSecurityPlugin } from 'src/securityPlugin/responseSecurityPlugin';
|
||||||
|
|
||||||
describe('DataStatisticService', () => {
|
describe('DataStatisticService', () => {
|
||||||
@ -34,9 +34,7 @@ describe('DataStatisticService', () => {
|
|||||||
surveyResponseRepository = module.get<MongoRepository<SurveyResponse>>(
|
surveyResponseRepository = module.get<MongoRepository<SurveyResponse>>(
|
||||||
getRepositoryToken(SurveyResponse),
|
getRepositoryToken(SurveyResponse),
|
||||||
);
|
);
|
||||||
const manager = module.get<XiaojuSurveyPluginManager>(
|
const manager = module.get<PluginManager>(PluginManager);
|
||||||
XiaojuSurveyPluginManager,
|
|
||||||
);
|
|
||||||
manager.registerPlugin(
|
manager.registerPlugin(
|
||||||
new ResponseSecurityPlugin('dataAesEncryptSecretKey'),
|
new ResponseSecurityPlugin('dataAesEncryptSecretKey'),
|
||||||
);
|
);
|
||||||
@ -204,7 +202,7 @@ describe('DataStatisticService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return desensitive table data', async () => {
|
it('should return desensitized table data', async () => {
|
||||||
const mockSchema = cloneDeep(mockSensitiveResponseSchema);
|
const mockSchema = cloneDeep(mockSensitiveResponseSchema);
|
||||||
const surveyResponseList: Array<SurveyResponse> = [
|
const surveyResponseList: Array<SurveyResponse> = [
|
||||||
{
|
{
|
||||||
|
259
server/src/modules/survey/__test/downloadTask.controller.spec.ts
Normal file
259
server/src/modules/survey/__test/downloadTask.controller.spec.ts
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { ObjectId } from 'mongodb';
|
||||||
|
import { DownloadTaskController } from '../controllers/downloadTask.controller';
|
||||||
|
import { ResponseSchemaService } from '../../surveyResponse/services/responseScheme.service';
|
||||||
|
import { AuthService } from 'src/modules/auth/services/auth.service';
|
||||||
|
import { DownloadTaskService } from '../services/downloadTask.service';
|
||||||
|
import { CollaboratorService } from '../services/collaborator.service';
|
||||||
|
import { SurveyMetaService } from '../services/surveyMeta.service';
|
||||||
|
import { WorkspaceMemberService } from 'src/modules/workspace/services/workspaceMember.service';
|
||||||
|
|
||||||
|
import { Logger } from 'src/logger';
|
||||||
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
|
import { NoPermissionException } from 'src/exceptions/noPermissionException';
|
||||||
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
|
|
||||||
|
import { Authentication } from 'src/guards/authentication.guard';
|
||||||
|
import { SurveyGuard } from 'src/guards/survey.guard';
|
||||||
|
|
||||||
|
describe('DownloadTaskController', () => {
|
||||||
|
let controller: DownloadTaskController;
|
||||||
|
let responseSchemaService: ResponseSchemaService;
|
||||||
|
let downloadTaskService: DownloadTaskService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [DownloadTaskController],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ResponseSchemaService,
|
||||||
|
useValue: {
|
||||||
|
getResponseSchemaByPageId: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: DownloadTaskService,
|
||||||
|
useValue: {
|
||||||
|
createDownloadTask: jest.fn(),
|
||||||
|
processDownloadTask: jest.fn(),
|
||||||
|
getDownloadTaskList: jest.fn(),
|
||||||
|
getDownloadTaskById: jest.fn(),
|
||||||
|
deleteDownloadTask: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: Logger,
|
||||||
|
useValue: {
|
||||||
|
error: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: AuthService,
|
||||||
|
useClass: jest.fn().mockImplementation(() => ({
|
||||||
|
varifytoken() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: CollaboratorService,
|
||||||
|
useValue: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: SurveyMetaService,
|
||||||
|
useValue: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: WorkspaceMemberService,
|
||||||
|
useValue: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: Authentication,
|
||||||
|
useClass: jest.fn().mockImplementation(() => ({
|
||||||
|
canActivate: () => true,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: SurveyGuard,
|
||||||
|
useClass: jest.fn().mockImplementation(() => ({
|
||||||
|
canActivate: () => true,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
controller = module.get<DownloadTaskController>(DownloadTaskController);
|
||||||
|
responseSchemaService = module.get<ResponseSchemaService>(
|
||||||
|
ResponseSchemaService,
|
||||||
|
);
|
||||||
|
downloadTaskService = module.get<DownloadTaskService>(DownloadTaskService);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createTask', () => {
|
||||||
|
it('should create a download task successfully', async () => {
|
||||||
|
const mockReqBody = {
|
||||||
|
surveyId: new ObjectId().toString(),
|
||||||
|
isMasked: false,
|
||||||
|
};
|
||||||
|
const mockReq = { user: { _id: 'mockUserId', username: 'mockUsername' } };
|
||||||
|
const mockTaskId = 'mockTaskId';
|
||||||
|
jest
|
||||||
|
.spyOn(responseSchemaService, 'getResponseSchemaByPageId')
|
||||||
|
.mockResolvedValue({} as any);
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskService, 'createDownloadTask')
|
||||||
|
.mockResolvedValue(mockTaskId);
|
||||||
|
|
||||||
|
const result = await controller.createTask(mockReqBody, mockReq);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
responseSchemaService.getResponseSchemaByPageId,
|
||||||
|
).toHaveBeenCalledWith(mockReqBody.surveyId);
|
||||||
|
expect(downloadTaskService.createDownloadTask).toHaveBeenCalledWith({
|
||||||
|
surveyId: mockReqBody.surveyId,
|
||||||
|
responseSchema: {},
|
||||||
|
creatorId: mockReq.user._id.toString(),
|
||||||
|
creator: mockReq.user.username,
|
||||||
|
params: { isMasked: mockReqBody.isMasked },
|
||||||
|
});
|
||||||
|
expect(downloadTaskService.processDownloadTask).toHaveBeenCalledWith({
|
||||||
|
taskId: mockTaskId,
|
||||||
|
});
|
||||||
|
expect(result).toEqual({ code: 200, data: { taskId: mockTaskId } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw HttpException if validation fails', async () => {
|
||||||
|
const mockReqBody: any = { isMasked: false };
|
||||||
|
const mockReq = { user: { _id: 'mockUserId', username: 'mockUsername' } };
|
||||||
|
|
||||||
|
await expect(controller.createTask(mockReqBody, mockReq)).rejects.toThrow(
|
||||||
|
HttpException,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('downloadList', () => {
|
||||||
|
it('should return the download task list', async () => {
|
||||||
|
const mockQueryInfo = { pageIndex: 1, pageSize: 10 };
|
||||||
|
const mockReq = { user: { _id: 'mockUserId' } };
|
||||||
|
const mockTaskList: any = {
|
||||||
|
total: 1,
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
_id: 'mockTaskId',
|
||||||
|
curStatus: 'completed',
|
||||||
|
filename: 'mockFile.csv',
|
||||||
|
url: 'http://mock-url.com',
|
||||||
|
fileSize: 1024,
|
||||||
|
createDate: Date.now(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskService, 'getDownloadTaskList')
|
||||||
|
.mockResolvedValue(mockTaskList);
|
||||||
|
|
||||||
|
const result = await controller.downloadList(mockQueryInfo, mockReq);
|
||||||
|
|
||||||
|
expect(downloadTaskService.getDownloadTaskList).toHaveBeenCalledWith({
|
||||||
|
creatorId: mockReq.user._id.toString(),
|
||||||
|
pageIndex: mockQueryInfo.pageIndex,
|
||||||
|
pageSize: mockQueryInfo.pageSize,
|
||||||
|
});
|
||||||
|
expect(result.data.total).toEqual(mockTaskList.total);
|
||||||
|
expect(result.data.list[0].taskId).toEqual(
|
||||||
|
mockTaskList.list[0]._id.toString(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw HttpException if validation fails', async () => {
|
||||||
|
const mockQueryInfo: any = { pageIndex: 'invalid', pageSize: 10 };
|
||||||
|
const mockReq = { user: { _id: 'mockUserId' } };
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
controller.downloadList(mockQueryInfo, mockReq),
|
||||||
|
).rejects.toThrow(HttpException);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getDownloadTask', () => {
|
||||||
|
it('should return a download task', async () => {
|
||||||
|
const mockQuery = { taskId: 'mockTaskId' };
|
||||||
|
const mockReq = { user: { _id: 'mockUserId' } };
|
||||||
|
const mockTaskInfo: any = {
|
||||||
|
_id: 'mockTaskId',
|
||||||
|
creatorId: 'mockUserId',
|
||||||
|
curStatus: 'completed',
|
||||||
|
};
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskService, 'getDownloadTaskById')
|
||||||
|
.mockResolvedValue(mockTaskInfo);
|
||||||
|
|
||||||
|
const result = await controller.getDownloadTask(mockQuery, mockReq);
|
||||||
|
|
||||||
|
expect(downloadTaskService.getDownloadTaskById).toHaveBeenCalledWith({
|
||||||
|
taskId: mockQuery.taskId,
|
||||||
|
});
|
||||||
|
expect(result.data.taskId).toEqual(mockTaskInfo._id.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw NoPermissionException if user has no permission', async () => {
|
||||||
|
const mockQuery = { taskId: 'mockTaskId' };
|
||||||
|
const mockReq = { user: { _id: new ObjectId() } };
|
||||||
|
const mockTaskInfo: any = {
|
||||||
|
_id: 'mockTaskId',
|
||||||
|
creatorId: 'mockUserId',
|
||||||
|
curStatus: 'completed',
|
||||||
|
};
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskService, 'getDownloadTaskById')
|
||||||
|
.mockResolvedValue(mockTaskInfo);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
controller.getDownloadTask(mockQuery, mockReq),
|
||||||
|
).rejects.toThrow(new NoPermissionException('没有权限'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteFileByName', () => {
|
||||||
|
it('should delete a download task successfully', async () => {
|
||||||
|
const mockBody = { taskId: 'mockTaskId' };
|
||||||
|
const mockReq = { user: { _id: 'mockUserId' } };
|
||||||
|
const mockTaskInfo: any = {
|
||||||
|
_id: new ObjectId(),
|
||||||
|
creatorId: 'mockUserId',
|
||||||
|
};
|
||||||
|
const mockDelRes = { modifiedCount: 1 };
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskService, 'getDownloadTaskById')
|
||||||
|
.mockResolvedValue(mockTaskInfo);
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskService, 'deleteDownloadTask')
|
||||||
|
.mockResolvedValue(mockDelRes);
|
||||||
|
|
||||||
|
const result = await controller.deleteFileByName(mockBody, mockReq);
|
||||||
|
|
||||||
|
expect(downloadTaskService.deleteDownloadTask).toHaveBeenCalledWith({
|
||||||
|
taskId: mockBody.taskId,
|
||||||
|
});
|
||||||
|
expect(result).toEqual({ code: 200, data: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw HttpException if task does not exist', async () => {
|
||||||
|
const mockBody = { taskId: 'mockTaskId' };
|
||||||
|
const mockReq = { user: { _id: 'mockUserId' } };
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskService, 'getDownloadTaskById')
|
||||||
|
.mockResolvedValue(null);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
controller.deleteFileByName(mockBody, mockReq),
|
||||||
|
).rejects.toThrow(
|
||||||
|
new HttpException('任务不存在', EXCEPTION_CODE.PARAMETER_ERROR),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
192
server/src/modules/survey/__test/downloadTask.service.spec.ts
Normal file
192
server/src/modules/survey/__test/downloadTask.service.spec.ts
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { DownloadTaskService } from '../services/downloadTask.service';
|
||||||
|
import { MongoRepository } from 'typeorm';
|
||||||
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
|
import { DownloadTask } from 'src/models/downloadTask.entity';
|
||||||
|
import { SurveyResponse } from 'src/models/surveyResponse.entity';
|
||||||
|
import { ResponseSchemaService } from 'src/modules/surveyResponse/services/responseScheme.service';
|
||||||
|
import { DataStatisticService } from '../services/dataStatistic.service';
|
||||||
|
import { FileService } from 'src/modules/file/services/file.service';
|
||||||
|
import { Logger } from 'src/logger';
|
||||||
|
import { ObjectId } from 'mongodb';
|
||||||
|
import { RECORD_STATUS } from 'src/enums';
|
||||||
|
|
||||||
|
describe('DownloadTaskService', () => {
|
||||||
|
let service: DownloadTaskService;
|
||||||
|
let downloadTaskRepository: MongoRepository<DownloadTask>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
providers: [
|
||||||
|
DownloadTaskService,
|
||||||
|
{
|
||||||
|
provide: getRepositoryToken(DownloadTask),
|
||||||
|
useClass: MongoRepository,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: getRepositoryToken(SurveyResponse),
|
||||||
|
useClass: MongoRepository,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: ResponseSchemaService,
|
||||||
|
useValue: {
|
||||||
|
getResponseSchemaByPageId: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: DataStatisticService,
|
||||||
|
useValue: {
|
||||||
|
getDataTable: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: FileService,
|
||||||
|
useValue: {
|
||||||
|
upload: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: Logger,
|
||||||
|
useValue: {
|
||||||
|
info: jest.fn(),
|
||||||
|
error: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<DownloadTaskService>(DownloadTaskService);
|
||||||
|
downloadTaskRepository = module.get<MongoRepository<DownloadTask>>(
|
||||||
|
getRepositoryToken(DownloadTask),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createDownloadTask', () => {
|
||||||
|
it('should create and save a download task', async () => {
|
||||||
|
const mockTaskId = new ObjectId().toString();
|
||||||
|
const mockDownloadTask = { _id: new ObjectId(mockTaskId) };
|
||||||
|
const mockParams: any = {
|
||||||
|
surveyId: 'survey1',
|
||||||
|
responseSchema: { title: 'test-title', surveyPath: '/path' },
|
||||||
|
creatorId: 'creator1',
|
||||||
|
creator: 'creatorName',
|
||||||
|
params: { isMasked: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskRepository, 'create')
|
||||||
|
.mockReturnValue(mockDownloadTask as any);
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskRepository, 'save')
|
||||||
|
.mockResolvedValue(mockDownloadTask as any);
|
||||||
|
|
||||||
|
const result = await service.createDownloadTask(mockParams);
|
||||||
|
|
||||||
|
expect(downloadTaskRepository.create).toHaveBeenCalledWith({
|
||||||
|
surveyId: mockParams.surveyId,
|
||||||
|
surveyPath: mockParams.responseSchema.surveyPath,
|
||||||
|
fileSize: '计算中',
|
||||||
|
creatorId: mockParams.creatorId,
|
||||||
|
creator: mockParams.creator,
|
||||||
|
params: {
|
||||||
|
...mockParams.params,
|
||||||
|
title: mockParams.responseSchema.title,
|
||||||
|
},
|
||||||
|
filename: expect.any(String),
|
||||||
|
});
|
||||||
|
expect(downloadTaskRepository.save).toHaveBeenCalled();
|
||||||
|
expect(result).toEqual(mockTaskId);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getDownloadTaskList', () => {
|
||||||
|
it('should return task list and total count', async () => {
|
||||||
|
const mockCreatorId = 'creator1';
|
||||||
|
const mockTasks = [{ _id: '1' }, { _id: '2' }];
|
||||||
|
const mockTotal = 2;
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskRepository, 'findAndCount')
|
||||||
|
.mockResolvedValue([mockTasks as any, mockTotal]);
|
||||||
|
|
||||||
|
const result = await service.getDownloadTaskList({
|
||||||
|
creatorId: mockCreatorId,
|
||||||
|
pageIndex: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(downloadTaskRepository.findAndCount).toHaveBeenCalledWith({
|
||||||
|
where: {
|
||||||
|
creatorId: mockCreatorId,
|
||||||
|
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
||||||
|
},
|
||||||
|
take: 10,
|
||||||
|
skip: 0,
|
||||||
|
order: { createDate: -1 },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result).toEqual({
|
||||||
|
total: mockTotal,
|
||||||
|
list: mockTasks,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getDownloadTaskById', () => {
|
||||||
|
it('should return task by id', async () => {
|
||||||
|
const mockTaskId = new ObjectId().toString();
|
||||||
|
const mockTask = { _id: new ObjectId(mockTaskId) };
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskRepository, 'find')
|
||||||
|
.mockResolvedValue([mockTask as any]);
|
||||||
|
|
||||||
|
const result = await service.getDownloadTaskById({ taskId: mockTaskId });
|
||||||
|
|
||||||
|
expect(downloadTaskRepository.find).toHaveBeenCalledWith({
|
||||||
|
where: { _id: new ObjectId(mockTaskId) },
|
||||||
|
});
|
||||||
|
expect(result).toEqual(mockTask);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return null if task is not found', async () => {
|
||||||
|
const mockTaskId = new ObjectId().toString();
|
||||||
|
|
||||||
|
jest.spyOn(downloadTaskRepository, 'find').mockResolvedValue([]);
|
||||||
|
|
||||||
|
const result = await service.getDownloadTaskById({ taskId: mockTaskId });
|
||||||
|
|
||||||
|
expect(result).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteDownloadTask', () => {
|
||||||
|
it('should update task status to REMOVED', async () => {
|
||||||
|
const mockTaskId = new ObjectId().toString();
|
||||||
|
const mockUpdateResult = { matchedCount: 1 };
|
||||||
|
|
||||||
|
jest
|
||||||
|
.spyOn(downloadTaskRepository, 'updateOne')
|
||||||
|
.mockResolvedValue(mockUpdateResult as any);
|
||||||
|
|
||||||
|
const result = await service.deleteDownloadTask({ taskId: mockTaskId });
|
||||||
|
|
||||||
|
expect(downloadTaskRepository.updateOne).toHaveBeenCalledWith(
|
||||||
|
{
|
||||||
|
_id: new ObjectId(mockTaskId),
|
||||||
|
'curStatus.status': { $ne: RECORD_STATUS.REMOVED },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
curStatus: {
|
||||||
|
status: RECORD_STATUS.REMOVED,
|
||||||
|
date: expect.any(Number),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
$push: { statusList: expect.any(Object) },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(result).toEqual(mockUpdateResult);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
87
server/src/modules/survey/__test/session.controller.spec.ts
Normal file
87
server/src/modules/survey/__test/session.controller.spec.ts
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { SessionController } from '../controllers/session.controller';
|
||||||
|
import { SessionService } from '../services/session.service';
|
||||||
|
import { Logger } from 'src/logger';
|
||||||
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
|
import { Authentication } from 'src/guards/authentication.guard';
|
||||||
|
import { SurveyGuard } from 'src/guards/survey.guard';
|
||||||
|
import { SessionGuard } from 'src/guards/session.guard';
|
||||||
|
|
||||||
|
describe('SessionController', () => {
|
||||||
|
let controller: SessionController;
|
||||||
|
let sessionService: jest.Mocked<SessionService>;
|
||||||
|
let logger: jest.Mocked<Logger>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
controllers: [SessionController],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: SessionService,
|
||||||
|
useValue: {
|
||||||
|
create: jest.fn(),
|
||||||
|
updateSessionToEditing: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: Logger,
|
||||||
|
useValue: {
|
||||||
|
error: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.overrideGuard(Authentication)
|
||||||
|
.useValue({ canActivate: () => true })
|
||||||
|
.overrideGuard(SurveyGuard)
|
||||||
|
.useValue({ canActivate: () => true })
|
||||||
|
.overrideGuard(SessionGuard)
|
||||||
|
.useValue({ canActivate: () => true })
|
||||||
|
.compile();
|
||||||
|
|
||||||
|
controller = module.get<SessionController>(SessionController);
|
||||||
|
sessionService = module.get<jest.Mocked<SessionService>>(SessionService);
|
||||||
|
logger = module.get<jest.Mocked<Logger>>(Logger);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a session', async () => {
|
||||||
|
const reqBody = { surveyId: '123' };
|
||||||
|
const req = { user: { _id: 'userId' } };
|
||||||
|
const session: any = { _id: 'sessionId' };
|
||||||
|
|
||||||
|
sessionService.create.mockResolvedValue(session);
|
||||||
|
|
||||||
|
const result = await controller.create(reqBody, req);
|
||||||
|
|
||||||
|
expect(sessionService.create).toHaveBeenCalledWith({
|
||||||
|
surveyId: '123',
|
||||||
|
userId: 'userId',
|
||||||
|
});
|
||||||
|
expect(result).toEqual({ code: 200, data: { sessionId: 'sessionId' } });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an exception if validation fails', async () => {
|
||||||
|
const reqBody = { surveyId: null };
|
||||||
|
const req = { user: { _id: 'userId' } };
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.create(reqBody, req);
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(HttpException);
|
||||||
|
expect(logger.error).toHaveBeenCalled();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should seize a session', async () => {
|
||||||
|
const req = {
|
||||||
|
sessionInfo: { _id: 'sessionId', surveyId: 'surveyId' },
|
||||||
|
};
|
||||||
|
|
||||||
|
await controller.seize(req);
|
||||||
|
|
||||||
|
expect(sessionService.updateSessionToEditing).toHaveBeenCalledWith({
|
||||||
|
sessionId: 'sessionId',
|
||||||
|
surveyId: 'surveyId',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -5,18 +5,22 @@ import { SurveyConfService } from '../services/surveyConf.service';
|
|||||||
import { ResponseSchemaService } from '../../surveyResponse/services/responseScheme.service';
|
import { ResponseSchemaService } from '../../surveyResponse/services/responseScheme.service';
|
||||||
import { ContentSecurityService } from '../services/contentSecurity.service';
|
import { ContentSecurityService } from '../services/contentSecurity.service';
|
||||||
import { SurveyHistoryService } from '../services/surveyHistory.service';
|
import { SurveyHistoryService } from '../services/surveyHistory.service';
|
||||||
|
import { CounterService } from '../../surveyResponse/services/counter.service';
|
||||||
|
import { SessionService } from '../services/session.service';
|
||||||
|
import { UserService } from '../../auth/services/user.service';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
||||||
import { SurveyConf } from 'src/models/surveyConf.entity';
|
import { SurveyConf } from 'src/models/surveyConf.entity';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { Logger } from 'src/logger';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
|
||||||
import { LoggerProvider } from 'src/logger/logger.provider';
|
|
||||||
|
|
||||||
jest.mock('../services/surveyMeta.service');
|
jest.mock('../services/surveyMeta.service');
|
||||||
jest.mock('../services/surveyConf.service');
|
jest.mock('../services/surveyConf.service');
|
||||||
jest.mock('../../surveyResponse/services/responseScheme.service');
|
jest.mock('../../surveyResponse/services/responseScheme.service');
|
||||||
jest.mock('../services/contentSecurity.service');
|
jest.mock('../services/contentSecurity.service');
|
||||||
jest.mock('../services/surveyHistory.service');
|
jest.mock('../services/surveyHistory.service');
|
||||||
|
jest.mock('../services/session.service');
|
||||||
|
jest.mock('../../surveyResponse/services/counter.service');
|
||||||
|
jest.mock('../../auth/services/user.service');
|
||||||
|
|
||||||
jest.mock('src/guards/authentication.guard');
|
jest.mock('src/guards/authentication.guard');
|
||||||
jest.mock('src/guards/survey.guard');
|
jest.mock('src/guards/survey.guard');
|
||||||
@ -27,19 +31,36 @@ describe('SurveyController', () => {
|
|||||||
let surveyMetaService: SurveyMetaService;
|
let surveyMetaService: SurveyMetaService;
|
||||||
let surveyConfService: SurveyConfService;
|
let surveyConfService: SurveyConfService;
|
||||||
let responseSchemaService: ResponseSchemaService;
|
let responseSchemaService: ResponseSchemaService;
|
||||||
let contentSecurityService: ContentSecurityService;
|
|
||||||
let surveyHistoryService: SurveyHistoryService;
|
let surveyHistoryService: SurveyHistoryService;
|
||||||
|
let sessionService: SessionService;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
controllers: [SurveyController],
|
controllers: [SurveyController],
|
||||||
providers: [
|
providers: [
|
||||||
SurveyMetaService,
|
SurveyMetaService,
|
||||||
SurveyConfService,
|
{
|
||||||
|
provide: SurveyConfService,
|
||||||
|
useValue: {
|
||||||
|
getSurveyConfBySurveyId: jest.fn(),
|
||||||
|
getSurveyContentByCode: jest.fn(),
|
||||||
|
createSurveyConf: jest.fn(),
|
||||||
|
saveSurveyConf: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
ResponseSchemaService,
|
ResponseSchemaService,
|
||||||
ContentSecurityService,
|
ContentSecurityService,
|
||||||
SurveyHistoryService,
|
SurveyHistoryService,
|
||||||
LoggerProvider,
|
SessionService,
|
||||||
|
CounterService,
|
||||||
|
UserService,
|
||||||
|
{
|
||||||
|
provide: Logger,
|
||||||
|
useValue: {
|
||||||
|
error: jest.fn(),
|
||||||
|
info: jest.fn(),
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
|
||||||
@ -49,17 +70,14 @@ describe('SurveyController', () => {
|
|||||||
responseSchemaService = module.get<ResponseSchemaService>(
|
responseSchemaService = module.get<ResponseSchemaService>(
|
||||||
ResponseSchemaService,
|
ResponseSchemaService,
|
||||||
);
|
);
|
||||||
contentSecurityService = module.get<ContentSecurityService>(
|
|
||||||
ContentSecurityService,
|
|
||||||
);
|
|
||||||
surveyHistoryService =
|
surveyHistoryService =
|
||||||
module.get<SurveyHistoryService>(SurveyHistoryService);
|
module.get<SurveyHistoryService>(SurveyHistoryService);
|
||||||
|
sessionService = module.get<SessionService>(SessionService);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getBannerData', () => {
|
describe('getBannerData', () => {
|
||||||
it('should return banner data', async () => {
|
it('should return banner data', async () => {
|
||||||
const result = await controller.getBannerData();
|
const result = await controller.getBannerData();
|
||||||
|
|
||||||
expect(result.code).toBe(200);
|
expect(result.code).toBe(200);
|
||||||
expect(result.data).toBeDefined();
|
expect(result.data).toBeDefined();
|
||||||
});
|
});
|
||||||
@ -71,33 +89,17 @@ describe('SurveyController', () => {
|
|||||||
surveyType: 'normal',
|
surveyType: 'normal',
|
||||||
remark: '问卷调研',
|
remark: '问卷调研',
|
||||||
title: '问卷调研',
|
title: '问卷调研',
|
||||||
} as SurveyMeta;
|
};
|
||||||
|
|
||||||
const newId = new ObjectId();
|
const newId = new ObjectId();
|
||||||
jest
|
jest.spyOn(surveyMetaService, 'createSurveyMeta').mockResolvedValue({
|
||||||
.spyOn(surveyMetaService, 'createSurveyMeta')
|
_id: newId,
|
||||||
.mockImplementation(() => {
|
} as SurveyMeta);
|
||||||
const result = {
|
|
||||||
_id: newId,
|
jest.spyOn(surveyConfService, 'createSurveyConf').mockResolvedValue({
|
||||||
} as SurveyMeta;
|
_id: new ObjectId(),
|
||||||
return Promise.resolve(result);
|
pageId: newId.toString(),
|
||||||
});
|
} as SurveyConf);
|
||||||
jest
|
|
||||||
.spyOn(surveyConfService, 'createSurveyConf')
|
|
||||||
.mockImplementation(
|
|
||||||
(params: {
|
|
||||||
surveyId: string;
|
|
||||||
surveyType: string;
|
|
||||||
createMethod: string;
|
|
||||||
createFrom: string;
|
|
||||||
}) => {
|
|
||||||
const result = {
|
|
||||||
_id: new ObjectId(),
|
|
||||||
pageId: params.surveyId,
|
|
||||||
code: {},
|
|
||||||
} as SurveyConf;
|
|
||||||
return Promise.resolve(result);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await controller.createSurvey(surveyInfo, {
|
const result = await controller.createSurvey(surveyInfo, {
|
||||||
user: { username: 'testUser', _id: new ObjectId() },
|
user: { username: 'testUser', _id: new ObjectId() },
|
||||||
@ -126,19 +128,15 @@ describe('SurveyController', () => {
|
|||||||
createFrom: existsSurveyId.toString(),
|
createFrom: existsSurveyId.toString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
jest
|
jest.spyOn(surveyMetaService, 'createSurveyMeta').mockResolvedValue({
|
||||||
.spyOn(surveyMetaService, 'createSurveyMeta')
|
_id: new ObjectId(),
|
||||||
.mockImplementation(() => {
|
} as SurveyMeta);
|
||||||
const result = {
|
|
||||||
_id: new ObjectId(),
|
|
||||||
} as SurveyMeta;
|
|
||||||
return Promise.resolve(result);
|
|
||||||
});
|
|
||||||
|
|
||||||
const request = {
|
const request = {
|
||||||
user: { username: 'testUser', _id: new ObjectId() },
|
user: { username: 'testUser', _id: new ObjectId() },
|
||||||
surveyMeta: existsSurveyMeta,
|
surveyMeta: existsSurveyMeta,
|
||||||
}; // 模拟请求对象,根据实际情况进行调整
|
};
|
||||||
|
|
||||||
const result = await controller.createSurvey(params, request);
|
const result = await controller.createSurvey(params, request);
|
||||||
expect(result?.data?.id).toBeDefined();
|
expect(result?.data?.id).toBeDefined();
|
||||||
});
|
});
|
||||||
@ -159,6 +157,12 @@ describe('SurveyController', () => {
|
|||||||
jest
|
jest
|
||||||
.spyOn(surveyHistoryService, 'addHistory')
|
.spyOn(surveyHistoryService, 'addHistory')
|
||||||
.mockResolvedValue(undefined);
|
.mockResolvedValue(undefined);
|
||||||
|
jest
|
||||||
|
.spyOn(sessionService, 'findLatestEditingOne')
|
||||||
|
.mockResolvedValue(null);
|
||||||
|
jest
|
||||||
|
.spyOn(sessionService, 'updateSessionToEditing')
|
||||||
|
.mockResolvedValue(undefined);
|
||||||
|
|
||||||
const reqBody = {
|
const reqBody = {
|
||||||
surveyId: surveyId.toString(),
|
surveyId: surveyId.toString(),
|
||||||
@ -178,6 +182,7 @@ describe('SurveyController', () => {
|
|||||||
dataList: [],
|
dataList: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
sessionId: 'mock-session-id',
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await controller.updateConf(reqBody, {
|
const result = await controller.updateConf(reqBody, {
|
||||||
@ -229,12 +234,10 @@ describe('SurveyController', () => {
|
|||||||
|
|
||||||
jest
|
jest
|
||||||
.spyOn(surveyConfService, 'getSurveyConfBySurveyId')
|
.spyOn(surveyConfService, 'getSurveyConfBySurveyId')
|
||||||
.mockResolvedValue(
|
.mockResolvedValue({
|
||||||
Promise.resolve({
|
_id: new ObjectId(),
|
||||||
_id: new ObjectId(),
|
pageId: surveyId.toString(),
|
||||||
pageId: surveyId.toString(),
|
} as SurveyConf);
|
||||||
} as SurveyConf),
|
|
||||||
);
|
|
||||||
|
|
||||||
const request = {
|
const request = {
|
||||||
user: { username: 'testUser', _id: new ObjectId() },
|
user: { username: 'testUser', _id: new ObjectId() },
|
||||||
@ -250,7 +253,7 @@ describe('SurveyController', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('publishSurvey', () => {
|
describe('publishSurvey', () => {
|
||||||
it('should publish a survey success', async () => {
|
it('should publish a survey successfully', async () => {
|
||||||
const surveyId = new ObjectId();
|
const surveyId = new ObjectId();
|
||||||
const surveyMeta = {
|
const surveyMeta = {
|
||||||
_id: surveyId,
|
_id: surveyId,
|
||||||
@ -260,80 +263,24 @@ describe('SurveyController', () => {
|
|||||||
|
|
||||||
jest
|
jest
|
||||||
.spyOn(surveyConfService, 'getSurveyConfBySurveyId')
|
.spyOn(surveyConfService, 'getSurveyConfBySurveyId')
|
||||||
.mockResolvedValue(
|
.mockResolvedValue({
|
||||||
Promise.resolve({
|
_id: new ObjectId(),
|
||||||
_id: new ObjectId(),
|
pageId: surveyId.toString(),
|
||||||
pageId: surveyId.toString(),
|
code: {},
|
||||||
} as SurveyConf),
|
} as SurveyConf);
|
||||||
);
|
|
||||||
|
|
||||||
jest
|
jest
|
||||||
.spyOn(surveyConfService, 'getSurveyContentByCode')
|
.spyOn(surveyConfService, 'getSurveyContentByCode')
|
||||||
.mockResolvedValue({
|
.mockResolvedValue({ text: '' });
|
||||||
text: '题目1',
|
|
||||||
});
|
|
||||||
|
|
||||||
jest
|
|
||||||
.spyOn(contentSecurityService, 'isForbiddenContent')
|
|
||||||
.mockResolvedValue(false);
|
|
||||||
jest
|
|
||||||
.spyOn(surveyMetaService, 'publishSurveyMeta')
|
|
||||||
.mockResolvedValue(undefined);
|
|
||||||
jest
|
|
||||||
.spyOn(responseSchemaService, 'publishResponseSchema')
|
|
||||||
.mockResolvedValue(undefined);
|
|
||||||
jest
|
|
||||||
.spyOn(surveyHistoryService, 'addHistory')
|
|
||||||
.mockResolvedValue(undefined);
|
|
||||||
|
|
||||||
const result = await controller.publishSurvey(
|
const result = await controller.publishSurvey(
|
||||||
{ surveyId: surveyId.toString() },
|
{ surveyId: surveyId.toString() },
|
||||||
{ user: { username: 'testUser', _id: 'testUserId' }, surveyMeta },
|
{
|
||||||
);
|
user: { username: 'testUser', _id: new ObjectId() },
|
||||||
|
surveyMeta,
|
||||||
expect(result).toEqual({
|
},
|
||||||
code: 200,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not publish a survey with forbidden content', async () => {
|
|
||||||
const surveyId = new ObjectId();
|
|
||||||
const surveyMeta = {
|
|
||||||
_id: surveyId,
|
|
||||||
surveyType: 'normal',
|
|
||||||
owner: 'testUser',
|
|
||||||
} as SurveyMeta;
|
|
||||||
|
|
||||||
jest
|
|
||||||
.spyOn(surveyConfService, 'getSurveyConfBySurveyId')
|
|
||||||
.mockResolvedValue(
|
|
||||||
Promise.resolve({
|
|
||||||
_id: new ObjectId(),
|
|
||||||
pageId: surveyId.toString(),
|
|
||||||
} as SurveyConf),
|
|
||||||
);
|
|
||||||
|
|
||||||
jest
|
|
||||||
.spyOn(surveyConfService, 'getSurveyContentByCode')
|
|
||||||
.mockResolvedValue({
|
|
||||||
text: '违禁词',
|
|
||||||
});
|
|
||||||
|
|
||||||
jest
|
|
||||||
.spyOn(contentSecurityService, 'isForbiddenContent')
|
|
||||||
.mockResolvedValue(true);
|
|
||||||
|
|
||||||
await expect(
|
|
||||||
controller.publishSurvey(
|
|
||||||
{ surveyId: surveyId.toString() },
|
|
||||||
{ user: { username: 'testUser', _id: 'testUserId' }, surveyMeta },
|
|
||||||
),
|
|
||||||
).rejects.toThrow(
|
|
||||||
new HttpException(
|
|
||||||
'问卷存在非法关键字,不允许发布',
|
|
||||||
EXCEPTION_CODE.SURVEY_CONTENT_NOT_ALLOW,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
expect(result.code).toBe(200);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,7 @@ import { SurveyMetaService } from '../services/surveyMeta.service';
|
|||||||
|
|
||||||
import { UserService } from 'src/modules/auth/services/user.service';
|
import { UserService } from 'src/modules/auth/services/user.service';
|
||||||
import { AuthService } from 'src/modules/auth/services/auth.service';
|
import { AuthService } from 'src/modules/auth/services/auth.service';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
|
|
||||||
jest.mock('src/guards/authentication.guard');
|
jest.mock('src/guards/authentication.guard');
|
||||||
jest.mock('src/guards/survey.guard');
|
jest.mock('src/guards/survey.guard');
|
||||||
@ -49,7 +49,7 @@ describe('SurveyHistoryController', () => {
|
|||||||
useClass: jest.fn().mockImplementation(() => ({})),
|
useClass: jest.fn().mockImplementation(() => ({})),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: XiaojuSurveyLogger,
|
provide: Logger,
|
||||||
useValue: {
|
useValue: {
|
||||||
info: jest.fn(),
|
info: jest.fn(),
|
||||||
error: jest.fn(),
|
error: jest.fn(),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { SurveyMetaController } from '../controllers/surveyMeta.controller';
|
import { SurveyMetaController } from '../controllers/surveyMeta.controller';
|
||||||
import { SurveyMetaService } from '../services/surveyMeta.service';
|
import { SurveyMetaService } from '../services/surveyMeta.service';
|
||||||
import { LoggerProvider } from 'src/logger/logger.provider';
|
import { Logger } from 'src/logger';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { CollaboratorService } from '../services/collaborator.service';
|
import { CollaboratorService } from '../services/collaborator.service';
|
||||||
@ -28,7 +28,12 @@ describe('SurveyMetaController', () => {
|
|||||||
.mockResolvedValue({ count: 0, data: [] }),
|
.mockResolvedValue({ count: 0, data: [] }),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
LoggerProvider,
|
{
|
||||||
|
provide: Logger,
|
||||||
|
useValue: {
|
||||||
|
error() {},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
provide: CollaboratorService,
|
provide: CollaboratorService,
|
||||||
useValue: {
|
useValue: {
|
||||||
@ -116,6 +121,7 @@ describe('SurveyMetaController', () => {
|
|||||||
curStatus: {
|
curStatus: {
|
||||||
date: date,
|
date: date,
|
||||||
},
|
},
|
||||||
|
surveyType: 'normal',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@ -140,10 +146,12 @@ describe('SurveyMetaController', () => {
|
|||||||
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/,
|
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/,
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
|
surveyType: 'normal',
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(surveyMetaService.getSurveyMetaList).toHaveBeenCalledWith({
|
expect(surveyMetaService.getSurveyMetaList).toHaveBeenCalledWith({
|
||||||
pageNum: queryInfo.curPage,
|
pageNum: queryInfo.curPage,
|
||||||
pageSize: queryInfo.pageSize,
|
pageSize: queryInfo.pageSize,
|
||||||
@ -194,4 +202,24 @@ describe('SurveyMetaController', () => {
|
|||||||
workspaceId: undefined,
|
workspaceId: undefined,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should handle Joi validation in getList', async () => {
|
||||||
|
const invalidQueryInfo: any = {
|
||||||
|
curPage: 'invalid',
|
||||||
|
pageSize: 10,
|
||||||
|
};
|
||||||
|
const req = {
|
||||||
|
user: {
|
||||||
|
username: 'test-user',
|
||||||
|
_id: new ObjectId(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controller.getList(invalidQueryInfo, req);
|
||||||
|
} catch (error) {
|
||||||
|
expect(error).toBeInstanceOf(HttpException);
|
||||||
|
expect(error.code).toBe(EXCEPTION_CODE.PARAMETER_ERROR);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -3,7 +3,7 @@ import { SurveyMetaService } from '../services/surveyMeta.service';
|
|||||||
import { MongoRepository } from 'typeorm';
|
import { MongoRepository } from 'typeorm';
|
||||||
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
import { SurveyMeta } from 'src/models/surveyMeta.entity';
|
||||||
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
||||||
import { XiaojuSurveyPluginManager } from 'src/securityPlugin/pluginManager';
|
import { PluginManager } from 'src/securityPlugin/pluginManager';
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_STATUS } from 'src/enums';
|
||||||
import { getRepositoryToken } from '@nestjs/typeorm';
|
import { getRepositoryToken } from '@nestjs/typeorm';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
@ -13,7 +13,7 @@ import { ObjectId } from 'mongodb';
|
|||||||
describe('SurveyMetaService', () => {
|
describe('SurveyMetaService', () => {
|
||||||
let service: SurveyMetaService;
|
let service: SurveyMetaService;
|
||||||
let surveyRepository: MongoRepository<SurveyMeta>;
|
let surveyRepository: MongoRepository<SurveyMeta>;
|
||||||
let pluginManager: XiaojuSurveyPluginManager;
|
let pluginManager: PluginManager;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
@ -37,8 +37,8 @@ describe('SurveyMetaService', () => {
|
|||||||
surveyRepository = module.get<MongoRepository<SurveyMeta>>(
|
surveyRepository = module.get<MongoRepository<SurveyMeta>>(
|
||||||
getRepositoryToken(SurveyMeta),
|
getRepositoryToken(SurveyMeta),
|
||||||
);
|
);
|
||||||
pluginManager = module.get<XiaojuSurveyPluginManager>(
|
pluginManager = module.get<PluginManager>(
|
||||||
XiaojuSurveyPluginManager,
|
PluginManager,
|
||||||
);
|
);
|
||||||
pluginManager.registerPlugin(new SurveyUtilPlugin());
|
pluginManager.registerPlugin(new SurveyUtilPlugin());
|
||||||
});
|
});
|
||||||
|
@ -20,7 +20,7 @@ import {
|
|||||||
SURVEY_PERMISSION,
|
SURVEY_PERMISSION,
|
||||||
SURVEY_PERMISSION_DESCRIPTION,
|
SURVEY_PERMISSION_DESCRIPTION,
|
||||||
} from 'src/enums/surveyPermission';
|
} from 'src/enums/surveyPermission';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { WorkspaceMemberService } from 'src/modules/workspace/services/workspaceMember.service';
|
import { WorkspaceMemberService } from 'src/modules/workspace/services/workspaceMember.service';
|
||||||
|
|
||||||
import { CollaboratorService } from '../services/collaborator.service';
|
import { CollaboratorService } from '../services/collaborator.service';
|
||||||
@ -40,7 +40,7 @@ import { SurveyMetaService } from '../services/surveyMeta.service';
|
|||||||
export class CollaboratorController {
|
export class CollaboratorController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly collaboratorService: CollaboratorService,
|
private readonly collaboratorService: CollaboratorService,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly surveyMetaService: SurveyMetaService,
|
private readonly surveyMetaService: SurveyMetaService,
|
||||||
private readonly workspaceMemberServie: WorkspaceMemberService,
|
private readonly workspaceMemberServie: WorkspaceMemberService,
|
||||||
|
@ -13,10 +13,10 @@ import { DataStatisticService } from '../services/dataStatistic.service';
|
|||||||
import { ResponseSchemaService } from '../../surveyResponse/services/responseScheme.service';
|
import { ResponseSchemaService } from '../../surveyResponse/services/responseScheme.service';
|
||||||
|
|
||||||
import { Authentication } from 'src/guards/authentication.guard';
|
import { Authentication } from 'src/guards/authentication.guard';
|
||||||
import { XiaojuSurveyPluginManager } from 'src/securityPlugin/pluginManager';
|
import { PluginManager } from 'src/securityPlugin/pluginManager';
|
||||||
import { SurveyGuard } from 'src/guards/survey.guard';
|
import { SurveyGuard } from 'src/guards/survey.guard';
|
||||||
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { AggregationStatisDto } from '../dto/aggregationStatis.dto';
|
import { AggregationStatisDto } from '../dto/aggregationStatis.dto';
|
||||||
@ -30,8 +30,8 @@ export class DataStatisticController {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly responseSchemaService: ResponseSchemaService,
|
private readonly responseSchemaService: ResponseSchemaService,
|
||||||
private readonly dataStatisticService: DataStatisticService,
|
private readonly dataStatisticService: DataStatisticService,
|
||||||
private readonly pluginManager: XiaojuSurveyPluginManager,
|
private readonly pluginManager: PluginManager,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get('/dataTable')
|
@Get('/dataTable')
|
||||||
@ -46,7 +46,7 @@ export class DataStatisticController {
|
|||||||
) {
|
) {
|
||||||
const { value, error } = await Joi.object({
|
const { value, error } = await Joi.object({
|
||||||
surveyId: Joi.string().required(),
|
surveyId: Joi.string().required(),
|
||||||
isDesensitive: Joi.boolean().default(true), // 默认true就是需要脱敏
|
isMasked: Joi.boolean().default(true), // 默认true就是需要脱敏
|
||||||
page: Joi.number().default(1),
|
page: Joi.number().default(1),
|
||||||
pageSize: Joi.number().default(10),
|
pageSize: Joi.number().default(10),
|
||||||
}).validate(queryInfo);
|
}).validate(queryInfo);
|
||||||
@ -54,7 +54,7 @@ export class DataStatisticController {
|
|||||||
this.logger.error(error.message);
|
this.logger.error(error.message);
|
||||||
throw new HttpException('参数有误', EXCEPTION_CODE.PARAMETER_ERROR);
|
throw new HttpException('参数有误', EXCEPTION_CODE.PARAMETER_ERROR);
|
||||||
}
|
}
|
||||||
const { surveyId, isDesensitive, page, pageSize } = value;
|
const { surveyId, isMasked, page, pageSize } = value;
|
||||||
const responseSchema =
|
const responseSchema =
|
||||||
await this.responseSchemaService.getResponseSchemaByPageId(surveyId);
|
await this.responseSchemaService.getResponseSchemaByPageId(surveyId);
|
||||||
const { total, listHead, listBody } =
|
const { total, listHead, listBody } =
|
||||||
@ -65,10 +65,10 @@ export class DataStatisticController {
|
|||||||
pageSize,
|
pageSize,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isDesensitive) {
|
if (isMasked) {
|
||||||
// 脱敏
|
// 脱敏
|
||||||
listBody.forEach((item) => {
|
listBody.forEach((item) => {
|
||||||
this.pluginManager.triggerHook('desensitiveData', item);
|
this.pluginManager.triggerHook('maskData', item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import {
|
|||||||
Request,
|
Request,
|
||||||
Post,
|
Post,
|
||||||
Body,
|
Body,
|
||||||
// Response,
|
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
|
||||||
|
|
||||||
@ -17,10 +16,9 @@ import { ResponseSchemaService } from '../../surveyResponse/services/responseSch
|
|||||||
import { Authentication } from 'src/guards/authentication.guard';
|
import { Authentication } from 'src/guards/authentication.guard';
|
||||||
import { SurveyGuard } from 'src/guards/survey.guard';
|
import { SurveyGuard } from 'src/guards/survey.guard';
|
||||||
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
//后添加
|
|
||||||
import { DownloadTaskService } from '../services/downloadTask.service';
|
import { DownloadTaskService } from '../services/downloadTask.service';
|
||||||
import {
|
import {
|
||||||
GetDownloadTaskDto,
|
GetDownloadTaskDto,
|
||||||
@ -38,7 +36,7 @@ export class DownloadTaskController {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly responseSchemaService: ResponseSchemaService,
|
private readonly responseSchemaService: ResponseSchemaService,
|
||||||
private readonly downloadTaskService: DownloadTaskService,
|
private readonly downloadTaskService: DownloadTaskService,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Post('/createTask')
|
@Post('/createTask')
|
||||||
@ -57,14 +55,15 @@ export class DownloadTaskController {
|
|||||||
this.logger.error(error.message);
|
this.logger.error(error.message);
|
||||||
throw new HttpException('参数有误', EXCEPTION_CODE.PARAMETER_ERROR);
|
throw new HttpException('参数有误', EXCEPTION_CODE.PARAMETER_ERROR);
|
||||||
}
|
}
|
||||||
const { surveyId, isDesensitive } = value;
|
const { surveyId, isMasked } = value;
|
||||||
const responseSchema =
|
const responseSchema =
|
||||||
await this.responseSchemaService.getResponseSchemaByPageId(surveyId);
|
await this.responseSchemaService.getResponseSchemaByPageId(surveyId);
|
||||||
const id = await this.downloadTaskService.createDownloadTask({
|
const id = await this.downloadTaskService.createDownloadTask({
|
||||||
surveyId,
|
surveyId,
|
||||||
responseSchema,
|
responseSchema,
|
||||||
operatorId: req.user._id.toString(),
|
creatorId: req.user._id.toString(),
|
||||||
params: { isDesensitive },
|
creator: req.user.username,
|
||||||
|
params: { isMasked },
|
||||||
});
|
});
|
||||||
this.downloadTaskService.processDownloadTask({ taskId: id });
|
this.downloadTaskService.processDownloadTask({ taskId: id });
|
||||||
return {
|
return {
|
||||||
@ -88,7 +87,7 @@ export class DownloadTaskController {
|
|||||||
}
|
}
|
||||||
const { pageIndex, pageSize } = value;
|
const { pageIndex, pageSize } = value;
|
||||||
const { total, list } = await this.downloadTaskService.getDownloadTaskList({
|
const { total, list } = await this.downloadTaskService.getDownloadTaskList({
|
||||||
ownerId: req.user._id.toString(),
|
creatorId: req.user._id.toString(),
|
||||||
pageIndex,
|
pageIndex,
|
||||||
pageSize,
|
pageSize,
|
||||||
});
|
});
|
||||||
@ -139,7 +138,7 @@ export class DownloadTaskController {
|
|||||||
throw new HttpException('任务不存在', EXCEPTION_CODE.PARAMETER_ERROR);
|
throw new HttpException('任务不存在', EXCEPTION_CODE.PARAMETER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taskInfo.ownerId !== req.user._id.toString()) {
|
if (taskInfo.creatorId !== req.user._id.toString()) {
|
||||||
throw new NoPermissionException('没有权限');
|
throw new NoPermissionException('没有权限');
|
||||||
}
|
}
|
||||||
const res: Record<string, any> = {
|
const res: Record<string, any> = {
|
||||||
@ -172,7 +171,7 @@ export class DownloadTaskController {
|
|||||||
throw new HttpException('任务不存在', EXCEPTION_CODE.PARAMETER_ERROR);
|
throw new HttpException('任务不存在', EXCEPTION_CODE.PARAMETER_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taskInfo.ownerId !== req.user._id.toString()) {
|
if (taskInfo.creatorId !== req.user._id.toString()) {
|
||||||
throw new NoPermissionException('没有权限');
|
throw new NoPermissionException('没有权限');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import { SessionService } from '../services/session.service';
|
|||||||
import { Authentication } from 'src/guards/authentication.guard';
|
import { Authentication } from 'src/guards/authentication.guard';
|
||||||
import { SurveyGuard } from 'src/guards/survey.guard';
|
import { SurveyGuard } from 'src/guards/survey.guard';
|
||||||
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { SessionGuard } from 'src/guards/session.guard';
|
import { SessionGuard } from 'src/guards/session.guard';
|
||||||
@ -25,7 +25,7 @@ import { SessionGuard } from 'src/guards/session.guard';
|
|||||||
export class SessionController {
|
export class SessionController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly sessionService: SessionService,
|
private readonly sessionService: SessionService,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Post('/create')
|
@Post('/create')
|
||||||
@ -69,7 +69,6 @@ export class SessionController {
|
|||||||
@HttpCode(200)
|
@HttpCode(200)
|
||||||
@UseGuards(SurveyGuard)
|
@UseGuards(SurveyGuard)
|
||||||
@UseGuards(SessionGuard)
|
@UseGuards(SessionGuard)
|
||||||
|
|
||||||
@SetMetadata('sessionId', 'body.sessionId')
|
@SetMetadata('sessionId', 'body.sessionId')
|
||||||
@SetMetadata('surveyPermission', [SURVEY_PERMISSION.SURVEY_CONF_MANAGE])
|
@SetMetadata('surveyPermission', [SURVEY_PERMISSION.SURVEY_CONF_MANAGE])
|
||||||
@UseGuards(Authentication)
|
@UseGuards(Authentication)
|
||||||
|
@ -17,7 +17,6 @@ import { SurveyConfService } from '../services/surveyConf.service';
|
|||||||
import { ResponseSchemaService } from '../../surveyResponse/services/responseScheme.service';
|
import { ResponseSchemaService } from '../../surveyResponse/services/responseScheme.service';
|
||||||
import { ContentSecurityService } from '../services/contentSecurity.service';
|
import { ContentSecurityService } from '../services/contentSecurity.service';
|
||||||
import { SurveyHistoryService } from '../services/surveyHistory.service';
|
import { SurveyHistoryService } from '../services/surveyHistory.service';
|
||||||
import { CounterService } from 'src/modules/surveyResponse/services/counter.service';
|
|
||||||
|
|
||||||
import BannerData from '../template/banner/index.json';
|
import BannerData from '../template/banner/index.json';
|
||||||
import { CreateSurveyDto } from '../dto/createSurvey.dto';
|
import { CreateSurveyDto } from '../dto/createSurvey.dto';
|
||||||
@ -26,7 +25,7 @@ import { Authentication } from 'src/guards/authentication.guard';
|
|||||||
import { HISTORY_TYPE } from 'src/enums';
|
import { HISTORY_TYPE } from 'src/enums';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { SurveyGuard } from 'src/guards/survey.guard';
|
import { SurveyGuard } from 'src/guards/survey.guard';
|
||||||
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
||||||
|
|
||||||
@ -44,8 +43,7 @@ export class SurveyController {
|
|||||||
private readonly responseSchemaService: ResponseSchemaService,
|
private readonly responseSchemaService: ResponseSchemaService,
|
||||||
private readonly contentSecurityService: ContentSecurityService,
|
private readonly contentSecurityService: ContentSecurityService,
|
||||||
private readonly surveyHistoryService: SurveyHistoryService,
|
private readonly surveyHistoryService: SurveyHistoryService,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
private readonly counterService: CounterService,
|
|
||||||
private readonly sessionService: SessionService,
|
private readonly sessionService: SessionService,
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
) {}
|
) {}
|
||||||
|
@ -14,7 +14,7 @@ import { SurveyHistoryService } from '../services/surveyHistory.service';
|
|||||||
import { Authentication } from 'src/guards/authentication.guard';
|
import { Authentication } from 'src/guards/authentication.guard';
|
||||||
import { SurveyGuard } from 'src/guards/survey.guard';
|
import { SurveyGuard } from 'src/guards/survey.guard';
|
||||||
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
@ApiTags('survey')
|
@ApiTags('survey')
|
||||||
@ -22,7 +22,7 @@ import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
|||||||
export class SurveyHistoryController {
|
export class SurveyHistoryController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly surveyHistoryService: SurveyHistoryService,
|
private readonly surveyHistoryService: SurveyHistoryService,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get('/getList')
|
@Get('/getList')
|
||||||
|
@ -19,7 +19,7 @@ import { getFilter, getOrder } from 'src/utils/surveyUtil';
|
|||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { Authentication } from 'src/guards/authentication.guard';
|
import { Authentication } from 'src/guards/authentication.guard';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { SurveyGuard } from 'src/guards/survey.guard';
|
import { SurveyGuard } from 'src/guards/survey.guard';
|
||||||
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
import { SURVEY_PERMISSION } from 'src/enums/surveyPermission';
|
||||||
import { WorkspaceGuard } from 'src/guards/workspace.guard';
|
import { WorkspaceGuard } from 'src/guards/workspace.guard';
|
||||||
@ -33,7 +33,7 @@ import { CollaboratorService } from '../services/collaborator.service';
|
|||||||
export class SurveyMetaController {
|
export class SurveyMetaController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly surveyMetaService: SurveyMetaService,
|
private readonly surveyMetaService: SurveyMetaService,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
private readonly collaboratorService: CollaboratorService,
|
private readonly collaboratorService: CollaboratorService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
@ -12,10 +12,10 @@ export class CreateSurveyDto {
|
|||||||
surveyType: string;
|
surveyType: string;
|
||||||
|
|
||||||
@ApiProperty({ description: '创建方法', required: false })
|
@ApiProperty({ description: '创建方法', required: false })
|
||||||
createMethod: string;
|
createMethod?: string;
|
||||||
|
|
||||||
@ApiProperty({ description: '创建来源', required: false })
|
@ApiProperty({ description: '创建来源', required: false })
|
||||||
createFrom: string;
|
createFrom?: string;
|
||||||
|
|
||||||
@ApiProperty({ description: '问卷创建在哪个空间下', required: false })
|
@ApiProperty({ description: '问卷创建在哪个空间下', required: false })
|
||||||
workspaceId?: string;
|
workspaceId?: string;
|
||||||
|
@ -5,12 +5,12 @@ export class CreateDownloadDto {
|
|||||||
@ApiProperty({ description: '问卷id', required: true })
|
@ApiProperty({ description: '问卷id', required: true })
|
||||||
surveyId: string;
|
surveyId: string;
|
||||||
@ApiProperty({ description: '是否脱敏', required: false })
|
@ApiProperty({ description: '是否脱敏', required: false })
|
||||||
isDesensitive: boolean;
|
isMasked: boolean;
|
||||||
|
|
||||||
static validate(data) {
|
static validate(data) {
|
||||||
return Joi.object({
|
return Joi.object({
|
||||||
surveyId: Joi.string().required(),
|
surveyId: Joi.string().required(),
|
||||||
isDesensitive: Joi.boolean().allow(null).default(false),
|
isMasked: Joi.boolean().allow(null).default(false),
|
||||||
}).validate(data);
|
}).validate(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,14 @@ import { Collaborator } from 'src/models/collaborator.entity';
|
|||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { MongoRepository } from 'typeorm';
|
import { MongoRepository } from 'typeorm';
|
||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CollaboratorService {
|
export class CollaboratorService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(Collaborator)
|
@InjectRepository(Collaborator)
|
||||||
private readonly collaboratorRepository: MongoRepository<Collaborator>,
|
private readonly collaboratorRepository: MongoRepository<Collaborator>,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create({ surveyId, userId, permissions }) {
|
async create({ surveyId, userId, permissions }) {
|
||||||
|
@ -12,13 +12,13 @@ import xlsx from 'node-xlsx';
|
|||||||
import { load } from 'cheerio';
|
import { load } from 'cheerio';
|
||||||
import { get } from 'lodash';
|
import { get } from 'lodash';
|
||||||
import { FileService } from 'src/modules/file/services/file.service';
|
import { FileService } from 'src/modules/file/services/file.service';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DownloadTaskService {
|
export class DownloadTaskService {
|
||||||
private static taskList: Array<any> = [];
|
static taskList: Array<any> = [];
|
||||||
private static isExecuting: boolean = false;
|
static isExecuting: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(DownloadTask)
|
@InjectRepository(DownloadTask)
|
||||||
@ -28,26 +28,29 @@ export class DownloadTaskService {
|
|||||||
private readonly surveyResponseRepository: MongoRepository<SurveyResponse>,
|
private readonly surveyResponseRepository: MongoRepository<SurveyResponse>,
|
||||||
private readonly dataStatisticService: DataStatisticService,
|
private readonly dataStatisticService: DataStatisticService,
|
||||||
private readonly fileService: FileService,
|
private readonly fileService: FileService,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async createDownloadTask({
|
async createDownloadTask({
|
||||||
surveyId,
|
surveyId,
|
||||||
responseSchema,
|
responseSchema,
|
||||||
operatorId,
|
creatorId,
|
||||||
|
creator,
|
||||||
params,
|
params,
|
||||||
}: {
|
}: {
|
||||||
surveyId: string;
|
surveyId: string;
|
||||||
responseSchema: ResponseSchema;
|
responseSchema: ResponseSchema;
|
||||||
operatorId: string;
|
creatorId: string;
|
||||||
|
creator: string;
|
||||||
params: any;
|
params: any;
|
||||||
}) {
|
}) {
|
||||||
const filename = `${responseSchema.title}-${params.isDesensitive ? '脱敏' : '原'}回收数据-${moment().format('YYYYMMDDHHmmss')}.xlsx`;
|
const filename = `${responseSchema.title}-${params.isMasked ? '脱敏' : '原'}回收数据-${moment().format('YYYYMMDDHHmmss')}.xlsx`;
|
||||||
const downloadTask = this.downloadTaskRepository.create({
|
const downloadTask = this.downloadTaskRepository.create({
|
||||||
surveyId,
|
surveyId,
|
||||||
surveyPath: responseSchema.surveyPath,
|
surveyPath: responseSchema.surveyPath,
|
||||||
fileSize: '计算中',
|
fileSize: '计算中',
|
||||||
ownerId: operatorId,
|
creatorId,
|
||||||
|
creator,
|
||||||
params: {
|
params: {
|
||||||
...params,
|
...params,
|
||||||
title: responseSchema.title,
|
title: responseSchema.title,
|
||||||
@ -59,16 +62,16 @@ export class DownloadTaskService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getDownloadTaskList({
|
async getDownloadTaskList({
|
||||||
ownerId,
|
creatorId,
|
||||||
pageIndex,
|
pageIndex,
|
||||||
pageSize,
|
pageSize,
|
||||||
}: {
|
}: {
|
||||||
ownerId: string;
|
creatorId: string;
|
||||||
pageIndex: number;
|
pageIndex: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
}) {
|
}) {
|
||||||
const where = {
|
const where = {
|
||||||
ownerId,
|
creatorId,
|
||||||
'curStatus.status': {
|
'curStatus.status': {
|
||||||
$ne: RECORD_STATUS.REMOVED,
|
$ne: RECORD_STATUS.REMOVED,
|
||||||
},
|
},
|
||||||
@ -131,9 +134,11 @@ export class DownloadTaskService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async executeTask() {
|
async executeTask() {
|
||||||
try {
|
try {
|
||||||
for (const taskId of DownloadTaskService.taskList) {
|
while (DownloadTaskService.taskList.length > 0) {
|
||||||
|
const taskId = DownloadTaskService.taskList.shift();
|
||||||
|
this.logger.info(`handle taskId: ${taskId}`);
|
||||||
const taskInfo = await this.getDownloadTaskById({ taskId });
|
const taskInfo = await this.getDownloadTaskById({ taskId });
|
||||||
if (!taskInfo || taskInfo.curStatus.status === RECORD_STATUS.REMOVED) {
|
if (!taskInfo || taskInfo.curStatus.status === RECORD_STATUS.REMOVED) {
|
||||||
// 不存在或者已删除的,不处理
|
// 不存在或者已删除的,不处理
|
||||||
@ -228,7 +233,7 @@ export class DownloadTaskService {
|
|||||||
configKey: 'SERVER_LOCAL_CONFIG',
|
configKey: 'SERVER_LOCAL_CONFIG',
|
||||||
file,
|
file,
|
||||||
pathPrefix: 'exportfile',
|
pathPrefix: 'exportfile',
|
||||||
keepOriginFilename: true,
|
filename: taskInfo.filename,
|
||||||
});
|
});
|
||||||
|
|
||||||
const curStatus = {
|
const curStatus = {
|
||||||
|
@ -6,14 +6,14 @@ import { RECORD_STATUS } from 'src/enums';
|
|||||||
import { ObjectId } from 'mongodb';
|
import { ObjectId } from 'mongodb';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { XiaojuSurveyPluginManager } from 'src/securityPlugin/pluginManager';
|
import { PluginManager } from 'src/securityPlugin/pluginManager';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SurveyMetaService {
|
export class SurveyMetaService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(SurveyMeta)
|
@InjectRepository(SurveyMeta)
|
||||||
private readonly surveyRepository: MongoRepository<SurveyMeta>,
|
private readonly surveyRepository: MongoRepository<SurveyMeta>,
|
||||||
private readonly pluginManager: XiaojuSurveyPluginManager,
|
private readonly pluginManager: PluginManager,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getNewSurveyPath(): Promise<string> {
|
async getNewSurveyPath(): Promise<string> {
|
||||||
|
@ -13,14 +13,14 @@ import { ClientEncryptService } from '../services/clientEncrypt.service';
|
|||||||
import { MessagePushingTaskService } from 'src/modules/message/services/messagePushingTask.service';
|
import { MessagePushingTaskService } from 'src/modules/message/services/messagePushingTask.service';
|
||||||
|
|
||||||
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
import { PluginManagerProvider } from 'src/securityPlugin/pluginManager.provider';
|
||||||
import { XiaojuSurveyPluginManager } from 'src/securityPlugin/pluginManager';
|
import { PluginManager } from 'src/securityPlugin/pluginManager';
|
||||||
import { HttpException } from 'src/exceptions/httpException';
|
import { HttpException } from 'src/exceptions/httpException';
|
||||||
import { SurveyNotFoundException } from 'src/exceptions/surveyNotFoundException';
|
import { SurveyNotFoundException } from 'src/exceptions/surveyNotFoundException';
|
||||||
import { ResponseSecurityPlugin } from 'src/securityPlugin/responseSecurityPlugin';
|
import { ResponseSecurityPlugin } from 'src/securityPlugin/responseSecurityPlugin';
|
||||||
|
|
||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_STATUS } from 'src/enums';
|
||||||
import { SurveyResponse } from 'src/models/surveyResponse.entity';
|
import { SurveyResponse } from 'src/models/surveyResponse.entity';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
import { ResponseSchema } from 'src/models/responseSchema.entity';
|
||||||
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
||||||
import { UserService } from 'src/modules/auth/services/user.service';
|
import { UserService } from 'src/modules/auth/services/user.service';
|
||||||
@ -122,7 +122,7 @@ describe('SurveyResponseController', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: XiaojuSurveyLogger,
|
provide: Logger,
|
||||||
useValue: {
|
useValue: {
|
||||||
error: jest.fn(),
|
error: jest.fn(),
|
||||||
info: jest.fn(),
|
info: jest.fn(),
|
||||||
@ -153,8 +153,8 @@ describe('SurveyResponseController', () => {
|
|||||||
clientEncryptService =
|
clientEncryptService =
|
||||||
module.get<ClientEncryptService>(ClientEncryptService);
|
module.get<ClientEncryptService>(ClientEncryptService);
|
||||||
|
|
||||||
const pluginManager = module.get<XiaojuSurveyPluginManager>(
|
const pluginManager = module.get<PluginManager>(
|
||||||
XiaojuSurveyPluginManager,
|
PluginManager,
|
||||||
);
|
);
|
||||||
pluginManager.registerPlugin(
|
pluginManager.registerPlugin(
|
||||||
new ResponseSecurityPlugin('dataAesEncryptSecretKey'),
|
new ResponseSecurityPlugin('dataAesEncryptSecretKey'),
|
||||||
|
@ -13,7 +13,7 @@ import { EXCEPTION_CODE } from 'src/enums/exceptionCode';
|
|||||||
import { RECORD_STATUS } from 'src/enums';
|
import { RECORD_STATUS } from 'src/enums';
|
||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
import Joi from 'joi';
|
import Joi from 'joi';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { SurveyNotFoundException } from 'src/exceptions/surveyNotFoundException';
|
import { SurveyNotFoundException } from 'src/exceptions/surveyNotFoundException';
|
||||||
import { WhitelistType } from 'src/interfaces/survey';
|
import { WhitelistType } from 'src/interfaces/survey';
|
||||||
import { UserService } from 'src/modules/auth/services/user.service';
|
import { UserService } from 'src/modules/auth/services/user.service';
|
||||||
@ -24,7 +24,7 @@ import { WorkspaceMemberService } from 'src/modules/workspace/services/workspace
|
|||||||
export class ResponseSchemaController {
|
export class ResponseSchemaController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly responseSchemaService: ResponseSchemaService,
|
private readonly responseSchemaService: ResponseSchemaService,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly workspaceMemberService: WorkspaceMemberService,
|
private readonly workspaceMemberService: WorkspaceMemberService,
|
||||||
) {}
|
) {}
|
||||||
|
@ -18,7 +18,7 @@ import * as forge from 'node-forge';
|
|||||||
import { ApiTags } from '@nestjs/swagger';
|
import { ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
import { CounterService } from '../services/counter.service';
|
import { CounterService } from '../services/counter.service';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { WhitelistType } from 'src/interfaces/survey';
|
import { WhitelistType } from 'src/interfaces/survey';
|
||||||
import { UserService } from 'src/modules/auth/services/user.service';
|
import { UserService } from 'src/modules/auth/services/user.service';
|
||||||
import { WorkspaceMemberService } from 'src/modules/workspace/services/workspaceMember.service';
|
import { WorkspaceMemberService } from 'src/modules/workspace/services/workspaceMember.service';
|
||||||
@ -40,7 +40,7 @@ export class SurveyResponseController {
|
|||||||
private readonly clientEncryptService: ClientEncryptService,
|
private readonly clientEncryptService: ClientEncryptService,
|
||||||
private readonly messagePushingTaskService: MessagePushingTaskService,
|
private readonly messagePushingTaskService: MessagePushingTaskService,
|
||||||
private readonly counterService: CounterService,
|
private readonly counterService: CounterService,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
// private readonly redisService: RedisService,
|
// private readonly redisService: RedisService,
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly workspaceMemberService: WorkspaceMemberService,
|
private readonly workspaceMemberService: WorkspaceMemberService,
|
||||||
|
@ -10,7 +10,7 @@ import { Workspace } from 'src/models/workspace.entity';
|
|||||||
import { WorkspaceMember } from 'src/models/workspaceMember.entity';
|
import { WorkspaceMember } from 'src/models/workspaceMember.entity';
|
||||||
import { UserService } from 'src/modules/auth/services/user.service';
|
import { UserService } from 'src/modules/auth/services/user.service';
|
||||||
import { SurveyMetaService } from 'src/modules/survey/services/surveyMeta.service';
|
import { SurveyMetaService } from 'src/modules/survey/services/surveyMeta.service';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { User } from 'src/models/user.entity';
|
import { User } from 'src/models/user.entity';
|
||||||
|
|
||||||
jest.mock('src/guards/authentication.guard');
|
jest.mock('src/guards/authentication.guard');
|
||||||
@ -65,7 +65,7 @@ describe('WorkspaceController', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: XiaojuSurveyLogger,
|
provide: Logger,
|
||||||
useValue: {
|
useValue: {
|
||||||
info: jest.fn(),
|
info: jest.fn(),
|
||||||
error: jest.fn(),
|
error: jest.fn(),
|
||||||
|
@ -31,7 +31,7 @@ import {
|
|||||||
import { splitMembers } from '../utils/splitMember';
|
import { splitMembers } from '../utils/splitMember';
|
||||||
import { UserService } from 'src/modules/auth/services/user.service';
|
import { UserService } from 'src/modules/auth/services/user.service';
|
||||||
import { SurveyMetaService } from 'src/modules/survey/services/surveyMeta.service';
|
import { SurveyMetaService } from 'src/modules/survey/services/surveyMeta.service';
|
||||||
import { XiaojuSurveyLogger } from 'src/logger';
|
import { Logger } from 'src/logger';
|
||||||
import { GetWorkspaceListDto } from '../dto/getWorkspaceList.dto';
|
import { GetWorkspaceListDto } from '../dto/getWorkspaceList.dto';
|
||||||
import { WorkspaceMember } from 'src/models/workspaceMember.entity';
|
import { WorkspaceMember } from 'src/models/workspaceMember.entity';
|
||||||
import { Workspace } from 'src/models/workspace.entity';
|
import { Workspace } from 'src/models/workspace.entity';
|
||||||
@ -46,7 +46,7 @@ export class WorkspaceController {
|
|||||||
private readonly workspaceMemberService: WorkspaceMemberService,
|
private readonly workspaceMemberService: WorkspaceMemberService,
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly surveyMetaService: SurveyMetaService,
|
private readonly surveyMetaService: SurveyMetaService,
|
||||||
private readonly logger: XiaojuSurveyLogger,
|
private readonly logger: Logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Get('getRoleList')
|
@Get('getRoleList')
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
export interface XiaojuSurveyPlugin {
|
export interface XiaojuSurveyPlugin {
|
||||||
beforeResponseDataCreate?(responseData);
|
encryptResponseData?(responseData);
|
||||||
afterResponseFind?(responseData);
|
afterResponseFind?(responseData);
|
||||||
desensitiveData?(data: Record<string, any>);
|
maskData?(data: Record<string, any>);
|
||||||
genSurveyPath?();
|
genSurveyPath?();
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import xiaojuSurveyPluginManager, {
|
import xiaojuSurveyPluginManager, {
|
||||||
XiaojuSurveyPluginManager,
|
PluginManager,
|
||||||
} from './pluginManager';
|
} from './pluginManager';
|
||||||
import { Provider } from '@nestjs/common';
|
import { Provider } from '@nestjs/common';
|
||||||
|
|
||||||
export const PluginManagerProvider: Provider = {
|
export const PluginManagerProvider: Provider = {
|
||||||
provide: XiaojuSurveyPluginManager,
|
provide: PluginManager,
|
||||||
useValue: xiaojuSurveyPluginManager,
|
useValue: xiaojuSurveyPluginManager,
|
||||||
};
|
};
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { XiaojuSurveyPlugin } from './interface';
|
import { XiaojuSurveyPlugin } from './interface';
|
||||||
|
|
||||||
type AllowHooks =
|
type AllowHooks =
|
||||||
| 'beforeResponseDataCreate'
|
| 'encryptResponseData'
|
||||||
| 'afterResponseDataReaded'
|
| 'decryptResponseData'
|
||||||
| 'desensitiveData'
|
| 'maskData'
|
||||||
| 'genSurveyPath';
|
| 'genSurveyPath';
|
||||||
|
|
||||||
export class XiaojuSurveyPluginManager {
|
export class PluginManager {
|
||||||
private plugins: Array<XiaojuSurveyPlugin> = [];
|
private plugins: Array<XiaojuSurveyPlugin> = [];
|
||||||
// 注册插件
|
// 注册插件
|
||||||
registerPlugin(...plugins: Array<XiaojuSurveyPlugin>) {
|
registerPlugin(...plugins: Array<XiaojuSurveyPlugin>) {
|
||||||
@ -23,4 +23,4 @@ export class XiaojuSurveyPluginManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new XiaojuSurveyPluginManager();
|
export default new PluginManager();
|
||||||
|
@ -4,12 +4,12 @@ import {
|
|||||||
decryptData,
|
decryptData,
|
||||||
encryptData,
|
encryptData,
|
||||||
isDataSensitive,
|
isDataSensitive,
|
||||||
desensitiveData,
|
maskData,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
export class ResponseSecurityPlugin implements XiaojuSurveyPlugin {
|
export class ResponseSecurityPlugin implements XiaojuSurveyPlugin {
|
||||||
constructor(private readonly secretKey: string) {}
|
constructor(private readonly secretKey: string) {}
|
||||||
beforeResponseDataCreate(responseData: SurveyResponse) {
|
encryptResponseData(responseData: SurveyResponse) {
|
||||||
const secretKeys = [];
|
const secretKeys = [];
|
||||||
if (responseData.data) {
|
if (responseData.data) {
|
||||||
for (const key in responseData.data) {
|
for (const key in responseData.data) {
|
||||||
@ -39,7 +39,7 @@ export class ResponseSecurityPlugin implements XiaojuSurveyPlugin {
|
|||||||
responseData.secretKeys = secretKeys;
|
responseData.secretKeys = secretKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
afterResponseDataReaded(responseData: SurveyResponse) {
|
decryptResponseData(responseData: SurveyResponse) {
|
||||||
const secretKeys = responseData.secretKeys;
|
const secretKeys = responseData.secretKeys;
|
||||||
if (Array.isArray(secretKeys) && secretKeys.length > 0) {
|
if (Array.isArray(secretKeys) && secretKeys.length > 0) {
|
||||||
for (const key of secretKeys) {
|
for (const key of secretKeys) {
|
||||||
@ -57,10 +57,10 @@ export class ResponseSecurityPlugin implements XiaojuSurveyPlugin {
|
|||||||
responseData.secretKeys = [];
|
responseData.secretKeys = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
desensitiveData(data: Record<string, any>) {
|
maskData(data: Record<string, any>) {
|
||||||
Object.keys(data).forEach((key) => {
|
Object.keys(data).forEach((key) => {
|
||||||
if (isDataSensitive(data[key])) {
|
if (isDataSensitive(data[key])) {
|
||||||
data[key] = desensitiveData(data[key]);
|
data[key] = maskData(data[key]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ export const decryptData = (data, { secretKey }) => {
|
|||||||
return CryptoJS.AES.decrypt(data, secretKey).toString(CryptoJS.enc.Utf8);
|
return CryptoJS.AES.decrypt(data, secretKey).toString(CryptoJS.enc.Utf8);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const desensitiveData = (data: string): string => {
|
export const maskData = (data: string): string => {
|
||||||
if (!isString(data)) {
|
if (!isString(data)) {
|
||||||
return '*';
|
return '*';
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"echarts": "^5.5.0",
|
"echarts": "^5.5.0",
|
||||||
"element-plus": "^2.8.1",
|
"element-plus": "^2.8.3",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
"nanoid": "^5.0.7",
|
"nanoid": "^5.0.7",
|
||||||
|
@ -4,13 +4,10 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { watch, onBeforeUnmount } from 'vue'
|
import { watch, onBeforeUnmount } from 'vue'
|
||||||
import { get as _get } from 'lodash-es'
|
|
||||||
import { useUserStore } from '@/management/stores/user'
|
import { useUserStore } from '@/management/stores/user'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { ElMessageBox, ElMessage, type Action } from 'element-plus'
|
import { ElMessageBox, ElMessage, type Action } from 'element-plus'
|
||||||
|
import { checkIsTokenValid } from '@/management/api/auth';
|
||||||
// 这里不需要自动跳转登录页面,所以单独引入axios
|
|
||||||
import axios from 'axios'
|
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -32,16 +29,9 @@ const showConfirmBox = () => {
|
|||||||
|
|
||||||
const checkAuth = async () => {
|
const checkAuth = async () => {
|
||||||
try {
|
try {
|
||||||
const token = _get(userStore, 'userInfo.token')
|
const res: Record<string, any> = await checkIsTokenValid()
|
||||||
|
if (res.code !== 200 || !res.data) {
|
||||||
const res = await axios({
|
showConfirmBox();
|
||||||
url: '/api/user/getUserInfo',
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (res.data.code !== 200) {
|
|
||||||
showConfirmBox()
|
|
||||||
} else {
|
} else {
|
||||||
timer = setTimeout(
|
timer = setTimeout(
|
||||||
() => {
|
() => {
|
||||||
|
@ -19,3 +19,7 @@ export const getPasswordStrength = (password) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const checkIsTokenValid = () => {
|
||||||
|
return axios.get('/auth/verifyToken');
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
import axios from './base'
|
import axios from './base'
|
||||||
|
|
||||||
export const createDownloadSurveyResponseTask = ({ surveyId, isDesensitive }) => {
|
export const createDownloadTask = ({ surveyId, isMasked }) => {
|
||||||
return axios.post('/downloadTask/createTask', {
|
return axios.post('/downloadTask/createTask', {
|
||||||
surveyId,
|
surveyId,
|
||||||
isDesensitive
|
isMasked
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
91
web/src/management/components/TopNav.vue
Normal file
91
web/src/management/components/TopNav.vue
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<div class="top-nav">
|
||||||
|
<div class="left">
|
||||||
|
<img class="logo-img" src="/imgs/Logo.webp" alt="logo" />
|
||||||
|
<el-menu router default-active-index="survey" class="el-menu-demo" mode="horizontal">
|
||||||
|
<el-menu-item index="survey" >
|
||||||
|
<router-link :to="{ name: 'survey' }">问卷列表</router-link>
|
||||||
|
</el-menu-item>
|
||||||
|
<el-menu-item index="download">
|
||||||
|
<router-link :to="{ name: 'download' }">下载中心</router-link>
|
||||||
|
</el-menu-item>
|
||||||
|
</el-menu>
|
||||||
|
</div>
|
||||||
|
<div class="login-info">
|
||||||
|
您好,{{ userInfo?.username }}
|
||||||
|
<img class="login-info-img" src="/imgs/avatar.webp" />
|
||||||
|
<span class="logout" @click="handleLogout">退出</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useUserStore } from '@/management/stores/user'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const userInfo = computed(() => {
|
||||||
|
return userStore.userInfo
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleLogout = () => {
|
||||||
|
userStore.logout()
|
||||||
|
router.replace({ name: 'login' })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.top-nav {
|
||||||
|
background: #fff;
|
||||||
|
color: #4a4c5b;
|
||||||
|
padding: 0 20px;
|
||||||
|
height: 56px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.04);
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: calc(100% - 200px);
|
||||||
|
.logo-img {
|
||||||
|
width: 90px;
|
||||||
|
height: fit-content;
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
.el-menu {
|
||||||
|
width: 100%;
|
||||||
|
height: 56px;
|
||||||
|
border: none !important;
|
||||||
|
:deep(.el-menu-item, .is-active) {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
.router-link-active {
|
||||||
|
color: $primary-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.login-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.login-info-img {
|
||||||
|
margin-left: 10px;
|
||||||
|
height: 30px;
|
||||||
|
margin-top: -6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout {
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #faa600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -6,6 +6,10 @@ import safeHtml from './directive/safeHtml'
|
|||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
|
|
||||||
|
import moment from 'moment'
|
||||||
|
import 'moment/locale/zh-cn'
|
||||||
|
moment.locale('zh-cn')
|
||||||
|
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<div class="menus">
|
<div class="menus">
|
||||||
<el-button type="primary" :loading="isDownloading" @click="onDownload">导出全部数据</el-button>
|
<el-button type="primary" :loading="isDownloading" @click="onDownload">导出全部数据</el-button>
|
||||||
<el-switch
|
<el-switch
|
||||||
class="desensitive-switch"
|
class="desensitize-switch"
|
||||||
:model-value="isShowOriginData"
|
:model-value="isShowOriginData"
|
||||||
active-text="是否展示原数据"
|
active-text="是否展示原数据"
|
||||||
@input="onIsShowOriginChange"
|
@input="onIsShowOriginChange"
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<el-dialog v-model="downloadDialogVisible" title="导出确认" width="500" style="padding: 40px">
|
<el-dialog v-model="downloadDialogVisible" title="导出确认" width="500" style="padding: 40px">
|
||||||
<el-form :model="downloadForm" label-width="100px" label-position="left">
|
<el-form :model="downloadForm" label-width="100px" label-position="left">
|
||||||
<el-form-item label="导出内容">
|
<el-form-item label="导出内容">
|
||||||
<el-radio-group v-model="downloadForm.isDesensitive">
|
<el-radio-group v-model="downloadForm.isMasked">
|
||||||
<el-radio :value="true">脱敏数据</el-radio>
|
<el-radio :value="true">脱敏数据</el-radio>
|
||||||
<el-radio :value="false">原回收数据</el-radio>
|
<el-radio :value="false">原回收数据</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
@ -63,7 +63,7 @@ import EmptyIndex from '@/management/components/EmptyIndex.vue'
|
|||||||
import { getRecycleList } from '@/management/api/analysis'
|
import { getRecycleList } from '@/management/api/analysis'
|
||||||
import { noDataConfig } from '@/management/config/analysisConfig'
|
import { noDataConfig } from '@/management/config/analysisConfig'
|
||||||
import DataTable from '../components/DataTable.vue'
|
import DataTable from '../components/DataTable.vue'
|
||||||
import { createDownloadSurveyResponseTask, getDownloadTask } from '@/management/api/downloadTask'
|
import { createDownloadTask, getDownloadTask } from '@/management/api/downloadTask'
|
||||||
|
|
||||||
const dataTableState = reactive({
|
const dataTableState = reactive({
|
||||||
mainTableLoading: false,
|
mainTableLoading: false,
|
||||||
@ -78,8 +78,8 @@ const dataTableState = reactive({
|
|||||||
isDownloading: false,
|
isDownloading: false,
|
||||||
downloadDialogVisible: false,
|
downloadDialogVisible: false,
|
||||||
downloadForm: {
|
downloadForm: {
|
||||||
isDesensitive: true
|
isMasked: true,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const { mainTableLoading, tableData, isShowOriginData, downloadDialogVisible, isDownloading } =
|
const { mainTableLoading, tableData, isShowOriginData, downloadDialogVisible, isDownloading } =
|
||||||
@ -137,7 +137,7 @@ const init = async () => {
|
|||||||
const res = await getRecycleList({
|
const res = await getRecycleList({
|
||||||
page: dataTableState.currentPage,
|
page: dataTableState.currentPage,
|
||||||
surveyId: route.params.id,
|
surveyId: route.params.id,
|
||||||
isDesensitive: !dataTableState.tmpIsShowOriginData // 发起请求的时候,isShowOriginData还没改变,暂存了一个字段
|
isMasked: !dataTableState.tmpIsShowOriginData // 发起请求的时候,isShowOriginData还没改变,暂存了一个字段
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@ -162,10 +162,7 @@ const confirmDownload = async () => {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
isDownloading.value = true
|
isDownloading.value = true
|
||||||
const createRes = await createDownloadSurveyResponseTask({
|
const createRes = await createDownloadTask({ surveyId: route.params.id, isMasked: downloadForm.isMasked })
|
||||||
surveyId: route.params.id,
|
|
||||||
isDesensitive: downloadForm.isDesensitive
|
|
||||||
})
|
|
||||||
dataTableState.downloadDialogVisible = false
|
dataTableState.downloadDialogVisible = false
|
||||||
if (createRes.code === 200) {
|
if (createRes.code === 200) {
|
||||||
ElMessage.success(`下载文件计算中,可前往“下载中心”查看`)
|
ElMessage.success(`下载文件计算中,可前往“下载中心”查看`)
|
||||||
@ -237,7 +234,7 @@ const checkIsTaskFinished = (taskId) => {
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.desensitive-switch {
|
.desensitize-switch {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
27
web/src/management/pages/download/DownloadPage.vue
Normal file
27
web/src/management/pages/download/DownloadPage.vue
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<template>
|
||||||
|
<div class="question-list-root">
|
||||||
|
<TopNav></TopNav>
|
||||||
|
<div class="table-container">
|
||||||
|
<DownloadTaskList></DownloadTaskList>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import TopNav from '@/management/components/TopNav.vue';
|
||||||
|
import DownloadTaskList from './components/DownloadTaskList.vue'
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.question-list-root {
|
||||||
|
height: 100%;
|
||||||
|
background-color: #f6f7f9;
|
||||||
|
.table-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%; /* 确保容器宽度为100% */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -57,12 +57,6 @@ import { ElMessage, ElMessageBox } from 'element-plus'
|
|||||||
import { deleteDownloadTask, getDownloadTaskList } from '@/management/api/downloadTask'
|
import { deleteDownloadTask, getDownloadTaskList } from '@/management/api/downloadTask'
|
||||||
import { CODE_MAP } from '@/management/api/base'
|
import { CODE_MAP } from '@/management/api/base'
|
||||||
|
|
||||||
import moment from 'moment'
|
|
||||||
// 引入中文
|
|
||||||
import 'moment/locale/zh-cn'
|
|
||||||
// 设置中文
|
|
||||||
moment.locale('zh-cn')
|
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const pageSize = ref(10)
|
const pageSize = ref(10)
|
||||||
const total = ref(0)
|
const total = ref(0)
|
@ -1,103 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="question-list-root">
|
|
||||||
<div class="top-nav">
|
|
||||||
<div class="left">
|
|
||||||
<img class="logo-img" src="/imgs/Logo.webp" alt="logo" />
|
|
||||||
<el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal">
|
|
||||||
<el-menu-item index="1" @click="handleSurvey">问卷列表</el-menu-item>
|
|
||||||
<el-menu-item index="2">下载中心</el-menu-item>
|
|
||||||
</el-menu>
|
|
||||||
</div>
|
|
||||||
<div class="login-info">
|
|
||||||
您好,{{ userInfo?.username }}
|
|
||||||
<img class="login-info-img" src="/imgs/avatar.webp" />
|
|
||||||
<span class="logout" @click="handleLogout">退出</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="table-container">
|
|
||||||
<DownloadTaskList></DownloadTaskList>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref, computed } from 'vue'
|
|
||||||
import { useUserStore } from '@/management/stores/user'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import DownloadTaskList from './components/DownloadTaskList.vue'
|
|
||||||
|
|
||||||
const userStore = useUserStore()
|
|
||||||
const router = useRouter()
|
|
||||||
const userInfo = computed(() => {
|
|
||||||
return userStore.userInfo
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleSurvey = () => {
|
|
||||||
router.push('/survey')
|
|
||||||
}
|
|
||||||
const handleLogout = () => {
|
|
||||||
userStore.logout()
|
|
||||||
router.replace({ name: 'login' })
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeIndex = ref('2')
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.question-list-root {
|
|
||||||
height: 100%;
|
|
||||||
background-color: #f6f7f9;
|
|
||||||
.top-nav {
|
|
||||||
background: #fff;
|
|
||||||
color: #4a4c5b;
|
|
||||||
padding: 0 20px;
|
|
||||||
height: 56px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.04);
|
|
||||||
.left {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
width: calc(100% - 200px);
|
|
||||||
.logo-img {
|
|
||||||
width: 90px;
|
|
||||||
height: fit-content;
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
|
||||||
.el-menu {
|
|
||||||
width: 100%;
|
|
||||||
height: 56px;
|
|
||||||
border: none !important;
|
|
||||||
:deep(.el-menu-item, .is-active) {
|
|
||||||
border: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.login-info {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
.login-info-img {
|
|
||||||
margin-left: 10px;
|
|
||||||
height: 30px;
|
|
||||||
margin-top: -6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logout {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #faa600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.table-container {
|
|
||||||
margin-top: 20px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%; /* 确保容器宽度为100% */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,19 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="question-list-root">
|
<div class="question-list-root">
|
||||||
<div class="top-nav">
|
<TopNav></TopNav>
|
||||||
<div class="left">
|
|
||||||
<img class="logo-img" src="/imgs/Logo.webp" alt="logo" />
|
|
||||||
<el-menu :default-active="activeIndex" class="el-menu-demo" mode="horizontal">
|
|
||||||
<el-menu-item index="1">问卷列表</el-menu-item>
|
|
||||||
<el-menu-item index="2" @click="handleDownload">下载中心</el-menu-item>
|
|
||||||
</el-menu>
|
|
||||||
</div>
|
|
||||||
<div class="login-info">
|
|
||||||
您好,{{ userInfo?.username }}
|
|
||||||
<img class="login-info-img" src="/imgs/avatar.webp" />
|
|
||||||
<span class="logout" @click="handleLogout">退出</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="content-wrap">
|
<div class="content-wrap">
|
||||||
<SliderBar :menus="spaceMenus" @select="handleSpaceSelect" />
|
<SliderBar :menus="spaceMenus" @select="handleSpaceSelect" />
|
||||||
<div class="list-content">
|
<div class="list-content">
|
||||||
@ -80,6 +67,7 @@ import BaseList from './components/BaseList.vue'
|
|||||||
import SpaceList from './components/SpaceList.vue'
|
import SpaceList from './components/SpaceList.vue'
|
||||||
import SliderBar from './components/SliderBar.vue'
|
import SliderBar from './components/SliderBar.vue'
|
||||||
import SpaceModify from './components/SpaceModify.vue'
|
import SpaceModify from './components/SpaceModify.vue'
|
||||||
|
import TopNav from '@/management/components/TopNav.vue'
|
||||||
import { SpaceType } from '@/management/utils/types/workSpace'
|
import { SpaceType } from '@/management/utils/types/workSpace'
|
||||||
import { useUserStore } from '@/management/stores/user'
|
import { useUserStore } from '@/management/stores/user'
|
||||||
import { useWorkSpaceStore } from '@/management/stores/workSpace'
|
import { useWorkSpaceStore } from '@/management/stores/workSpace'
|
||||||
@ -93,16 +81,12 @@ const { surveyList, surveyTotal } = storeToRefs(surveyListStore)
|
|||||||
const { spaceMenus, workSpaceId, spaceType, workSpaceList, workSpaceListTotal } =
|
const { spaceMenus, workSpaceId, spaceType, workSpaceList, workSpaceListTotal } =
|
||||||
storeToRefs(workSpaceStore)
|
storeToRefs(workSpaceStore)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const userInfo = computed(() => {
|
|
||||||
return userStore.userInfo
|
|
||||||
})
|
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
const spaceListRef = ref<any>(null)
|
const spaceListRef = ref<any>(null)
|
||||||
const spaceLoading = ref(false)
|
const spaceLoading = ref(false)
|
||||||
|
|
||||||
const activeIndex = ref('1')
|
|
||||||
|
|
||||||
const fetchSpaceList = async (params?: any) => {
|
const fetchSpaceList = async (params?: any) => {
|
||||||
spaceLoading.value = true
|
spaceLoading.value = true
|
||||||
@ -181,67 +165,13 @@ const onSpaceCreate = () => {
|
|||||||
const onCreate = () => {
|
const onCreate = () => {
|
||||||
router.push('/create')
|
router.push('/create')
|
||||||
}
|
}
|
||||||
const handleLogout = () => {
|
|
||||||
userStore.logout()
|
|
||||||
router.replace({ name: 'login' })
|
|
||||||
}
|
|
||||||
// 下载页面
|
|
||||||
const handleDownload = () => {
|
|
||||||
router.push({ name: 'download' })
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.question-list-root {
|
.question-list-root {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #f6f7f9;
|
background-color: #f6f7f9;
|
||||||
|
|
||||||
.top-nav {
|
|
||||||
background: #fff;
|
|
||||||
color: #4a4c5b;
|
|
||||||
padding: 0 20px;
|
|
||||||
height: 56px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.04);
|
|
||||||
.left {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
width: calc(100% - 200px);
|
|
||||||
.logo-img {
|
|
||||||
width: 90px;
|
|
||||||
height: fit-content;
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
|
||||||
.el-menu {
|
|
||||||
width: 100%;
|
|
||||||
height: 56px;
|
|
||||||
border: none !important;
|
|
||||||
:deep(.el-menu-item, .is-active) {
|
|
||||||
border: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.login-info {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
.login-info-img {
|
|
||||||
margin-left: 10px;
|
|
||||||
height: 30px;
|
|
||||||
margin-top: -6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logout {
|
|
||||||
margin-left: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #faa600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.content-wrap {
|
.content-wrap {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: calc(100% - 56px);
|
height: calc(100% - 56px);
|
||||||
|
@ -32,7 +32,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
{
|
{
|
||||||
path: '/download',
|
path: '/download',
|
||||||
name: 'download',
|
name: 'download',
|
||||||
component: () => import('../pages/downloadTask/TaskList.vue'),
|
component: () => import('../pages/download/DownloadPage.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
needLogin: true
|
needLogin: true
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,8 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import 'moment/locale/zh-cn'
|
|
||||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||||
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
|
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
|
||||||
moment.locale('zh-cn')
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
formConfig: any
|
formConfig: any
|
||||||
|
@ -19,12 +19,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import 'moment/locale/zh-cn'
|
|
||||||
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
import zhCn from 'element-plus/es/locale/lang/zh-cn'
|
||||||
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
|
import { FORM_CHANGE_EVENT_KEY } from '@/materials/setters/constant'
|
||||||
|
|
||||||
moment.locale('zh-cn')
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
formConfig: any
|
formConfig: any
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,6 @@ import { useRouter } from 'vue-router'
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { pick } from 'lodash-es'
|
import { pick } from 'lodash-es'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
// 引入中文
|
|
||||||
import 'moment/locale/zh-cn'
|
|
||||||
// 设置中文
|
|
||||||
|
|
||||||
import { isMobile as isInMobile } from '@/render/utils/index'
|
import { isMobile as isInMobile } from '@/render/utils/index'
|
||||||
|
|
||||||
@ -16,7 +13,6 @@ import { useErrorInfo } from '@/render/stores/errorInfo'
|
|||||||
import adapter from '../adapter'
|
import adapter from '../adapter'
|
||||||
import { RuleMatch } from '@/common/logicEngine/RulesMatch'
|
import { RuleMatch } from '@/common/logicEngine/RulesMatch'
|
||||||
|
|
||||||
moment.locale('zh-cn')
|
|
||||||
/**
|
/**
|
||||||
* CODE_MAP不从management引入,在dev阶段,会导致B端 router被加载,进而导致C端路由被添加 baseUrl: /management
|
* CODE_MAP不从management引入,在dev阶段,会导致B端 router被加载,进而导致C端路由被添加 baseUrl: /management
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user