Skip to content

Instantly share code, notes, and snippets.

@dosandk
Created April 12, 2023 09:11
Show Gist options
  • Select an option

  • Save dosandk/77916b2466818493dab927f47e778892 to your computer and use it in GitHub Desktop.

Select an option

Save dosandk/77916b2466818493dab927f47e778892 to your computer and use it in GitHub Desktop.
import { HttpException, HttpStatus, Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model, Types } from 'mongoose';
import { TaskDto } from './dto/task.dto';
import { Task } from './types/task.interface';
import { Track } from '../tracks/types/track.interface';
import { User } from '../users/types/user.interface';
import { TaskInProgress } from './types/task-in-progress.interface';
import { SaveTaskProgressDto } from './dto/save-task-progress.dto';
import { AddCommentDto } from './dto/comments/add-comment.dto';
import { DeleteCommentDto } from './dto/comments/delete-comment.dto';
import { UpdateCommentDto } from './dto/comments/update-comment.dto';
import { UserUpdate } from 'src/users/dto/user-update.dto';
import { UsersRepository } from 'src/users/users.repository';
import { TasksInProgressRepository } from './tasks-in-progress.repository';
import { reviewStatuses } from './models/task-in-progress.model';
import { TASKS_RESPONSE_MESSAGES, USER_RESPONSE_MESSAGES } from 'src/shared/constants';
@Injectable()
export class TasksService {
constructor(
@InjectModel('Track') private readonly trackModel: Model<Track>,
@InjectModel('Task') private readonly taskModel: Model<Task>,
@InjectModel('Comment') private readonly commentModel: Model<Comment>,
private userRepository: UsersRepository,
private tasksInProgressRepository: TasksInProgressRepository
) {}
async findAll({ skip, limit }): Promise<Task[]> {
return await this.taskModel.find({}, null, { skip, limit });
}
async create(task: TaskDto): Promise<Task> {
const { trackId } = task;
const track = await this.trackModel.findOne({ trackId }).exec();
const newTask = new this.taskModel({
...task
});
const taskDocument = await newTask.save();
if (track) {
track.tasks.push(taskDocument._id);
await track.save();
}
return taskDocument;
}
getUserMentorId(user: User) {
const userMentorId = user.mentor;
if (!userMentorId) {
throw new HttpException(USER_RESPONSE_MESSAGES.userWithoutMentor, HttpStatus.BAD_REQUEST);
}
return userMentorId;
}
async findTaskInProgressByUserAndTaskIds(
taskId: string,
userId: string
): Promise<TaskInProgress> {
return this.tasksInProgressRepository.findOne({ taskId, userId });
}
async updateUserInProgressTasks(
task: Task,
user: User,
saveTaskProgressDto: SaveTaskProgressDto
): Promise<TaskInProgress> {
const newTaskInProgress = await this.createTaskInProgress(task, user, saveTaskProgressDto);
const userUpdates = [
{
key: 'tasksInProgress',
value: [...user.tasksInProgress, newTaskInProgress._id]
}
];
await this.updateUser(user._id, userUpdates);
return newTaskInProgress;
}
async updateTaskInProgress({
taskInProgress,
saveTaskProgressDto,
mentorId,
tasksStatus
}: any): Promise<TaskInProgress> {
const { solutionCode, isCompleted, taskName } = saveTaskProgressDto;
taskInProgress.solutionCode = solutionCode;
taskInProgress.isCompleted = isCompleted;
taskInProgress.taskName = taskName;
if (mentorId) {
taskInProgress.reviewer = mentorId;
}
if (tasksStatus) {
taskInProgress.isReviewedByMentor = tasksStatus;
}
return taskInProgress.save();
}
async createTaskInProgress(
task: Task,
user: User,
saveTaskProgressDto: SaveTaskProgressDto
): Promise<TaskInProgress> {
const { solutionCode, isCompleted, isReviewedByMentor, reviewer, taskName } = saveTaskProgressDto;
const newTaskInProgress = await this.tasksInProgressRepository.create({
userId: user._id,
taskId: task._id,
solutionCode,
isCompleted,
isReviewedByMentor: isReviewedByMentor || reviewStatuses.Null,
reviewer,
taskName
});
return newTaskInProgress;
}
// TODO: rename
async foo (saveTaskProgressDto) {
const [task, user] = await Promise.all([
this.taskModel.findOne({ taskId: saveTaskProgressDto.taskName }),
this.userRepository.findOne({ _id: new Types.ObjectId(saveTaskProgressDto.userId) })
]);
return [task, user];
}
async saveProgress(saveTaskProgressDto: SaveTaskProgressDto): Promise<TaskInProgress> {
const [task, user] = await this.foo(saveTaskProgressDto);
const taskInProgress = await this.findTaskInProgressByUserAndTaskIds(task._id, user._id);
if (taskInProgress) {
return this.updateTaskInProgress({ taskInProgress, saveTaskProgressDto });
}
return this.updateUserInProgressTasks(task, user, saveTaskProgressDto);
}
async getTaskInProgressByUserId(taskName: string, userId: string) {
const taskInProgress = await this.tasksInProgressRepository.findOne({
userId: new Types.ObjectId(userId),
taskName
});
if (!taskInProgress) {
throw new HttpException(TASKS_RESPONSE_MESSAGES.taskNotFound, HttpStatus.BAD_REQUEST);
}
return taskInProgress;
}
async sendTaskToReview(saveTaskProgressDto: SaveTaskProgressDto): Promise<TaskInProgress> {
const [task, user] = await this.foo(saveTaskProgressDto);
const mentorId = this.getUserMentorId(user);
const taskInProgress = await this.findTaskInProgressByUserAndTaskIds(task._id, user._id);
if (taskInProgress) {
return this.updateTaskInProgress({
taskInProgress,
saveTaskProgressDto,
mentorId,
reviewStatuses: reviewStatuses.InPending
});
}
// createUserTaskInProgress
return this.updateUserInProgressTasks(task, user, saveTaskProgressDto);
}
async getTasksInReviewForMentor(mentorId: string) {
const tasksInReview = await this.tasksInProgressRepository.find({
reviewer: new Types.ObjectId(mentorId),
isReviewedByMentor: reviewStatuses.InPending
});
if (!tasksInReview) {
throw new HttpException(TASKS_RESPONSE_MESSAGES.tasksNotFound, HttpStatus.BAD_REQUEST);
}
return tasksInReview;
}
async getComments(userId: string, taskId: string): Promise<Comment[]> {
const task = await this.getUserTask(userId, taskId);
return (await task.populate('comments')).comments as Comment[];
}
async addComment({ userId, taskId, body }: AddCommentDto): Promise<TaskInProgress> {
const task = await this.getUserTask(userId, taskId);
const comment = new this.commentModel({
taskId: task._id,
date: new Date().toISOString(),
body
});
const commentDoc = await comment.save();
(task.comments as Types.ObjectId[]).push(commentDoc._id);
return await task.save();
}
async deleteComment({ userId, taskId, commentId }: DeleteCommentDto): Promise<TaskInProgress> {
await this.commentModel.findByIdAndDelete(commentId);
return await this.tasksInProgressRepository.findOneAndUpdate(
{ userId, taskId },
{ $pull: { comments: commentId } },
{ new: true }
);
}
async updateComment({ commentId, body }: UpdateCommentDto): Promise<Comment> {
return await this.commentModel.findByIdAndUpdate(
commentId,
{ body, date: new Date().toISOString() },
{ new: true }
);
}
async getUserTasks(
userId: string,
{ isMetadata, isCompleted }: { isMetadata?: boolean; isCompleted?: boolean }
): Promise<TaskInProgress[]> {
const populateOptions = {
path: 'tasksInProgress',
populate: {
path: 'taskId'
}
};
if (isCompleted !== undefined) {
populateOptions['match'] = { isCompleted };
}
if (isMetadata) {
populateOptions['select'] = { userId: 0, __v: 0 };
}
const user = await this.userRepository.findOne({ _id: new Types.ObjectId(userId) });
const populatedUser = await user.populate(populateOptions);
return populatedUser.tasksInProgress as TaskInProgress[];
}
async getUserTask(userId: string, taskId: string): Promise<TaskInProgress> {
const tasks: any[] = await this.getUserTasks(userId, { isMetadata: false });
return tasks.find(task => task.taskId._id.toString() === taskId);
}
private async updateUser(userId: string, updates: UserUpdate[]): Promise<User> {
const currentUser = await this.userRepository.findOne({ _id: new Types.ObjectId(userId) });
if (!currentUser) {
throw new NotFoundException(`There isn't any user with id: ${userId}`);
}
updates.forEach(({ key, value }) => (currentUser[key] = value));
return await currentUser.save();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment