-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmovies-router.js
387 lines (363 loc) · 13.2 KB
/
movies-router.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
const mongoose = require("mongoose");
const ObjectId= require('mongoose').Types.ObjectId
const Movie = require("./models/MovieModel");
const User = require("./models/UserModel");
const Person = require("./models/PersonModel");
const Review = require("./models/ReviewModel");
const Notification = require("./models/NotificationModel");
const express = require('express');
let router = express.Router();
router.get("/", queryParse, loadSearch, respondSearch);
router.post("/", getIDs, createMovie, addMovieToPeople, createNotifications, pushNotificationsToFollowers);
router.get("/:id", recommendMovies, inList, sendMovie);
//////////////////////////MOVIE QUERY RESULTS////////////////////////////////////
// parses the query, including page #, title, genre, and person name
function queryParse(req, res, next){
if(req.session.loggedin){
let params = [];
let q = ""
for(prop in req.query){
if(prop == "page"){
continue;
}
params.push(prop + "=" + req.query[prop]);
}
req.qstring = params.join("&");
//trys to set the page that was requested by the user and attempts to convert to a Number
try{
req.query.page = req.query.page || 1;
req.query.page = Number(req.query.page);
if(req.query.page < 1){
req.query.page = 1;
}
}
catch{
req.query.page = 1;
}
//adds to the query string if there is a query parameter for title, "" if not
if(!req.query.title){
req.query.title = "";
}
else{
q = q + "&title=" + req.query.title
}
//same method as for title
if(!req.query.genre){
req.query.genre = "";
}
else{
q = q + "&genre=" + req.query.genre
}
//if there is nothing in the person parameter move to the next function, if there is run a contains search on the database to find matching people, the move to the next function
if(!req.query.person){
req.query.person = ""
res.q = q
next();
return
}
if(req.query.person){
q = q + "&person=" + req.query.person
res.q = q
Person.find({name: new RegExp(req.query.person, 'i')}).select("_id").exec(function(err, result){
req.query.pID = result
next();
})
}
}
else{
res.redirect("/"); //should be status 401, but redirects so user can log in.
}
}
//after parsing the query, builds the search results
function loadSearch(req, res, next){
let startIndex = ((req.query.page-1) * 10);
if(req.query.person === ""){
Movie.find({title: new RegExp(req.query.title, 'i'), genres: new RegExp(req.query.genre, 'i')}).limit(10).skip(startIndex).sort("title").populate("actor director writer").exec(function(err, results){
if(err){
res.status(500).send("Error Finding Movies.");
console.log(err);
return;
}
res.search = results;
next();
return;
})
}
else{
Movie.find({title: new RegExp(req.query.title, 'i'), genres: new RegExp(req.query.genre, 'i'), $or: [{actor: {$in: req.query.pID}}, {director: {$in: req.query.pID}}, {writer: {$in: req.query.pID}}]}).limit(10).skip(startIndex).populate("actor director writer").exec(function(err, results){
if(err){
res.status(500).send("Error Finding Movies.");
console.log(err);
return;
}
let maxpages = results.length / 10;
res.search = results;
next();
return;
})
}
}
//renders the search results page for the query requested, or sends the requested movies matching the query
function respondSearch(req, res, next){
res.format({
"application/json": function(){
res.status(200).json(req.search);
},
"text/html": () => {
res.render('./primaries/searchresults', {movies: res.search, session:req.session, current: req.query.page, query: res.q});
}
});
}
///////////////////////////////ADDS A NEW MOVIE///////////////////////////////
//takes the list of names of actors, writers and directors being added to this new movie and finds their Person objects
function getIDs(req, res, next){
if(req.session.loggedin && req.session.admin){
Person.findArrayByName(req.body.director, function(err, result){
if(err){
console.log(err);
res.sendStatus(500);
//these people should've been verified already because they should be names directly from the server
//therefore it is a 500 server error.
}
else{
req.directors = result;
Person.findArrayByName(req.body.actor, function(err, result){
if(err){
console.log(err);
res.sendStatus(500);
//these people should've been verified already because they should be names directly from the server
//therefore it is a 500 server error.
}
else{
req.actors = result;
Person.findArrayByName(req.body.writer, function(err, result){
if(err){
console.log(err);
res.sendStatus(500);
//these people should've been verified already because they should be names directly from the server
//therefore it is a 500 server error.
}
else{
req.writers = result;
next();
}
});
}
});
}
});
}
else{
res.sendStatus(401);
//Authentication is required and has failed or has not yet been provided.
}
}
//creates the new movie object
function createMovie(req, res, next){
Movie.getTitle(req.body.title, function(err, result){ //
if(result.length >= 1){
res.sendStatus(409);
//checks if there are duplicate titles, if there are then send a 409 conflicting resource error.
}
else{
//creates a new Movie document from the Movie schema.
let newMovie = new Movie();
newMovie._id = mongoose.Types.ObjectId();
newMovie.title = req.body.title;
newMovie.year = req.body.year;
newMovie.plot = req.body.plot;
newMovie.runtime = req.body.runtime;
newMovie.writer = req.writers;
newMovie.actor = req.actors;
newMovie.director = req.directors;
newMovie.genres = req.body.genres;
newMovie.save(function(err, movie) {
if (err) {
if(err.code == 11000){ //this is duplicate-key error (someone already exists with that name)
res.sendStatus(409); //409 is the status code for duplicate resource or resource already exists.
}
else if(err.name === 'ValidationError'){
res.sendStatus(400); //Bad request, the data send by the client failed to get verified and added.
}
else{
console.log(err);
res.sendStatus(500); //something is wrong with the server that is not due to the content of the new document
}
}
else{
res.movie = movie;
next();
}
});
}
});
}
//pushes the newly made movie document ID to the actors, writers and director's respective arrays to keep the bidirectional many-many relationship.
function addMovieToPeople(req, res, next){
Person.updateMany({'_id': {$in: res.movie.director}}, { $push: { "director": res.movie._id }}, function(err, results){
if(err){
console.log(err);
res.setHeader('content-type', 'application/json');
res.status(500).send(res.movie);
//these ids should've already been verified by the server, so if they can't be added then the server has a problem.
}
else{
Person.updateMany({'_id': {$in: res.movie.actor}}, { $push: { "actor": res.movie._id }}, function(err, results){
if(err){
console.log(err);
res.setHeader('content-type', 'application/json');
res.status(500).send(res.movie);
//these ids should've already been verified by the server, so if they can't be added then the server has a problem.
}
else{
Person.updateMany({'_id': {$in: res.movie.writer}}, { $push: { "writer": res.movie._id }}, function(err, results){
if(err){
console.log(err);
res.setHeader('content-type', 'application/json');
res.status(500).send(res.movie);
//these ids should've already been verified by the server, so if they can't be added then the server has a problem.
}
else{
next(); }
});
}
});
}
});
}
//creates notifications objects for the writers, actors, and directors to send to their followers.
function createNotifications(req, res, next){
let notifications = [];
//create notification documents depending on if it is a writer, director, or actor and pushes them into an array
res.movie.writer.forEach(writer=>{
let newNotification = new Notification();
newNotification._id = mongoose.Types.ObjectId();
newNotification.person = writer;
newNotification.movieId = res.movie._id;
newNotification.nType = 4;
notifications.push(newNotification);
});
res.movie.actor.forEach(actor=>{
let newNotification = new Notification();
newNotification._id = mongoose.Types.ObjectId();
newNotification.person = actor;
newNotification.movieId = res.movie._id;
newNotification.nType = 3;
notifications.push(newNotification);
});
res.movie.director.forEach(director=>{
let newNotification = new Notification();
newNotification._id = mongoose.Types.ObjectId();
newNotification.person = director;
newNotification.movieId = res.movie._id;
newNotification.nType = 2;
notifications.push(newNotification);
});
req.notifications = notifications;
//adds all the Notification documents into the server
Notification.insertMany(notifications, function(err, result){
if(err){
console.log(err);
res.setHeader('content-type', 'application/json');
res.status(500).send(res.movie);
//the server can't create these notifications, so it's a server error.
//the content should already be verified at this point
}
else{
next();
}
});
}
//pushes the notification document ID to the followers of each respective writer/director/actor
async function pushNotificationsToFollowers(req, res, next){
//loops through the notifications created
await req.notifications.forEach(async (notification) => {
const results = await Person.findById(notification.person);
try{
//updates all of the Person objects in their followers array to include the notification ID in their notifications array
await User.updateMany({'_id': results.followers}, { $push: { "notifications": notification._id }});
}
catch(err){
res.setHeader('content-type', 'application/json');
res.status(500).send(res.movie);
}
});
res.setHeader('content-type', 'application/json');
res.status(201).send(res.movie);
}
///////////////////////////////SENDS A MOVIE OBJECT/PAGE///////////////////////////////
//we will find the movie with this id in the parameter.
router.param("id", function(req, res, next, value){
if(req.session.loggedin){
Movie.findById(value, function(err, result){
if(err || !result){
console.log(err);
res.sendStatus(404);
//404 not found to indicate movie cannot be found with this ID.
return;
}
//populates the movie now found
Movie.findById(value).populate("director writer actor").populate({path: "reviews", populate: {path: "username", select: 'username'}}).exec(function(err, result){
if(err){
console.log(err);
res.sendStatus(500);
//500 Internal Server Error
//the server can't populate the data that it has already verified, making it a server error.
}
req.movie = result;
next();
});
});
}
else{
res.redirect("/"); //should be status 401, but redirects so user can log in.
}
});
//gets the recommended movies for the movie being requested
function recommendMovies(req, res, next){
if(req.session.loggedin){
Movie.getSimilar(req.movie, function(err, result){
if(err){
console.log(err);
res.sendStatus(500);
}
else{
req.recommendedMovies = result
next();
}
})
}
else{
res.redirect("/"); //should be status 401, but redirects so user can log in.
}
}
//checks if this movie being requested is in the logged-in user's watchlist for pug display purposes
function inList(req, res, next){
User.inWatchlist(req.session.userID, req.movie, function(err, result){
if(err){
console.log(err);
res.sendStatus(500);
}
else{
req.inList = result
next()
}
})
}
//sends the movie object/movie page
function sendMovie(req, res, next){
if(req.session.loggedin){
res.format({
"application/json": function(){
res.status(200).json(req.movie);
},
"text/html": () => { res.render('./primaries/movieprofile', {movie: req.movie, recommendedMovies: req.recommendedMovies, session: req.session, inList: req.inList});}
});
next();
}
else{
res.redirect("/"); //should be status 401, but redirects so user can log in.
}
}
//Export the router so it can be mounted in the main app
module.exports = router;