require("dotenv").config(); const app = require("express")(); const bodyParser = require("body-parser"); const bcrypt = require("bcryptjs"); const uuid = require("uuid").v4; const axios = require("axios"); const mongoose = require("mongoose"); const cors = require("cors"); mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, }); const User = require("./models/User"); const Movie = require("./models/Movie"); const Userdata = require("./models/Userdata"); const { WATCH_STATUS, RATINGS } = require("./util/consts"); const tmdb = axios.create({ baseURL: "https://api.themoviedb.org/3/", timeout: 1000, params: { api_key: process.env.TMDB_KEY, }, }); const getProot = () => tmdb .get("/configuration", { params: { api_key: process.env.TMDB_KEY, }, }) .then(res => res.data) .then(data => data.images.base_url + "w500") .catch(e => { console.error("ERR on tmdb configuration", e.message); return getProot(); }); (async function main() { const posterRoot = await getProot(); app.use(bodyParser.json()); app.use(cors()); app.use((req, _, next) => { console.log(req.method, req.url); req["Container"] = {}; next(); }); app.post("/register", async (req, res) => { if (!req.body.username || !req.body.email || !req.body.password) { res.statusCode = 400; res.send({ success: false, msg: "Error! All fields were not sent.", }); } try { await User.create({ email: req.body.email, username: req.body.username, password: await bcrypt.hash( req.body.password, process.env.SALT, ), }); res.send({ success: true, msg: "Successfully created user." }); } catch (e) { console.error("ERR on /register", e.message); res.statusCode = 500; res.send({ success: false, msg: "An error occured while creating the user! Username and email should be unique.", }); } }); app.post("/login", async (req, res) => { if (!req.body.username || !req.body.password) { res.statusCode = 400; res.send({ success: false, msg: "Error! All fields were not sent.", }); } const user = await User.findOne({ username: req.body.username }); const valid = await bcrypt.compare(req.body.password, user.password); if (valid) { const token = uuid(); user.tokens.push(token); await user.save(); res.send({ success: true, token }); } }); const verifyUser = async (req, res, next) => { if (!req.headers["authentication"]) { res.statusCode = 401; return res.send({ success: false, msg: "User not logged in. Authentication header was not found.", }); } const user = await User.findOne({ tokens: req.headers["authentication"], }); if (user) { req["Container"].user = user; next(); } else { res.statusCode = 401; res.send({ success: false, msg: "Authentication header was not valid.", }); } }; app.get("/search/:query", verifyUser, async (req, res) => { try { const results = ( await tmdb.get(`/search/movie`, { params: { query: req.params.query, api_key: process.env.TMDB_KEY, }, }) ).data.results; const movies = results.map( ({ poster_path, overview, release_date, id, title }) => { const movie = { poster: posterRoot + poster_path, overview, release: release_date, movieId: id, title, }; return movie; }, ); res.send({ success: true, results: movies }); } catch (e) { console.error("ERR on /search", e.message); res.statusCode = 500; res.send({ success: false, msg: "An error occured, please try again", }); } }); app.get("/movie/:id", verifyUser, async (req, res) => { try { const fromDB = await Movie.findOne({ movieId: req.params.id }); if (!fromDB) { const result = ( await tmdb.get(`/movie/${req.params.id}`, { params: { api_key: process.env.TMDB_KEY }, }) ).data; const movie = { poster: posterRoot + result.poster_path, overview: result.overview, release: result.release_date, movieId: req.params.id, title: result.title, }; res.send({ success: true, data: movie }); await Movie.create(movie); } else { const data = await Userdata.findOne({ userId: req["Container"].user._id, movieId: req.params.id, }); const movie = fromDB.toJSON(); if (data) { movie.watchStatus = data.watchStatus; movie.rating = data.rating; } movie.poster = posterRoot + movie.poster; delete movie._id; delete movie.__v; res.send({ success: true, data: movie }); } } catch (e) { console.error("ERR on /movie", e.message); res.statusCode = 500; res.send({ success: false, msg: "An error occured, please try again", }); } }); app.post("/movie/:id", verifyUser, async (req, res) => { try { const userId = req["Container"].user._id; const movieId = req.params.id; const { watchStatus, rating } = req.body; if (!movieId) { res.statusCode = 400; return res.send({ success: false, msg: "movieId was not sent.", }); } if (watchStatus && !WATCH_STATUS.includes(watchStatus)) { res.statusCode = 400; return res.send({ success: false, msg: "watchStatus must be one of " + WATCH_STATUS.join(", "), }); } if (rating && !RATINGS.includes(rating)) { res.statusCode = 400; return res.send({ success: false, msg: "rating must be one of " + RATINGS.join(", "), }); } await Userdata.updateOne( { userId, movieId }, { userId, movieId, watchStatus: req.body.watchStatus, rating: req.body.rating, }, { upsert: true, }, ); res.send({ success: true }); } catch { res.statusCode = 500; res.send({ success: false, msg: "An error occured, please try again", }); } }); app.listen(process.env.PORT, () => console.log("Listening on port", process.env.PORT), ); })();