Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backend-todos-completed #177

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# chai aur backend series
# chai aur backend series

This is a video series on backend with javascript

- [Model link](https://app.eraser.io/workspace/YtPqZ1VogxGy1jzIDkzj?origin=share)

- [Video playlist](https://www.youtube.com/watch?v=EH3vGeqeIAo&list=PLu71SKxNbfoBGh_8p_NS-ZAh6v7HhYqHW)

---

# Summary of this project

This project is a complex backend project that is built with nodejs, expressjs, mongodb, mongoose, jwt, bcrypt, and many more. This project is a complete backend project that has all the features that a backend project should have.
Expand All @@ -14,11 +16,15 @@ We are building a complete video hosting website similar to youtube with all the
Project uses all standard practices like JWT, bcrypt, access tokens, refresh Tokens and many more. We have spent a lot of time in building this project and we are sure that you will learn a lot from this project.

---

Top Contributer to complete all TODOs

1. Spiderman (just sample) [Link to Repo](https://www.youtube.com/@chaiaurcode)
1. Spiderman (just sample) [Link to Repo](https://www.youtube.com/@chaiaurcode)

---

---
## How to contribute in this open source Project

First, please understand that this is not your regular project to merge your PR. This repo requires you to finish all assignments that are in controller folder. We don't accept half work, please finish all controllers and then reach us out on [Discord](https://hitesh.ai/discord) or [Twitter](https://twitter.com/@hiteshdotcom) and after checking your repo, I will add link to your repo in this readme.
First, please understand that this is not your regular project to merge your PR. This repo requires you to finish all assignments that are in controller folder. We don't accept half work, please finish all controllers and then reach us out on [Discord](https://hitesh.ai/discord) or [Twitter](https://twitter.com/@hiteshdotcom) and after checking your repo, I will add link to your repo in this readme.

#171
168 changes: 146 additions & 22 deletions src/controllers/comment.controller.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,155 @@
import mongoose from "mongoose"
import {Comment} from "../models/comment.model.js"
import {ApiError} from "../utils/ApiError.js"
import {ApiResponse} from "../utils/ApiResponse.js"
import {asyncHandler} from "../utils/asyncHandler.js"
import mongoose from "mongoose";
import { Comment } from "../models/comment.model.js";
import { Video } from "../models/video.model.js";
import { ApiError } from "../utils/ApiError.js";
import { ApiResponse } from "../utils/ApiResponse.js";
import { asyncHandler } from "../utils/asyncHandler.js";

const getVideoComments = asyncHandler(async (req, res) => {
//TODO: get all comments for a video
const {videoId} = req.params
const {page = 1, limit = 10} = req.query
//TODO: get all comments for a video
const { videoId } = req.params;
const { page = 1, limit = 10 } = req.query;
const video = await Video.findById(videoId);
if (!video) {
throw new ApiError(404, "Video not found");
}
const options = {
page,
limit,
};
const comments = await Comment.aggregate([
{
$match: {
video: new mongoose.Types.ObjectId(videoId),
},
},
{
$lookup: {
from: "users",
localField: "owner",
foreignField: "_id",
as: "createdBy",
pipeline: [
{
$project: {
username: 1,
fullName: 1,
avatar: 1,
},
},
],
},
},
{
$addFields: {
createdBy: {
$first: "$createdBy",
},
},
},
{
$unwind: "$createdBy",
},
{
$project: {
content: 1,
createdBy: 1,
},
},
{
$skip: (page - 1) * limit,
},
{
$limit: parseInt(limit),
},
]);

})
return res
.status(200)
.json(new ApiResponse(200, comments, "Comments Fetched"));
});

const addComment = asyncHandler(async (req, res) => {
// TODO: add a comment to a video
})
// TODO: add a comment to a video
const { videoId } = req.params;
const { content } = req.body;
const user = req.user._id;
if (!content) {
throw new ApiError(400, "Comment content is missing");
}
const video = await Video.findById(videoId);
if (!video) {
throw new ApiError(404, "Video not found");
}
const comment = await Comment.create({
content,
video: videoId,
owner: user,
});
if (!comment) {
throw new ApiError(500, "Error while saving the comment");
}

return response
.status(200)
.json(new ApiResponse(200, comment, "Comment Saved"));
});

const updateComment = asyncHandler(async (req, res) => {
// TODO: update a comment
})
// TODO: update a comment
const { content } = req.body;
if (!content) {
throw new ApiError(400, "Comment content is required");
}
const { commentId } = req.params;
const user = req.user._id;
const originalComment = await Comment.findById(commentId);
if (!originalComment) {
throw new ApiError(404, "Comment not found");
}
if (originalComment.owner !== user) {
throw new ApiError(403, "You don't have permission to update this comment");
}

