Skip to content

Commit

Permalink
Progress: Made the dashboard front
Browse files Browse the repository at this point in the history
  • Loading branch information
Shubham-Guptaji committed Jun 9, 2024
1 parent 37118fc commit 474dd6a
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 27 deletions.
13 changes: 7 additions & 6 deletions controllers/blog.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -646,14 +646,12 @@ export const UpdatePost = asyncHandler(async function (req, res, next) {

export const DeletePost = asyncHandler(async function (req, res, next) {
const { id } = req.params;
const { authorId } = req.body;

if (req.user.id !== authorId && req.user.role !== "admin") {
const post = await Blog.findById(id);
if (req.user.id !== post.author.toString() && req.user.role !== "admin") {
return next(new AppError('You do not have permission to perform this action', 403));
}

const post = await Blog.findOne({ _id: id, author: authorId })

// Check if the post exists
if (!post) return next(new AppError("Your Post not found", 404));

Expand All @@ -665,7 +663,8 @@ export const DeletePost = asyncHandler(async function (req, res, next) {
} catch (error) {
return next(new AppError("Error deleting post resources", 500));
}

const postlikes = post.likes;
const postcomments = post.comments.length;
// Delete the post from the database
await Blog.findByIdAndDelete(id);
await Comment.deleteMany({ blog: id });
Expand All @@ -674,7 +673,9 @@ export const DeletePost = asyncHandler(async function (req, res, next) {

// Remove the post ID from the user's blogs array
await User.findByIdAndUpdate(req.user.id, {
$pull: { blogs: post._id }
$pull: { blogs: post._id },
$inc: { likes: -postlikes },
$inc: { comments: -postcomments }
}).exec();

// Respond with success message and post details
Expand Down
4 changes: 4 additions & 0 deletions controllers/comments.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const CreateComment = asyncHandler(async function (req, res, next) {
// Save the comment and the blog
await mycomment.save();
await commentToBlog.save();
await User.findByIdAndUpdate(commentToBlog.author, { $inc: { comments: 1 } }, { new: true });

// Send success response
res.status(201).json({
Expand Down Expand Up @@ -134,13 +135,16 @@ export const deleteComment = async (req, res, next) => {
}

// Delete the comment and remove its reference from the associated blog
commentAuthor = comment.blogAuthor;
await Promise.all([
comment.deleteOne(),
Blog.updateOne(
{ _id: comment.blog },
{ $pull: { comments: commentId } }
)
]);

await User.findByIdAndUpdate(commentAuthor, { $inc: { comments: -1 } }, { new: true });

// Response for comment
res.status(200).json({
Expand Down
12 changes: 9 additions & 3 deletions controllers/miscellaneous.controllers.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ export const followUser = asyncHandler(async function (req, res, next) {
user: req.user.id
});
}

// Check if follow document was created successfully
if (!follow) {
return next(new AppError("Your request couldn't be processed", 500));
Expand All @@ -225,6 +224,7 @@ export const followUser = asyncHandler(async function (req, res, next) {
// Increment followers count for the followed author directly
author.followers += 1;
await author.save();
await User.findByIdAndUpdate(req.user.id, { $inc: { following: 1 } }, { new: true });

// Send a success response
res.status(200).json({
Expand Down Expand Up @@ -464,6 +464,7 @@ export const unfollowUser = asyncHandler(async function (req, res, next) {
// Decrement the followers count for the author
const userUpdate = await User.findByIdAndUpdate(follow.author, { $inc: { followers: -1 } });
await userUpdate.save();
await User.findByIdAndUpdate(req.user.id, { $inc: { following: -1 } }, { new: true });

// Return the success response
res.status(200).json({
Expand Down Expand Up @@ -534,7 +535,7 @@ export const LikePost = asyncHandler(async function (req, res, next) {
// If the blog is not found, return an error
return next(new AppError('Blog not found!', 404));
}

await User.findByIdAndUpdate(blog.author, { $inc: { likes: 1 } }, { new: true });
// Create a new like
await Like.create({ blog: postId, user: req.user.id, author: blog.author });

Expand Down Expand Up @@ -574,9 +575,14 @@ export const UnLikePost = asyncHandler(async function (req, res, next) {
console.log(err);
});

if (!blog) {
// If the blog is not found, return an error
return next(new AppError('Blog not found!', 404));
}

// Delete the like information from the database
await Like.findByIdAndDelete(likeInfo._id);

await User.findByIdAndUpdate(blog.author, { $inc: { likes: -1 } }, {new: true})
// Return the updated info to the client side
res.status(200).json({
status: true,
Expand Down
128 changes: 112 additions & 16 deletions controllers/user.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Follower from "../models/follower.model.js";
import Blog from "../models/blog.model.js";
import Comment from "../models/comment.model.js";
import Resourcefile from "../models/resources.model.js";
import mongoose from "mongoose";

const CookieOptions = {
secure: process.env.NODE_ENV === "production" ? true : false,
Expand Down Expand Up @@ -43,6 +44,24 @@ const generateAccessAndRefreshTokens = async (userId) => {
}
}

const getWeeklyPartitions = (numberOfWeeks = 8) => {
const today = new Date();
const weeks = [];
// Calculate start date for the last 7 weeks (considering today)
const startOfWeek = new Date(today);
startOfWeek.setDate(today.getDate() - (today.getDay() || 7) + 1 - numberOfWeeks * 7);

while (startOfWeek < today) {
const endOfWeek = new Date(startOfWeek);
endOfWeek.setDate(startOfWeek.getDate() + 7);

weeks.push({ start: new Date(startOfWeek), end: new Date(endOfWeek) });

startOfWeek.setDate(startOfWeek.getDate() + 7);
}
return weeks;
}



/**
Expand Down Expand Up @@ -313,21 +332,21 @@ export const refreshAccessToken = asyncHandler(async (req, res, next) => {


// Finding the User in Database by username and if found then compare password
const user = await User.findById(decodedToken.id);
const user = await User.findById(decodedToken.id);

// Checking if the user has been blocked by admin
if (user.isBlocked) {
return next(
new AppError(`Your account has been blocked. Please contact support`, 403)
);
}
// Checking if the user has been blocked by admin
if (user.isBlocked) {
return next(
new AppError(`Your account has been blocked. Please contact support`, 403)
);
}

// Checking if the user's account is closed, then open it again
if (user.isClosed) {
user.isClosed = false;
await user.save();
user.info = "Account reopened successfully.";
}
// Checking if the user's account is closed, then open it again
if (user.isClosed) {
user.isClosed = false;
await user.save();
user.info = "Account reopened successfully.";
}

// Returning the response
return res
Expand Down Expand Up @@ -595,6 +614,29 @@ export const userProfile = asyncHandler(async function (req, res, next) {
];

// If the requesting user is not the same as the requested user and not an admin, filter unpublished posts

pipeline.push(
{
$set: {
publishedPosts: {
$filter: {
input: "$blogPosts",
as: "mypost",
cond: { $eq: ["$$mypost.isPublished", true] }
}
}
}
},
{
$set: {
postPublished: {
$size: "$publishedPosts"
}
}
}
);


if (req.user.username !== username && req.user.role !== "admin") {
pipeline.push(
{
Expand All @@ -620,7 +662,16 @@ export const userProfile = asyncHandler(async function (req, res, next) {

// Add projection stage to limit the number of returned posts to 20
pipeline.push(

{
$set: {
blogPosts: {
$sortArray: {
input: "$blogPosts",
sortBy: { createdAt: -1 }
}
}
}
},
{
$project: {
username: 1,
Expand All @@ -632,8 +683,12 @@ export const userProfile = asyncHandler(async function (req, res, next) {
role: 1,
isClosed: 1,
isBlocked: 1,
postPublished: 1,
createdAt: 1,
followers: 1,
following: 1,
likes: 1,
comments: 1,
isVerified: 1,
blogPosts: { $slice: ["$blogPosts", skip, limit] },
totalPosts: 1,
Expand Down Expand Up @@ -702,6 +757,47 @@ export const userProfile = asyncHandler(async function (req, res, next) {
});
});

/**
* @authChartData
* @Route {{server}}/user/profile/chartdata
* @Method get
* @Access private ( logged in users only )
*/

export const authChartData = asyncHandler(async function (req, res, next) {
try {
const authorId = req.user.id;
const weeks = getWeeklyPartitions();

const likesData = [];
const followersData = [];
for (const week of weeks) {
const likesCount = await Like.countDocuments({
author: mongoose.Types.ObjectId.createFromHexString(authorId),
createdAt: { $gt: week.start, $lte: week.end },
});

const followersCount = await Follower.countDocuments({
author: mongoose.Types.ObjectId.createFromHexString(authorId),
createdAt: { $gte: week.start, $lt: week.end },
});

likesData.push({ week: week.end, count: likesCount });
followersData.push({ week: week.end, count: followersCount });
}
let chartData = { likesData, followersData }

res.status(200).json({
success: true,
message: "Chart Data fetched successfully",
chartData
})
} catch (err) {
return next(new AppError("Some Error Occurred", 500));
}
});



/**
* @BlockUser
Expand Down Expand Up @@ -1033,8 +1129,8 @@ export const updateProfile = asyncHandler(async function (req, res, next) {
return next(new AppError("Invalid user id or user does not exist", 400));
}

if(email) {
if(!user.isVerified) user.email = email;
if (email) {
if (!user.isVerified) user.email = email;
else return next(new AppError("Email can not be changed."))
}
if (firstName) user.firstName = firstName;
Expand Down
12 changes: 12 additions & 0 deletions models/user.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ const userSchema = new Schema({
type: Number,
default: 0
},
likes: {
type: Number,
default: 0
},
following: {
type: Number,
default: 0
},
comments: {
type: Number,
default: 0
},
resetToken: String,
resetTokenExpiry: Date,
verifyToken: String,
Expand Down
5 changes: 3 additions & 2 deletions routes/user.routes.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Router } from "express";
import { isAdmin, isLoggedIn, isVerified } from "../middlewares/auth.middleware.js";
import upload from "../middlewares/multer.middleware.js";
import { AllUsers, CloseAccount, DeleteUser, VerifyAccount, VerifyTokenEmail, blockUser, changePassword, forgotPassword, loginUser, refreshAccessToken, registerUser, resetPassword, unBlockUser, updateProfile, userLogOut, userProfile } from "../controllers/user.controller.js";
import { AllUsers, CloseAccount, DeleteUser, VerifyAccount, VerifyTokenEmail, authChartData, blockUser, changePassword, forgotPassword, loginUser, refreshAccessToken, registerUser, resetPassword, unBlockUser, updateProfile, userLogOut, userProfile } from "../controllers/user.controller.js";
import rate from "../middlewares/requestLimit.js";

const router = Router();
Expand All @@ -13,7 +13,7 @@ router.post('/refresh-token', rate(15 * 60 * 1000, 5), refreshAccessToken);
router.post('/forgot-password', rate(15 * 60 * 1000, 5), forgotPassword);
router.post('/reset/:resetToken', rate(15 * 60 * 1000, 10), resetPassword);
router.post("/change-password", rate(60 * 60 * 1000, 10), isLoggedIn, changePassword);
router.get('/profile/:username', rate(15 * 60 * 1000, 30), isLoggedIn, userProfile);
router.post('/profile/:username', rate(15 * 60 * 1000, 30), isLoggedIn, userProfile);
router.patch('/profile/:id/unblock', rate(60 * 60 * 1000, 35), isLoggedIn, isAdmin, unBlockUser);
router.patch('/profile/:id/block', rate(60 * 60 * 1000, 35), isLoggedIn, isAdmin, blockUser);
router.patch('/profile/close', rate(60 * 60 * 1000, 5), isLoggedIn, CloseAccount);
Expand All @@ -22,6 +22,7 @@ router.patch('/profile/:username/verify/:token', rate(60 * 60 * 1000, 5), Verify
router.patch('/profile', rate(60 * 60 * 1000, 8) , isLoggedIn, upload.single('avatar'), updateProfile);
router.delete('/profile/:id', rate(60 * 60 * 1000, 35), isLoggedIn, DeleteUser);
router.get('/profile', rate(60 * 60 * 1000, 35), isLoggedIn, isAdmin, AllUsers);
router.get('/profile/chartdata', rate(60 * 60 * 1000, 30), isLoggedIn, authChartData);


export default router;
50 changes: 50 additions & 0 deletions utils/chartData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import mongoose from 'mongoose';
import Like from '../models/like.model.js';
import Follower from '../models/follower.model.js';

// Utility function to get the start and end dates of the past 2 months partitioned by weeks
function getWeeklyPartitions(numberOfWeeks = 8) {
const today = new Date();
const weeks = [];
// Calculate start date for the last 7 weeks (considering today)
const startOfWeek = new Date(today);
startOfWeek.setDate(today.getDate() - (today.getDay() || 7) + 1 - numberOfWeeks * 7);

while (startOfWeek < today) {
const endOfWeek = new Date(startOfWeek);
endOfWeek.setDate(startOfWeek.getDate() + 7);

weeks.push({ start: new Date(startOfWeek), end: new Date(endOfWeek) });

startOfWeek.setDate(startOfWeek.getDate() + 7);
}
return weeks;
}

// Function to get likes and followers data partitioned by week
async function getWeeklyData(authorId) {
const weeks = getWeeklyPartitions();

const likesData = [];
const followersData = [];
for (const week of weeks) {
const likesCount = await Like.countDocuments({
author: mongoose.Types.ObjectId.createFromHexString(authorId),
createdAt: { $gt: week.start, $lte: week.end },
});

const followersCount = await Follower.countDocuments({
author: mongoose.Types.ObjectId.createFromHexString(authorId),
createdAt: { $gte: week.start, $lt: week.end },
});

likesData.push({ week: week.end, count: likesCount });
followersData.push({ week: week.end, count: followersCount });
}
let chartData = { likesData, followersData }
return chartData;
}


export default getWeeklyData;

0 comments on commit 474dd6a

Please sign in to comment.