Skip to content
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
2 changes: 1 addition & 1 deletion apps/api/.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
ACCESS_TOKEN_SECRET=[YOUR_ACCESS_TOKEN_SECRET_HERE]
REFRESH_TOKEN_SECRET=[YOUR_REFRESH_TOKEN_SECRET_HERE]
MONGO_URL=[YOUR_MONGO_CONNECTION_STRING_HERE]
MONGO_URL=mongodb+srv://jesussaucedo:1234@cluster0.pbp95rs.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to remove this from the PR

27 changes: 13 additions & 14 deletions apps/api/src/controllers/auth.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';

import { User } from '../models/user';

const users: User[] = [];
import User from '../models/user';

const register = async (req, res) => {
const { username, password } = req.body;
Expand All @@ -15,18 +13,19 @@ const register = async (req, res) => {
});
}

// Check that we don't have duplicates
const duplicate = users.find((u) => u.username === username);
if (duplicate) {
return res.status(409).json({ message: 'User already exist' });
}

try {
// Check that we don't have duplicates
const user = await User.findOne({ username });

if (user) {
return res.status(409).json({ message: 'User already exist' });
}

// Encrypt the password
const hashedPassword = await bcrypt.hash(password, 10);

// Store new user
users.push({ username, password: hashedPassword });
await User.create({ username, password: hashedPassword });

res.status(201).json({ message: 'User registered successfully' });
} catch (e) {
Expand All @@ -45,15 +44,15 @@ const login = async (req, res) => {
}

// Retrieve user
const user = users.find((u) => u.username === username);
const user = await User.findOne({ username }).exec();

// Check if we found the user and the password matches
if (!user || !(await bcrypt.compare(password, user.password))) {
return res.status(401).json({ message: 'Invalid credentials' });
}

// Generate access token and refresh token
const accessToken = jwt.sign({ username }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: '15m' });
const accessToken = jwt.sign({ username }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: '1h' });
const refreshToken = jwt.sign({ username }, process.env.REFRESH_TOKEN_SECRET, { expiresIn: '7d' });

// Save refresh token
Expand All @@ -79,7 +78,7 @@ const refresh = (req, res) => {
return res.status(403).json({ message: 'Forbidden' });
}

const accessToken = jwt.sign({ username }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: '15m' });
const accessToken = jwt.sign({ username }, process.env.ACCESS_TOKEN_SECRET, { expiresIn: '1h' });
res.json({ accessToken });
});
};
Expand All @@ -94,4 +93,4 @@ export default {
login,
refresh,
logout
};
};
2 changes: 1 addition & 1 deletion apps/api/src/controllers/category.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,4 @@ export default {
createCategory,
updateCategory,
deleteCategory
};
};
103 changes: 103 additions & 0 deletions apps/api/src/controllers/post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import Post from '../models/post';
import Comment from '../models/comment';

const getPosts = async (req, res) => {
try {
const posts = await Post.find().populate('category').exec();
res.status(200).json(posts);
} catch (error) {
const { message } = error;
res.status(500).json({ message });
}
};

const getPostsByCategory = async (req, res) => {
const { category } = req.params;
try {
const posts = await Post.find({ category }).populate('category').exec();
res.status(200).json(posts);
} catch (error) {
const { message } = error;
res.status(500).json({ message });
}
};

const getPostById = async (req, res) => {
const { id } = req.params;
try {
const post = await Post.findById(id).populate('category').populate('comments').exec();
if (!post) {
return res.status(404).send({ message: 'Post not found' });
}
res.status(200).json(post);
} catch (error) {
const { message } = error;
res.status(500).json({ message });
}
};

const createPost = async (req, res) => {
try {
const post = await Post.create(req.body);
res.status(201).json(post);
} catch (error) {
const { message } = error;
res.status(500).json({ message });
}
};

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

if (!post) {
return res.status(404).send({ message: 'Post not found' });
}
const newComment = await Comment.create(req.body);
post.comments.push(newComment._id);
await post.save();
res.status(201).json(newComment);
} catch (error) {
const { message } = error;
res.status(500).json({ message });
}
};

const updatePost = async (req, res) => {
const { id } = req.params;
try {
const post = await Post.findByIdAndUpdate(id, req.body, { new: true });
if (!post) {
return res.status(404).send({ message: 'Post not found' });
}
res.status(200).json(post);
} catch (error) {
const { message } = error;
res.status(500).json({ message });
}
};

const deletePost = async (req, res) => {
const { id } = req.params;
try {
const post = await Post.findByIdAndDelete(id);
if (!post) {
return res.status(404).send({ message: 'Post not found' });
}
res.status(204).json(post);
} catch (error) {
const { message } = error;
res.status(500).json({ message });
}
};

