const mongoose = require('mongoose'),
Models = require("./models");
const Movies = Models.Movie;
const Anime = Models.Anime;
const TVseries = Models.TVseries;
const Users = Models.User;
const { check, validationResult } = require('express-validator');
mongoose.connect(process.env.CONNECTION_URI, { useNewUrlParser: true, useUnifiedTopology: true });
// mongodb://localhost:27017/replaydb
const express = require("express"),
morgan = require("morgan"),
fs = require("fs"),
path = require("path"),
uuid = require("uuid"),
bodyparser = require("body-parser");
const app = express();
app.use(express.static("public"));
const accessLogStream = fs.createWriteStream(path.join(__dirname, "log.txt"), {
flags: "a",
});
app.use(morgan("combined", { stream: accessLogStream }));
app.use(bodyparser.json());
const cors = require('cors');
let allowedOrigins = ['http://localhost:8080', 'http://testsite.com','http://localhost:4200', 'http://localhost:1234', 'https://yevheniiairapetian.github.io','https://r3play.netlify.app'];
app.use(cors({
origin: (origin, callback) => {
if (!origin) return callback(null, true);
if (allowedOrigins.indexOf(origin) === -1) { // If a specific origin isn’t found on the list of allowed origins
let message = 'The CORS policy for this application doesn’t allow access from origin ' + origin;
return callback(new Error(message), false);
}
return callback(null, true);
}
}));
let auth = require('./auth')(app);
const passport = require('passport');
require('./passport');
/**
* API call to get all "/movies" returning JSON object (Returns all movies)
* @name getMovies
* @async
* @param {string} /movies
* @param {} returns all movies in the response as json object
*/
app.get("/movies", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Movies.find()
.then((movies) => {
res.status(201).json(movies);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error:' + err);
//returns all movies in the response as json object
});
});
/**
* API call to get all "/movies" returning JSON object (Returns all movies)
* @name getAnimes
* @async
* @param {string} /animes
* @param {} returns all anime in the response as json object
* API call to get all "/anime" returning JSON object (Returns all anime)
* @name getAnimes
* @async
*/
app.get("/animes", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Anime.find()
.then((anime) => {
res.status(201).json(anime);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error:' + err);
//returns all anime in the response as json object
});
});
/**
* API call to get all "/movies" returning JSON object (Returns all movies)
* @name getTVSeries
* @async
* @param {string} /tvseries
* @param {} returns all TV series in the response as json object
* API call to get all "/tvseries" returning JSON object (Returns all TV series)
* @name getTVSeries
* @async
* API call to get all "/tvseries" returning JSON object (Returns all tv series)
* @name getTVSeries
* @async
*/
app.get("/tvseries", passport.authenticate('jwt', { session: false }), async (req, res) => {
await TVseries.find()
.then((tvseries) => {
res.status(201).json(tvseries);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error:' + err);
//returns all tv series in the response as json object
});
});
/**
* API call to get "/" returning documentation html file
* @name getDocumentation
* @async
* API call to get "/documentation" returning HTML file
* @name getDocumentation
* @async
*/
app.get('/documentation', (req, res) => {
res.sendFile('index.html', { root: 'public' });
});
/**
* API call to get "/movies/movieTitle" returning json object with a movie
* @param {string} /movies/:movieTitle
* @param {} returns json object with a movie
* @name getMovieTitle
* @async
*/
app.get('/movies/:movieTitle', passport.authenticate('jwt', { session: false }), async (req, res) => {
await Movies.findOne({ Title: req.params.movieTitle })
.then((movie) => {
res.status(201).json(movie);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to get "/animes/:animeTitle" returning json object with an anime
* @param {string} /movies/:movieTitle
* @param {} returns json object with an anime
* @name getAnimeTitle
* @async
* API call to get "/animes/animeTitle" returning json object with an anime
* @name getAnimeTitle
* @async
*/
app.get('/animes/:animeTitle', passport.authenticate('jwt', { session: false }), async (req, res) => {
await Anime.findOne({ Title: req.params.movieTitle })
.then((anime) => {
res.status(201).json(anime);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to get "/tvseries/:tvTitle" returning json object with an TV series
* @param {string} /movies/:movieTitle
* @param {} returns json object with an anime
* API call to get "/tvseries/:tvTitle" returning json object with a TV series
* @name getTVTitle
* @async
*/
app.get('/tvseries/:tvTitle', passport.authenticate('jwt', { session: false }), async (req, res) => {
await TVseries.findOne({ Title: req.params.tvTitle })
.then((tvseries) => {
res.status(201).json(tvseries);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to get "/movies/genres/:genreName" returning json object with a movie genre name and description
* @param {string} /movies/genres/genreName
* @param {} returns json object with a movie genre name and description
* @name getMovieGenre
* @async
*/
app.get('/movies/genres/:genreName', passport.authenticate('jwt', { session: false }), async (req, res) => {
await Movies.findOne({ 'Genre.Name': req.params.genreName })
.then((movie) => {
res.status(201).json(movie.Genre);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to get "/animes/genres/animeName" returning json object with an anime genre name and description
* @param {string} /animes/genres/animeName
* @param {} returns json object with an anime genre name and description
* @name getAnimeGenre
* @async
*/
app.get('/animes/genres/:animeName', passport.authenticate('jwt', { session: false }), async (req, res) => {
await Anime.findOne({ 'Genre.Name': req.params.genreName })
.then((anime) => {
res.status(201).json(anime.Genre);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to get "/tvseries/genres/tvName" returning json object with a tv series genre name and description
* @param {string} /tvseries/genres/tvName
* @param {} returns json object with a TV series genre name and description
* @name getTVGenre
* @async
*/
app.get('/tvseries/genres/:tvName', passport.authenticate('jwt', { session: false }), async (req, res) => {
await TVseries.findOne({ 'Genre.Name': req.params.genreName })
.then((tvseries) => {
res.status(201).json(tvseries.Genre);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to get "/movies/directors/:directorName" eturning json object with a movie director name and bio
* @param {string} /movies/directors/:directorName
* @param {} returning json object with a movie director name and bio
* @name getMovieDirector
* @async
*/
app.get("/movies/directors/:directorName", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Movies.findOne({ 'Director.Name': req.params.directorName })
.then((movie) => {
res.status(201).json(movie.Director);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to get "/animes/directors/directorName" returning json object with an anime director name and bio
* @param {string} /animes/directors/directorName
* @param {} returning json object with an anime director name and bio
* @name getAnimeDirector
* @async
*/
app.get("/animes/directors/:directorName", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Movies.findOne({ 'Director.Name': req.params.directorName })
.then((anime) => {
res.status(201).json(anime.Director);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to get "/tvseries/directors/directorName" returning json object with a tv series director name and bio
* @param {string} /tvseries/directors/directorName
* @param {} returning json object with a tv series director name and bio
* @name getTVDirector
* @async
*/
app.get("/tvseries/directors/:directorName", passport.authenticate('jwt', { session: false }), async (req, res) => {
await TVseries.findOne({ 'Director.Name': req.params.directorName })
.then((tvseries) => {
res.status(201).json(tvseries.Director);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to post "/users" returning json object with a new user
* @param {object} {Username: string,
Password: number,
Email: string,
Birthday: Date}
* @param {} returning json object with a new user
* @name postUser
* @async
*/
app.post("/users", [
check('Username', 'Username is required').isLength({ min: 5 }),
check('Username', 'Username contains non alphanumeric characters - not allowed.').isAlphanumeric(),
check('Password', 'Password is required').not().isEmpty(),
check('Email', 'Email does not appear to be valid').isEmail()
], async (req, res) => {
let errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
let hashedPassword = Users.hashPassword(req.body.Password);
await Users.findOne({ Username: req.body.Username })
.then((user) => {
if (user) {
return res.status(400).send(req.body.Username + 'already exists');
} else {
Users
.create({
Username: req.body.Username,
Password: hashedPassword,
Email: req.body.Email,
Birthday: req.body.Birthday
})
.then((user) => { res.status(201).json({ Username: user.Username, Email: user.Email }) })
.catch((error) => {
console.error(error);
res.status(500).send('Error: ' + error);
})
}
})
.catch((error) => {
console.error(error);
res.status(500).send('Error: ' + error);
});
});
/**
* API call to post "/users/:id/:movies/:MovieID" returning user json object with a favorite movie data
* @param {string} /users/:id/:movies/:MovieID
* @param {} returning user json object with a favorite movie data
* @name postMovie
* @async
*/
app.post("/users/:id/:movies/:MovieID", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Users.findOneAndUpdate({ Username: req.params.id }, {
$push: { FavoriteMovies: req.params.MovieID }
},
{ new: true }) // This line makes sure that the updated document is returned
.then((updatedUser) => {
res.status(201).json(updatedUser);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
//adds a favorite movies to the list of favorites
});
/**
* API call to post "/users/:id/:animes/:AnimeID" returning user json object with a favorite anime data (anime gets pushed to favoriteMovies)
* @param {string} /users/:id/:animes/:AnimeID
* @param {} returning user json object with a favorite anime data (anime gets pushed to favoriteMovies)
* @name postAnime
* @async
*/
app.post("/users/:id/:animes/:AnimeID", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Users.findOneAndUpdate({ Username: req.params.id }, {
$push: { FavoriteMovies: req.params.AnimeID }
},
{ new: true }) // This line makes sure that the updated document is returned
.then((updatedUser) => {
res.status(201).json(updatedUser);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to post "/users/:id/:tvseries/:tvID" returning user json object with a favorite movie data (tv series gets pushed to favoriteMovies)
* @param {string} /users/:id/:tvseries/:tvID
* @param {} returning user json object with a favorite movie data (tv series gets pushed to favoriteMovies)
* @name postTV
* @async
*/
app.post("/users/:id/:tvseries/:tvID", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Users.findOneAndUpdate({ Username: req.params.id }, {
$push: { FavoriteMovies: req.params.tvID }
},
{ new: true }) // This line makes sure that the updated document is returned
.then((updatedUser) => {
res.status(201).json(updatedUser);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
//adds a favorite tv series to the list of favorites
});
/**
* API call to delete "/users/:id/:movies/:MovieID" returning user json object with a deleted movie data
* @param {string} /users/:id/:movies/:MovieID
* @param {} returning user json object with a deleted movie data
* @name deleteMovie
* @async
*/
app.delete("/users/:id/:movies/:MovieID", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Users.findOneAndUpdate({ Username: req.params.id }, {
$pull: { FavoriteMovies: req.params.MovieID }
},
{ new: true }) // This line makes sure that the updated document is returned
.then((updatedUser) => {
res.status(201).json(updatedUser);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
//deletes a movies from the favorites list
});
/**
* API call to delete "/users/:id/:animes/:AnimeID" returning user json object with a deleted movie data (anime gets deleted from the FavoriteMovies)
* @param {string} /users/:id/:animes/:AnimeID
* @param {} returning user json object with a deleted movie data (anime gets deleted from the FavoriteMovies)
* @name deleteAnime
* @async
*/
app.delete("/users/:id/:animes/:AnimeID", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Users.findOneAndUpdate({ Username: req.params.id }, {
$pull: { FavoriteMovies: req.params.AnimeID }
},
{ new: true }) // This line makes sure that the updated document is returned
.then((updatedUser) => {
res.status(201).json(updatedUser);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to delete "/users/:id/:tvseries/:tvID" returning user json object with a deleted movie data (tv series gets deleted from the FavoriteMovies)
* @param {string} /users/:id/:tvseries/:tvID
* @param {} returning user json object with a deleted movie data (tv series gets deleted from the FavoriteMovies)
* @name deleteTV
* @async
*/
app.delete("/users/:id/:tvseries/:tvID", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Users.findOneAndUpdate({ Username: req.params.id }, {
$pull: { FavoriteMovies: req.params.tvID }
},
{ new: true }) // This line makes sure that the updated document is returned
.then((updatedUser) => {
res.status(201).json(updatedUser);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to put "/users/:id" returning user json object with an updated user data
* @param {object} {Username: string,
Password: number,
Email: string,
Birthday: Date}
* @param {} returning json object with a new user
* @name putUser
* @async
*/
app.put("/users/:id", passport.authenticate('jwt', { session: false }), [
check('Username', 'Username is required').isLength({ min: 5 }),
check('Username', 'Username contains non alphanumeric characters - not allowed.').isAlphanumeric(),
check('Password', 'Password is required').not().isEmpty(),
check('Email', 'Email does not appear to be valid').isEmail()
], async (req, res) => {
let errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
let hashedPassword = Users.hashPassword(req.body.Password);
await Users.findOneAndUpdate({ Username: req.params.id }, {
$set:
{
Username: req.body.Username,
Password: hashedPassword,
Email: req.body.Email,
Birthday: req.body.Birthday
}
},
{ new: true }) // This line makes sure that the updated document is returned
.then((updatedUser) => {
res.json(updatedUser);
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
})
});
/**
* API call to delete "/users/:id" returning user json object with a deleted user data
* @param {string} /users/:id/
* @param {} returning user json object with a deleted user data
* @name deleteUser
* @async
*/
app.delete("/users/:id", passport.authenticate('jwt', { session: false }), async (req, res) => {
await Users.findOneAndRemove({ Username: req.params.id })
.then((user) => {
if (!user) {
res.status(400).send(req.params.id + ' was not found');
} else {
res.status(200).send(req.params.id + ' was deleted.');
}
})
.catch((err) => {
console.error(err);
res.status(500).send('Error: ' + err);
});
});
/**
* API call to get "/" returning documentation html file
* @name getDocumentation
* @async
*/
app.get("/", (req, res) => {
res.sendFile('index.html', { root: 'public' });
});
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send("Something broke!");
});
const port = process.env.PORT || 8080;
app.listen(port, '0.0.0.0',() => {
console.log('Listening on Port ' + port);
});