const updateComment = await Comment.findByIdAndUpdate(
commentId,
{
$set: {
content,
},
},
{ new: true }
);

if (!updateComment) {
throw new ApiError(500, "Error while updating comment");
}

return res
.status(200)
.json(new ApiResponse(200, updateComment, "Comment updated"));
});

const deleteComment = asyncHandler(async (req, res) => {
// TODO: delete a comment
})

export {
getVideoComments,
addComment,
updateComment,
deleteComment
}
// TODO: delete a comment
const { commentId } = req.params;
const user = req.user._id;
const comment = await Comment(findById(commentId));
if (!comment) {
throw new ApiError(404, "Comment not found");
}
if (comment.owner !== user) {
throw new ApiError(404, "You don't have permission to delete this comment");
}

const deleteComment = await Comment.findByIdAndDelete(commentId);
if (!deleteComment) {
throw new ApiError(500, "Error while deleting comment");
}

return res
.status(200)
.json(new ApiResponse(200, deleteComment, "Comment deleted"));
});

export { getVideoComments, addComment, updateComment, deleteComment };
165 changes: 150 additions & 15 deletions src/controllers/dashboard.controller.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,155 @@
import mongoose from "mongoose"
import {Video} from "../models/video.model.js"
import {Subscription} from "../models/subscription.model.js"
import {Like} from "../models/like.model.js"
import {ApiError} from "../utils/ApiError.js"
import {ApiResponse} from "../utils/ApiResponse.js"
import {asyncHandler} from "../utils/asyncHandler.js"
import mongoose from "mongoose";
import { Video } from "../models/video.model.js";
import { Subscription } from "../models/subscription.model.js";
import { Like } from "../models/like.model.js";
import { ApiError } from "../utils/ApiError.js";
import { ApiResponse } from "../utils/ApiResponse.js";
import { asyncHandler } from "../utils/asyncHandler.js";

const getChannelStats = asyncHandler(async (req, res) => {
// TODO: Get the channel stats like total video views, total subscribers, total videos, total likes etc.
})
// TODO: Get the channel stats like total video views, total subscribers, total videos, total likes etc.
const userId = req.user._id;
const videoCount = await Video.aggregate([
{
$match: {
owner: new mongoose.Types.ObjectId(userId),
},
},
{
$group: {
_id: "$videoFile",
totalViews: {
$sum: "$views",
},
totalVideos: {
$sum: 1,
},
},
},
{
$project: {
_id: 0,
totalViews: 1,
totalVideos: 1,
},
},
]);

const subsCount = await Subscription.aggregate([
{
$match: {
channel: new mongoose.Types.ObjectId(userId),
},
},
{
$group: {
_id: null,
totalSubscribers: {
$sum: 1,
},
},
},
{
$project: {
_id: 0,
totalSubscribers: 1,
},
},
]);

const likeCount = await Like.aggregate([
{
$lookup: {
from: "videos",
localField: "video",
foreignField: "_id",
as: "videoInfo",
},
},
{
$lookup: {
from: "tweets",
localField: "tweet",
foreignField: "_id",
as: "tweetInfo",
},
},
{
$lookup: {
from: "comments",
localField: "comment",
foreignField: "_id",
as: "commentInfo",
},
},
{
$match: {
$or: [
{
"videoInfo.owner": userId,
},
{
"tweetInfo.owner": userId,
},
{
"commentInfo.owner": userId,
},
],
},
},
{
$group: {
_id: null,
totalLikes: { $sum: 1 },
},
},
{
$project: {
_id: 0,
totalLikes: 1,
},
},
]);

const info = {
totalViews: videoCount[0].totalViews,
totalVideos: videoCount[0].totalVideos,
totalSubscribers: subsCount[0].totalSubscribers,
totalLikes: likeCount[0].totalLikes,
};

return res
.status(200)
.json(new ApiResponse(200, info, "Channel Stats Fetched"));
});

const getChannelVideos = asyncHandler(async (req, res) => {
// TODO: Get all the videos uploaded by the channel
})
// TODO: Get all the videos uploaded by the channel
const userId = req.user._id;
const videos = await Video.aggregate([
{
$match: {
owner: new mongoose.Types.ObjectId(userId),
},
},
{
$project: {
videoFile: 1,
thumbnail: 1,
title: 1,
duration: 1,
views: 1,
isPublished: 1,
owner: 1,
createdAt: 1,
updatedAt: 1,
},
},
]);

return res
.status(200)
.json(new ApiResponse(200, videos, "Channel Videos Fetched"));
});

export {
getChannelStats,
getChannelVideos
}
export { getChannelStats, getChannelVideos };
Loading