export default {
getPosts,
getPostsByCategory,
getPostById,
createPost,
createPostComment,
updatePost,
deletePost
};
9 changes: 5 additions & 4 deletions apps/api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import mongoose from 'mongoose';
import { corsOptions } from './config/corsConfig';
import { verifyToken } from './middleware/auth';
import { errorHandler } from './middleware/errorHandler';

import auth from './routes/auth';
import categories from './routes/categories';
import posts from './routes/posts';

const host = process.env.HOST ?? 'localhost';
const port = process.env.PORT ? Number(process.env.PORT) : 3000;
Expand All @@ -17,23 +19,22 @@ const app = express();
app.use(express.json());
app.use(helmet());
app.use(cors(corsOptions));

app.use('/api/auth', auth);

app.use(verifyToken);

app.use('/api/categories', categories);
app.use('/api/posts', posts);

app.use(errorHandler);

mongoose
.connect(process.env.MONGO_URL)
.then(() => {
console.log('Connected to MongoDB');

app.listen(port, host, () => {
console.log(`[ ready ] http://${host}:${port}`);
});
})
.catch((e) => {
console.error(e);
});

2 changes: 1 addition & 1 deletion apps/api/src/middleware/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ export const verifyToken = (req, res, next) => {

export default {
verifyToken
};
};
2 changes: 1 addition & 1 deletion apps/api/src/models/category.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ export const categorySchema = new Schema<ICategory>(

const Category = mongoose.model<ICategory>('Category', categorySchema);

export default Category;
export default Category;
20 changes: 20 additions & 0 deletions apps/api/src/models/comment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import mongoose, { Document, Schema } from 'mongoose';

interface IComment extends Document {
author: string;
content: string;
}

const commentSchema = new Schema<IComment>(
{
author: String,
content: String
},
{
timestamps: true
}
);

const Comment = mongoose.model<IComment>('Comment', commentSchema);

export default Comment;
57 changes: 57 additions & 0 deletions apps/api/src/models/post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import mongoose, { Document, Schema } from 'mongoose';

import Comment from './comment';

interface IPost extends Document {
title: string;
image: string;
description: string;
category: mongoose.Types.ObjectId;
comments: mongoose.Types.ObjectId[];
}

const postSchema = new Schema<IPost>(
{
title: {
type: String,
required: [true, 'Property is required']
},
image: {
type: String,
required: [true, 'Property is required']
},
description: {
type: String,
required: [true, 'Property is required']
},
category: {
type: Schema.Types.ObjectId,
ref: 'Category',
required: [true, 'Property is required']
},
comments: [
{
type: Schema.Types.ObjectId,
ref: 'Comment'
}
]
},
{
timestamps: true
}
);

postSchema.pre('findOneAndDelete', async function (next) {
try {
const postToDelete = await this.model.findById(this.getFilter());
await Comment.deleteMany({ _id: { $in: postToDelete.comments } });
next();
} catch (error) {
console.log(error, 'ERROR!!!');
next(error);
}
});

const Post = mongoose.model<IPost>('Post', postSchema);

export default Post;
26 changes: 24 additions & 2 deletions apps/api/src/models/user.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
export type User = {
import mongoose, { Document, Schema } from 'mongoose';

interface IUser extends Document {
username: string;
password: string;
};
}

const userSchema = new Schema<IUser>(
{
username: {
type: String,
required: [true, 'Property is required']
},
password: {
type: String,
required: [true, 'Property is required']
}
},
{
timestamps: true
}
);

const User = mongoose.model<IUser>('User', userSchema);

export default User;
7 changes: 1 addition & 6 deletions apps/api/src/routes/categories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,14 @@ import categoryController from '../controllers/category';

const router = express.Router();

// Get all categories
router.get('/', categoryController.getCategories);

// Get category by id
router.get('/:id', categoryController.getCategoryById);

// Create category
router.post('/', categoryController.createCategory);

// Update category
router.patch('/:id', categoryController.updateCategory);

// Delete category
router.delete('/:id', categoryController.deleteCategory);

export default router;
export default router;
20 changes: 20 additions & 0 deletions apps/api/src/routes/posts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import express from 'express';
import postController from '../controllers/post';

const router = express.Router();

router.get('/', postController.getPosts);

router.get('/category/:category', postController.getPostsByCategory);

router.get('/:id', postController.getPostById);

router.post('/', postController.createPost);

router.post('/:id/comments', postController.createPostComment);

router.patch('/:id', postController.updatePost);

router.delete('/:id', postController.deletePost);

export default router;