Skip to content

Commit

Permalink
28-00-starting-setup
Browse files Browse the repository at this point in the history
  • Loading branch information
leo41271 committed Jul 30, 2024
1 parent f9e1b1e commit ec5a1a1
Show file tree
Hide file tree
Showing 66 changed files with 2,707 additions and 0 deletions.
87 changes: 87 additions & 0 deletions 28 GraphQL/backend/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
const path = require('path');

const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const multer = require('multer');

const feedRoutes = require('./routes/feed');
const authRoutes = require('./routes/auth');

const app = express();
/** SOCKET-IO CONFIGURATION */
const http = require('http');
const server = http.createServer(app);
/** ======================= */

const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'images');
},
filename: (req, file, cb) => {
/** DON'T USE .toISOString() on windows */
cb(null, Date.now() + '-' + file.originalname);
},
});

const fileFilter = (req, file, cb) => {
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
cb(null, true);
} else {
cb(null, false);
}
};

// app.use(bodyParser.urlEncoded()); // x-www-form-urlencoded <form>
app.use(bodyParser.json()); // application/json
app.use(
multer({ storage: fileStorage, fileFilter: fileFilter }).single('image')
);
app.use('/images', express.static(path.join(__dirname, 'images')));

app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader(
'Access-Control-Allow-Methods',
'OPTIONS, GET, POST, PUT, PATCH, DELETE'
);
res.setHeader(
'Access-Control-Allow-Headers',
'Content-Type, Authorization'
);
next();
});

app.use('/feed', feedRoutes);
app.use('/auth', authRoutes);

app.use((error, req, res, next) => {
console.log(error);
const status = error.statusCode;
const message = error.message;
const data = error.data;
res.status(status).json({ message: message, data: data });
});

/** REPLACE CONNECTION STRING IF USING ATLAS
* "mongodb+srv://<username>:<password>@<cluster-id>.mongodb.net/<dbName>?retryWrites=true&authSource=admin"
*/
mongoose
.connect(
'mongodb://127.0.0.1:27017/messages?retryWrites=true&authSource=admin'
)
.then(() => {
/** SEE LINES 12-15 -- UPDATED CONFIGURATION */
const io = require('./socket').init(server);
io.on('connection', (socket) => {
console.log('Client connected.');
});
/** ======================================== */
/** LISTEN TO CUSTOM SERVER INSTANCE */
server.listen(8080);
})
.catch((err) => console.log(err));
111 changes: 111 additions & 0 deletions 28 GraphQL/backend/controllers/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
const { validationResult } = require('express-validator');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');

const User = require('../models/user');

exports.signup = async (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const error = new Error('Validation failed.');
error.statusCode = 422;
error.data = errors.array();
throw error;
}
const email = req.body.email;
const name = req.body.name;
const password = req.body.password;
try {
const hashedPw = await bcrypt.hash(password, 12);

const user = new User({
email: email,
password: hashedPw,
name: name,
});
const result = await user.save();
res.status(201).json({
message: 'User created!',
userId: result._id,
});
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};

