Skip to content

Commit

Permalink
Dev - add questions into response of draft exam & hide user informati…
Browse files Browse the repository at this point in the history
…on if required (#153)



* feat/#146 (#151)

* feat: [add questions into response of draft exam]

---------

Co-authored-by: Loc Xuan Dao <102164071+locxuandao@users.noreply.github.com>
Co-authored-by: dungnguyenn1103 <91179133+DungNguyen2003@users.noreply.github.com>
  • Loading branch information
3 people authored Mar 27, 2023
1 parent b15604f commit abc8d2b
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 14 deletions.
8 changes: 5 additions & 3 deletions src/apis/v1/documents/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const getDocuments = async (urlParams: URLParams) => {
.skip(pageSize * currentPage)
.limit(pageSize)
.sort({ created_at: order === 'DESC' ? -1 : 1 })
.populate('author', '-is_blocked -roles -created_at -updated_at -__v')
.populate('author', '-is_deleted -is_blocked -roles -created_at -updated_at -__v')
.populate('subject', '-is_deleted -created_at -updated_at -__v');

logger.info(`Get all documents successfully`);
Expand Down Expand Up @@ -147,7 +147,7 @@ export const getDocumentsByAdmin = async (filter: DocumentFilter, urlParams: URL
.skip(pageSize * currentPage)
.limit(pageSize)
.sort({ created_at: order === 'DESC' ? -1 : 1 })
.populate('author', '-is_blocked -roles -created_at -updated_at -__v')
.populate('author', '-is_deleted -is_blocked -roles -created_at -updated_at -__v')
.populate('subject', '-is_deleted -created_at -updated_at -__v');

logger.info(`Get all documents successfully`);
Expand Down Expand Up @@ -179,7 +179,9 @@ export const getDocumentsBySubjectId = async (subjectId: string) => {

logger.info(`Get all documents by subjectId successfully`);
return {
documents: resultAll[0],
documents: resultAll[0].map((documents: any) => {
return { ...documents.toObject(), author: hideUserInfoIfRequired(documents?.author) };
}),
subject: resultAll[1],
};
} catch (error) {
Expand Down
7 changes: 7 additions & 0 deletions src/apis/v1/exam/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,10 @@ export const deleteExam = async (req: RequestWithUser, res: Response) => {

res.send(fmt.formatResponse(result, Date.now() - req.startTime, 'OK'));
};

export const getDraftExam = async (req: RequestWithUser, res: Response) => {
const author = req?.user?._id;
const result = await service.getDraftExam(String(author));

res.send(fmt.formatResponse(result, Date.now() - req.startTime, 'OK'));
};
2 changes: 2 additions & 0 deletions src/apis/v1/exam/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const router = Router();

router.get('/', authMiddleware, asyncRouteHandler(controller.getExams));

router.get('/draft-exam', authMiddleware, asyncRouteHandler(controller.getDraftExam));

router.get(
'/:id',
authMiddleware,
Expand Down
78 changes: 74 additions & 4 deletions src/apis/v1/exam/service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { ObjectId } from 'mongodb';
import { ObjectId as ObjectIdType } from 'mongoose';
import { ObjectId as ObjectIdType, PipelineStage } from 'mongoose';
import { ErrorCodes, HttpException } from 'exceptions';
import { ExamModel } from 'models';
import { DEFAULT_PAGING } from 'utils/constants';
import { logger } from 'utils/logger';
import URLParams from 'utils/rest/urlparams';
import { ExamDto, UpdateExamByAdminDto, UpdateExamByOwnerDto } from './dto/ExamDto';
import { hideUserInfoIfRequired } from 'utils';

//Get all user's exams
export const getExams = async (urlParams: URLParams) => {
Expand Down Expand Up @@ -71,7 +72,9 @@ export const getExams = async (urlParams: URLParams) => {

const resolveAll = await Promise.all([count, data]);
return {
result: resolveAll[1],
result: resolveAll[1].map((exam: any) => {
return { ...exam, author: hideUserInfoIfRequired(exam?.author[0]) };
}),
meta: {
total: resolveAll[0],
pageSize,
Expand Down Expand Up @@ -131,6 +134,8 @@ export const getExamById = async (id: string) => {
_id: '$author._id',
fullname: '$author.fullname',
email: '$author.email',
nickname: '$author.nickname',
is_show_info: '$author.is_show_info',
},
subject: {
_id: '$subject._id',
Expand All @@ -155,7 +160,10 @@ export const getExamById = async (id: string) => {
},
]);

return data[0];
return {
...data[0],
author: hideUserInfoIfRequired(data[0].author),
};
} catch (error) {
logger.error(`Error while get exam: ${error}`);
throw new HttpException(400, error, ErrorCodes.BAD_REQUEST.CODE);
Expand Down Expand Up @@ -228,7 +236,9 @@ export const getExamsBySubjectId = async (subjectId: string, urlParams: URLParam
const resolveAll = await Promise.all([count, data]);

return {
result: resolveAll[1],
result: resolveAll[1].map((exam: any) => {
return { ...exam, author: hideUserInfoIfRequired(exam?.author[0]) };
}),
meta: {
total: resolveAll[0],
pageSize,
Expand All @@ -247,6 +257,15 @@ export const createExam = async (input: ExamDto, author: ObjectIdType) => {
author,
...input,
};
const DraftExamExist = await ExamModel.findOne({
author,
is_draft: true,
}).sort({ created_at: -1 });

if (DraftExamExist) {
return DraftExamExist;
}

const data = await ExamModel.create(exam);

return data;
Expand Down Expand Up @@ -303,3 +322,54 @@ export const updateExamByAdmin = async (examId: string, input: UpdateExamByAdmin
throw new HttpException(400, ErrorCodes.BAD_REQUEST.MESSAGE, ErrorCodes.BAD_REQUEST.CODE);
}
};

export const getDraftExam = async (author: string) => {
try {
const _id = new ObjectId(author);

const pipeline: PipelineStage[] = [
{
$match: { author: _id, is_draft: true },
},
{
$lookup: {
from: 'question',
localField: '_id',
foreignField: 'exam_id',
as: 'questions',
},
},
{
$project: {
_id: 1,
title: 1,
description: 1,
questions: {
$map: {
input: '$questions',
as: 'question',
in: {
_id: '$$question._id',
content: '$$question.content',
image: '$$question.image',
correct_answer: '$$question.correct_answer',
answers: '$$question.answers',
is_essay: '$$question.is_essay',
accuracy: '$$question.accuracy',
},
},
},
},
},
{
$sort: { created_at: -1 },
},
];
const data = await ExamModel.aggregate(pipeline);

return data[0];
} catch (error) {
logger.error(`Error while create exam: ${error}`);
throw new HttpException(400, ErrorCodes.BAD_REQUEST.MESSAGE, ErrorCodes.BAD_REQUEST.CODE);
}
};
9 changes: 8 additions & 1 deletion src/apis/v1/user/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import RequestWithUser from 'utils/rest/request';
import * as service from './service';
import fmt from 'utils/formatter';

import { UserDto, UpdateUserDto, ParamsUserDto } from './dto/UserDto';
import { UserDto, UpdateUserDto, ParamsUserDto, QueryUserDto } from './dto/UserDto';
import URLParams from 'utils/rest/urlparams';

export const createUser = async (request: RequestWithUser, response: Response) => {
Expand Down Expand Up @@ -35,3 +35,10 @@ export const deleteUser = async (request: RequestWithUser, response: Response) =
const result = await service.deleteUser(params.id);
response.send(fmt.formatResponse(result, Date.now() - request.startTime, 'OK'));
};

export const getUserByEmail = async (req: RequestWithUser, res: Response) => {
const query: QueryUserDto = req.query;

const result = await service.getUserByEmail(query.email);
res.send(fmt.formatResponse(result, Date.now() - req.startTime, 'OK'));
};
21 changes: 21 additions & 0 deletions src/apis/v1/user/dto/UserDto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ export class UserDto {
@IsOptional()
@IsString()
role: string;

@IsOptional()
@IsString()
nickname: string;

@IsOptional()
@IsBoolean()
is_show_info: boolean;
}

export class UpdateUserDto {
Expand All @@ -34,9 +42,22 @@ export class UpdateUserDto {
@IsOptional()
@IsString()
role: string;

@IsOptional()
@IsString()
nickname: string;

@IsOptional()
@IsBoolean()
is_show_info: boolean;
}
export class ParamsUserDto {
@IsString()
@IsDefined()
id: string;
}
export class QueryUserDto {
@IsString()
@IsOptional()
email?: string;
}
1 change: 1 addition & 0 deletions src/apis/v1/user/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ router.post(
asyncRouteHandler(controller.createUser)
);
router.get('/', authMiddleware, adminMiddleware, asyncRouteHandler(controller.getUsers));
router.get('/email', authMiddleware, adminMiddleware, asyncRouteHandler(controller.getUserByEmail));

router.put(
'/:id',
Expand Down
7 changes: 3 additions & 4 deletions src/apis/v1/user/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { logger } from 'utils/logger';
import { UserDto, UpdateUserDto } from './dto/UserDto';
import URLParams from 'utils/rest/urlparams';
import { DEFAULT_PAGING } from 'utils/constants';
import { hideUserInfoIfRequired } from 'utils';

export const createUser = async function (input: UserDto) {
try {
Expand Down Expand Up @@ -76,7 +77,7 @@ export const getUserById = async function (id: ObjectId) {
export const getUserByEmail = async function (email: string) {
try {
const user = await UserModel.findOne({ email });
return user;
return hideUserInfoIfRequired(user);
} catch (error) {
logger.error(`Error while get user by email: ${error}`);
throw new HttpException(400, ErrorCodes.BAD_REQUEST.MESSAGE, ErrorCodes.BAD_REQUEST.CODE);
Expand All @@ -88,9 +89,7 @@ export const updateUser = async function (input: UpdateUserDto, id: string) {
const users = await UserModel.findOneAndUpdate(
{ _id: id },
{
fullname: input.fullname,
roles: input.role,
is_blocked: input.is_blocked,
$set: input,
}
);
logger.info(`Update for user have id: ${id} successfully`);
Expand Down
9 changes: 7 additions & 2 deletions src/apis/v1/userExam/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import URLParams from 'utils/rest/urlparams';
import { DEFAULT_PAGING } from 'utils/constants';
import UserExam from 'models/types/UserExam';

import { hideUserInfoIfRequired } from 'utils';

export const createUserExam = async (input: UserExamDto, author: ObjectIdType) => {
try {
const exam = await getExamById(input.exam_id);
Expand Down Expand Up @@ -238,7 +240,9 @@ export const getAllUserExamsByOwner = async (userId: string, filter: UserExamFil
pageSize,
currentPage,
},
result: resolveAll[1],
result: resolveAll[1].map((userExam: any) => {
return { ...userExam, author: hideUserInfoIfRequired(userExam?.author[0]) };
}),
};
} catch (error) {
logger.error(`Error while get all user exams : ${error}`);
Expand Down Expand Up @@ -302,7 +306,7 @@ export const getUserExamByOwner = async (userEmail: string, userExamId: string)
}

if (userExam[0]?.is_completed) {
return userExam[0];
return { ...userExam[0], author: hideUserInfoIfRequired(userExam[0]?.author) };
}

//duration is in milliseconds
Expand All @@ -329,6 +333,7 @@ export const getUserExamByOwner = async (userEmail: string, userExamId: string)
_id: question._id,
};
}),
author: hideUserInfoIfRequired(userExam[0]?.author),
};
} catch (error) {
logger.error(`Error while get userExam of user : ${error}`);
Expand Down

0 comments on commit abc8d2b

Please sign in to comment.