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

fix-#339: feature,implemented like functionality to the posts #394

Closed
wants to merge 3 commits into from
Closed
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
4 changes: 4 additions & 0 deletions backend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ app.get('/', (req, res) => {
res.send('Yay!! Backend of wanderlust app is now accessible');
});

app.get('/likePost/:postId', (req, res) => {
res.send('yayyy');
});

app.all('*', (req, res) => {
res.status(404).json({
status: 404,
Expand Down
34 changes: 32 additions & 2 deletions backend/controllers/posts-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const createPostHandler = async (req, res) => {
description,
categories,
isFeaturedPost,
authorId: req.user._id,
authorId: req.user._id || req.body.authorId,
});

const [savedPost] = await Promise.all([
Expand Down Expand Up @@ -112,12 +112,14 @@ export const getLatestPostsHandler = async (req, res) => {

export const getPostByIdHandler = async (req, res) => {
try {
const post = await Post.findById(req.params.id);
const post = await Post.findById({ _id: req.params.id });

// Validation - check if post exists
if (!post) {
return res.status(HTTP_STATUS.NOT_FOUND).json({ message: RESPONSE_MESSAGES.POSTS.NOT_FOUND });
}
const authorId = post.authorId;
console.log(authorId);

res.status(HTTP_STATUS.OK).json(post);
} catch (err) {
Expand Down Expand Up @@ -157,3 +159,31 @@ export const deletePostByIdHandler = async (req, res) => {
res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ message: err.message });
}
};

export const likePostByUser = async (req, res) => {
try {
const post = await Post.findById({ _id: req.params.postId });
if (!post) {
return res.status(HTTP_STATUS.NOT_FOUND).json({ message: RESPONSE_MESSAGES.POSTS.NOT_FOUND });
}

const userIndex = post.likes.indexOf(req.user._id);
if (userIndex === -1) {
post.numberOfLikes += 1;
post.likes.push(req.user._id);
} else {
post.numberOfLikes -= 1;
post.likes.splice(userIndex, 1);
}
const [savedPost] = await Promise.all([
post.save(), // Save the post
deleteDataFromCache(REDIS_KEYS.ALL_POSTS), // Invalidate cache for all posts
deleteDataFromCache(REDIS_KEYS.FEATURED_POSTS), // Invalidate cache for featured posts
deleteDataFromCache(REDIS_KEYS.LATEST_POSTS), // Invalidate cache for latest posts
]);

res.status(HTTP_STATUS.OK).json(savedPost);
} catch (err) {
res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ message: err.message });
}
};
39 changes: 39 additions & 0 deletions backend/controllers/user-controller.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { HTTP_STATUS, RESPONSE_MESSAGES } from '../utils/constants.js';
import User from '../models/user.js';
import bcrypt from 'bcryptjs';

export const getAllUserHandler = async (req, res) => {
try {
Expand Down Expand Up @@ -50,3 +51,41 @@ export const deleteUserHandler = async (req, res) => {
.json({ message: RESPONSE_MESSAGES.COMMON.INTERNAL_SERVER_ERROR, error: error });
}
};

export const getUserInformartion = async (req, res) => {
const userId = req.params.id;
try {
const user = await User.findById({ _id: userId }).select('_id userName email');
if (!user) {
res.status(HTTP_STATUS.NOT_FOUND).json({ message: RESPONSE_MESSAGES.USERS.USER_NOT_EXISTS });
}
return res.status(HTTP_STATUS.OK).json(user);
} catch (err) {
res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ message: err.message });
}
};

export const updateUserHandler = async (req, res) => {
try {
const salt = await bcrypt.genSalt(10);
const hashPassword = await bcrypt.hash(req.body.password, salt);

const updatedUser = await User.findByIdAndUpdate(
req.params.id,
{
$set: {
userName: req.body.username,
email: req.body.email,
password: hashPassword,
},
},
{
new: true,
}
);

res.status(HTTP_STATUS.OK).json(updatedUser);
} catch (err) {
res.status(HTTP_STATUS.INTERNAL_SERVER_ERROR).json({ message: err.message });
}
};
44 changes: 44 additions & 0 deletions backend/data/sample_posts.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"categories": ["Travel", "Beaches"],
"description": "The Maldives is a tropical paradise known for its stunning beaches, crystal-clear waters, and vibrant marine life. In this journey, we explore the breathtaking beauty of the Maldives' beaches. From the white sands to the vibrant coral reefs, there's something for every traveler.The Maldives is a tropical paradise known for its stunning beaches, crystal-clear waters, and vibrant marine life. In this journey, we explore the breathtaking beauty of the Maldives' beaches. From the white sands to the vibrant coral reefs, there's something for every traveler.",
"isFeaturedPost": true,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"timeOfPost": {
"$date": "2023-11-24T14:33:21.700Z"
}
Expand All @@ -23,6 +26,9 @@
"categories": ["Travel", "City", "Night"],
"description": "Discover the magic of cityscapes at night in this captivating journey. The city lights, towering skyscrapers, and bustling streets create a unique atmosphere that is truly mesmerizing. Join us as we explore cities after dark and witness their vibrant energy. As the sun sets and darkness descends, the city transforms into a different world. It's a world of illuminated skyscrapers, neon signs, and the hustle and bustle of the nightlife. In this blog post, we'll take you on a journey through the cityscape at night, and you'll see why it's a mesmerizing experience. The city comes alive in a way that is entirely different from the daytime. The streets are aglow with a sea of lights, and the architecture of the city takes on a whole new dimension. It's a visual spectacle that leaves a lasting impression. We'll explore the beauty of city lights, the towering skyscrapers that touch the sky, and the vibrancy of the nightlife. You'll get a sense of the energy that flows through the city when the moon is high, and the stars twinkle overhead. The cityscape at night is a canvas of colors and shapes. It's a photographer's dream, and if you have a passion for photography, this is the time to capture the city's true essence. Whether you're in a bustling metropolis or a quaint town, the magic of the cityscape at night is universal. The city's landmarks, from iconic bridges to historic buildings, take on a different aura. The reflections in the water, the long-exposure shots of traffic, and the silhouettes of people on the streets all contribute to the enchanting experience. We'll also delve into the sounds of the night, from the chatter of people enjoying their evenings to the distant hum of traffic. It's a symphony of urban life that's unique to the nighttime hours. If you're a traveler seeking a new perspective on familiar places or an adventurer exploring a new city, this blog post will inspire you to go out and experience the cityscape at night. The night holds surprises and discoveries that the daytime can't offer. We'll share tips on how to make the most of your night photography and how to capture the essence of the city in your images. Whether you're a professional photographer or an amateur with a smartphone, you'll find something valuable in this journey through the city's nightscape. So, join us as we step into the night and immerse ourselves in the captivating world of the cityscape at night. It's a mesmerizing experience that will leave you with memories and photographs to cherish for a lifetime.",
"isFeaturedPost": true,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"timeOfPost": {
"$date": "2023-11-04T14:33:21.700Z"
}
Expand All @@ -37,6 +43,9 @@
"categories": ["Travel", "Adventure", "Nature"],
"description": "Get ready to experience the thrill of outdoor adventures in some of the world's most beautiful natural settings. From hiking and camping to white-water rafting, this journey takes you to the heart of nature and offers an adrenaline rush like no other.",
"isFeaturedPost": true,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"timeOfPost": {
"$date": "2023-10-04T14:33:21.700Z"
}
Expand All @@ -51,6 +60,9 @@
"categories": ["Travel", "City", "Landmarks"],
"description": "Marvel at the iconic London skyline, featuring historic landmarks like Big Ben, the London Eye, and the Shard. Join us on a journey to explore the rich history and modernity of the British capital through its stunning skyline.",
"isFeaturedPost": true,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"timeOfPost": {
"$date": "2023-09-11T14:33:21.700Z"
}
Expand All @@ -65,6 +77,9 @@
"categories": ["Nature", "Scenic", "Tranquil"],
"description": "Find solace and serenity in the heart of nature's most scenic landscapes. This journey takes you to tranquil forests, serene lakes, and picturesque countryside. Immerse yourself in the beauty of the natural world and experience true peace.",
"isFeaturedPost": true,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"timeOfPost": {
"$date": "2023-08-22T14:33:21.700Z"
}
Expand All @@ -79,6 +94,9 @@
"categories": ["Travel", "Beaches", "Sunset"],
"description": "Witness the breathtaking beauty of sunsets by the beach. As the sun dips below the horizon, it paints the sky with hues of orange, pink, and gold. This journey captures the magical moments of evening by the sea.",
"isFeaturedPost": false,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"timeOfPost": {
"$date": "2023-03-25T14:33:21.700Z"
}
Expand All @@ -93,6 +111,9 @@
"categories": ["Travel", "City", "Night"],
"description": "Experience the vibrant energy of cities after dark. The city lights, bustling streets, and lively nightlife create a spectacle that must be seen to be believed. Join us for a journey through the electrifying nightscapes of urban hubs.",
"isFeaturedPost": false,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"timeOfPost": {
"$date": "2023-05-26T14:33:21.700Z"
}
Expand All @@ -107,6 +128,9 @@
"categories": ["Travel", "Adventure", "Mountains"],
"description": "Embark on thrilling mountain adventures in some of the world's most spectacular mountain ranges. From trekking through alpine meadows to conquering challenging peaks, this journey takes you to new heights in the world of adventure.",
"isFeaturedPost": false,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"timeOfPost": {
"$date": "2023-11-27T14:33:21.700Z"
}
Expand All @@ -121,6 +145,9 @@
"categories": ["Travel", "History", "Landmarks"],
"description": "Embark on a journey to explore historical sites and ancient landmarks that tell the stories of civilizations past. Uncover the secrets of the past as you visit historic sites and delve into the mysteries of history.",
"isFeaturedPost": false,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"timeOfPost": {
"$date": "2023-11-11T14:33:21.700Z"
}
Expand All @@ -135,8 +162,25 @@
"categories": ["Nature", "Forests", "Retreat"],
"description": "Find solace in the tranquility of the forest. This retreat into nature's embrace allows you to disconnect from the bustling world and discover the peaceful beauty of dense forests, serene lakes, and gentle streams.",
"isFeaturedPost": false,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"timeOfPost": {
"$date": "2023-07-22T14:33:21.700Z"
}
},
{
"authorName": "vamsiii",
"title": "vamsiPosts",
"imageLink": "https://i.ibb.co/3z72vmc/clean-lake-mountains-range-trees-nature-4k.webp",
"categories": ["Travel", "Beaches"],
"description": "The Maldives is a tropical paradise known for its stunning beaches, crystal-clear waters, and vibrant marine life. In this journey, we explore the breathtaking beauty of the Maldives' beaches. From the white sands to the vibrant coral reefs, there's something for every traveler.The Maldives is a tropical paradise known for its stunning beaches, crystal-clear waters, and vibrant marine life. In this journey, we explore the breathtaking beauty of the Maldives' beaches. From the white sands to the vibrant coral reefs, there's something for every traveler.",
"isFeaturedPost": false,
"likes": [],
"numberOfLikes": 0,
"authorId": "665bc7c00c0d962738398b5c",
"_id": "665dd4f2b23f177dd4170450",
"timeOfPost": "2024-06-03T14:36:34.186Z",
"__v": 0
}
]
8 changes: 8 additions & 0 deletions backend/models/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@ const postSchema = new Schema({
description: String,
isFeaturedPost: Boolean,
timeOfPost: { type: Date, default: Date.now },
likes: {
type: Array,
default: [],
},
numberOfLikes: {
type: Number,
default: 0,
},
authorId: {
type: Schema.Types.ObjectId,
ref: 'User',
Expand Down
7 changes: 7 additions & 0 deletions backend/routes/posts.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getLatestPostsHandler,
getPostByCategoryHandler,
getPostByIdHandler,
likePostByUser,
updatePostHandler,
} from '../controllers/posts-controller.js';
import { REDIS_KEYS } from '../utils/constants.js';
Expand All @@ -29,12 +30,18 @@ router.get('/categories/:category', getPostByCategoryHandler);

// Route for fetching the latest posts
router.get('/latest', cacheHandler(REDIS_KEYS.LATEST_POSTS), getLatestPostsHandler);

// Get a specific post by ID
router.get('/:id', getPostByIdHandler);

//random test
router.put('/likePost/:postId', authMiddleware, likePostByUser);

// Update a post by ID
router.patch('/:id', authMiddleware, isAuthorMiddleware, updatePostHandler);

// add like to post

// Delete a post by ID
router.delete('/:id', authMiddleware, isAuthorMiddleware, deletePostByIdHandler);

Expand Down
8 changes: 8 additions & 0 deletions backend/routes/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
changeUserRoleHandler,
deleteUserHandler,
getAllUserHandler,
getUserInformartion,
updateUserHandler,
} from '../controllers/user-controller.js';

const router = Router();
Expand All @@ -17,4 +19,10 @@ router.patch('/:userId', authMiddleware, isAdminMiddleware, changeUserRoleHandle
// delete the user
router.delete('/:userId', authMiddleware, isAdminMiddleware, deleteUserHandler);

// get user info
router.get('/:id', authMiddleware, getUserInformartion);

// update user Information
router.patch('/update/:id', authMiddleware, updateUserHandler);

export default router;
4 changes: 4 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import UnprotectedRoute from './components/unprotected-route';
import { useLayoutEffect } from 'react';
import RequireAuth from './components/require-auth';
import useThemeClass from './utils/theme-changer';
import { UserProfile } from './components/UserProfile';
import { YourPosts } from './components/YourPosts';

function App() {
useLayoutEffect(() => {
Expand All @@ -32,6 +34,8 @@ function App() {
</Route>
<Route element={<RequireAuth allowedRole={['ADMIN', 'USER']} />}>
<Route path="add-blog" element={<AddBlog />} />
<Route path="profile" element={<UserProfile />} />
<Route path="Your-Posts" element={<YourPosts />} />
</Route>
<Route path="admin" element={<RequireAuth allowedRole={['ADMIN']} />}>
<Route path="users" element={<AdminUsers />} />
Expand Down
Empty file.
Loading