exports.login = async (req, res, next) => {
const email = req.body.email;
const password = req.body.password;
let loadedUser;
try {
const user = await User.findOne({ email: email });
if (!user) {
const error = new Error(
'A user with this email could not be found.'
);
error.statusCode = 401;
throw error;
}
loadedUser = user;
const isEqual = await bcrypt.compare(password, user.password);
if (!isEqual) {
const error = new Error('Wrong password!');
error.statusCode = 401;
throw error;
}
const token = jwt.sign(
{ email: loadedUser.email, userId: loadedUser._id.toString() },
'somesupersecretsecret',
{ expiresIn: '1h' }
);
res.status(200).json({
token: token,
userId: loadedUser._id.toString(),
});
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};

exports.getUserStatus = async (req, res, next) => {
try {
const user = await User.findById(req.userId);
if (!user) {
const error = new Error('User not found.');
error.statusCode = 404;
throw error;
}
res.status(200).json({ status: user.status });
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};

exports.updateUserStatus = async (req, res, next) => {
const newStatus = req.body.status;
try {
const user = await User.findById(req.userId);
if (!user) {
const error = new Error('User not found.');
error.statusCode = 404;
throw error;
}
user.status = newStatus;
await user.save();
res.status(200).json({ message: 'User updated.' });
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};
196 changes: 196 additions & 0 deletions 28 GraphQL/backend/controllers/feed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
const fs = require('fs');
const path = require('path');

const { validationResult } = require('express-validator');

const io = require('../socket');
const Post = require('../models/post');
const User = require('../models/user');

exports.getPosts = async (req, res, next) => {
const currentPage = req.query.page || 1;
const perPage = 2;
try {
const totalItems = await Post.find().countDocuments();
const posts = await Post.find()
.populate('creator')
.sort({ createdAt: -1 })
.skip((currentPage - 1) * perPage)
.limit(perPage);
res.status(200).json({
message: 'Fetched posts successfully.',
posts: posts,
totalItems: totalItems,
});
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};

exports.createPost = async (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const error = new Error(
'Validation failed, entered data is incorrect.'
);
error.statusCode = 422;
throw error;
}
if (!req.file) {
const error = new Error('No image provided.');
error.statusCode = 422;
throw error;
}
/** REPLACE ALL '\' WITH '/' */
const imageUrl = req.file.path.replace(/\\/g, '/');
const title = req.body.title;
const content = req.body.content;
const post = new Post({
title: title,
content: content,
imageUrl: imageUrl,
creator: req.userId,
});
try {
await post.save();
const user = await User.findById(req.userId);
user.posts.push(post);
await user.save();
io.getIO().emit('posts', {
action: 'create',
post: {
...post._doc,
creator: { _id: req.userId, name: user.name },
},
});
res.status(201).json({
message: 'Post created successfully!',
post: post,
creator: {
_id: user._id,
name: user.name,
},
});
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};

exports.getPost = async (req, res, next) => {
const postId = req.params.postId;
try {
const post = await Post.findById(postId);
if (!post) {
const error = new Error('Could not find post.');
error.statusCode = 404;
throw error;
}
res.status(200).json({
message: 'Post fetched.',
post: post,
});
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};

exports.updatePost = async (req, res, next) => {
const postId = req.params.postId;
const errors = validationResult(req);
if (!errors.isEmpty()) {
const error = new Error(
'Validation failed, entered data is incorrect.'
);
error.statusCode = 422;
throw error;
}
const title = req.body.title;
const content = req.body.content;
let imageUrl = req.body.image;
if (req.file) {
/** REPLACE ALL '\' WITH '/' */
imageUrl = req.file.path.replace(/\\/g, '/');
}
if (!imageUrl) {
const error = new Error('No file picked.');
error.statusCode = 422;
throw error;
}
try {
const post = await Post.findById(postId).populate('creator');
if (!post) {
const error = new Error('Could not find post.');
error.statusCode = 404;
throw error;
}
if (post.creator._id.toString() !== req.userId) {
const error = new Error('Not authorized.');
error.statusCode = 403;
throw error;
}
if (imageUrl !== post.imageUrl) {
clearImage(post.imageUrl);
}
post.title = title;
post.imageUrl = imageUrl;
post.content = content;
const result = await post.save();
io.getIO().emit('posts', { action: 'update', post: result });
res.status(200).json({ message: 'Post updated!', post: result });
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};

exports.deletePost = async (req, res, next) => {
const postId = req.params.postId;
try {
const post = await Post.findById(postId);

if (!post) {
const error = new Error('Could not find post.');
error.statusCode = 404;
throw error;
}
if (post.creator.toString() !== req.userId) {
const error = new Error('Not authorized.');
error.statusCode = 403;
throw error;
}
// Check logged in user
clearImage(post.imageUrl);
/** .findByIdAndRemove -- REMOVED */
await Post.findByIdAndDelete(postId);

const user = await User.findById(req.userId);
user.posts.pull(postId);
await user.save();
io.getIO().emit('posts', {
action: 'delete',
post: postId,
});
res.status(200).json({ message: 'Deleted post.' });
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};

const clearImage = (filePath) => {
filePath = path.join(__dirname, '..', filePath);
fs.unlink(filePath, (err) => console.log(err));
};
Binary file added 28 GraphQL/backend/images/duck.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit ec5a1a1

Please sign in to comment.