Last active
June 14, 2016 20:25
-
-
Save sailsinaction/4aa62ec9b504d570c475449fdba193de to your computer and use it in GitHub Desktop.
Chapter 13 - Gists
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.d8888b. 888 888 d888 .d8888b. .d8888b. d8b 888 | |
d88P Y88b 888 888 d8888 d88P Y88b d88P Y88b Y8P 888 | |
888 888 888 888 888 .d88P 888 888 888 | |
888 88888b. 8888b. 88888b. 888888 .d88b. 888d888 888 8888" 888 888 .d8888b 888888 .d8888b | |
888 888 "88b "88b 888 "88b 888 d8P Y8b 888P" 888 "Y8b. 888 88888 888 88K 888 88K | |
888 888 888 888 .d888888 888 888 888 88888888 888 888 888 888 888888 888 888 888 "Y8888b. 888 "Y8888b. | |
Y88b d88P 888 888 888 888 888 d88P Y88b. Y8b. 888 888 Y88b d88P Y88b d88P 888 X88 Y88b. X88 | |
"Y8888P" 888 888 "Y888888 88888P" "Y888 "Y8888 888 8888888 "Y8888P" "Y8888P88 888 88888P' "Y888 88888P' | |
888 | |
888 | |
888 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tutorialDetail: function(req, res) { | |
// Find the tutorial that will be displayed | |
Tutorial.findOne({ | |
id: req.param('id') | |
}) | |
.populate('owner') | |
.populate('videos') | |
.populate('ratings') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Find all ratings made by the currently authenticated user agent | |
Rating.find({ | |
byUser: req.session.userId | |
}).exec(function(err, foundRating){ | |
if (err) return res.negotiate(err); | |
// If the user agent hasn't made any ratings, assign myRating to null | |
if (foundRating.length === 0) { | |
foundTutorial.myRating = null; | |
} else { | |
// Iterate through ratings to determine whether the rating matches | |
// the id of the tutorial to be displayed. | |
_.each(foundRating, function(rating){ | |
if (foundTutorial.id === rating.byTutorial) { | |
foundTutorial.myRating = rating.stars; | |
return; | |
} | |
}); | |
} | |
// If the tutorial has no ratings assign averageRating to null. | |
if (foundTutorial.ratings.length === 0) { | |
foundTutorial.averageRating = null; | |
} else { | |
var sumfoundTutorialRatings = 0; | |
// Iterate through each rating and add up the sum of all ratings | |
_.each(foundTutorial.ratings, function(rating){ | |
sumfoundTutorialRatings = sumfoundTutorialRatings + rating.stars; | |
}); | |
// Calculate the average rating | |
foundTutorial.averageRating = sumfoundTutorialRatings / foundTutorial.ratings.length; | |
} | |
// limit the owner attribute to the users name | |
foundTutorial.owner = foundTutorial.owner.username; | |
// Transform createdAt in time ago format | |
foundTutorial.created = DatetimeService.getTimeAgo({date: foundTutorial.createdAt}); | |
// Transform updatedAt in time ago format | |
foundTutorial.updated = DatetimeService.getTimeAgo({date: foundTutorial.updatedAt}); | |
// If not logged in set `me` property to `null` and pass the tutorial to the view | |
if (!req.session.userId) { | |
return res.view('tutorials-detail', { | |
me: null, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} | |
User.findOne(req.session.userId) | |
.exec(function(err, user) { | |
if (err) return res.negotiate(err); | |
if (!user) { | |
sails.log.verbose('Session refers to a user who no longer exists- did you delete a user, then try to refresh the page with an open tab logged-in as that user?'); | |
return res.view('tutorials-detail', { | |
me: null | |
}); | |
} | |
// We'll provide `me` as a local to the profile page view. | |
// (this is so we can render the logged-in navbar state, etc.) | |
var me = { | |
gravatarURL: user.gravatarURL, | |
username: user.username, | |
admin: user.admin | |
}; | |
if (user.username === foundTutorial.owner) { | |
me.isMe = true; | |
return res.view('tutorials-detail', { | |
me: me, | |
showAddTutorialButton: true, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} else { | |
return res.view('tutorials-detail', { | |
me: { | |
gravatarURL: user.gravatarURL, | |
username: user.username, | |
admin: user.admin | |
}, | |
showAddTutorialButton: true, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tutorialDetail: function(req, res) { | |
// Find the tutorial that will be displayed | |
Tutorial.findOne({ | |
id: req.param('id') | |
}) | |
.populate('owner') | |
.populate('videos') | |
.populate('ratings') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Find all ratings made by the currently authenticated user agent | |
Rating.find({ | |
byUser: req.session.userId | |
}).exec(function(err, foundRating){ | |
if (err) return res.negotiate(err); | |
// If the user agent hasn't made any ratings, assign myRating to null | |
if (foundRating.length === 0) { | |
foundTutorial.myRating = null; | |
} else { | |
// Iterate through ratings to determine whether the rating matches | |
// the id of the tutorial to be displayed. | |
_.each(foundRating, function(rating){ | |
if (foundTutorial.id === rating.byTutorial) { | |
foundTutorial.myRating = rating.stars; | |
return; | |
} | |
}); | |
} | |
// If the tutorial has no ratings assign averageRating to null. | |
if (foundTutorial.ratings.length === 0) { | |
foundTutorial.averageRating = null; | |
} else { | |
var sumfoundTutorialRatings = 0; | |
// Iterate through each rating and add up the sum of all ratings | |
_.each(foundTutorial.ratings, function(rating){ | |
sumfoundTutorialRatings = sumfoundTutorialRatings + rating.stars; | |
}); | |
// Calculate the average rating | |
foundTutorial.averageRating = sumfoundTutorialRatings / foundTutorial.ratings.length; | |
} | |
// limit the owner attribute to the users name | |
foundTutorial.owner = foundTutorial.owner.username; | |
// Transform createdAt in time ago format | |
foundTutorial.created = DatetimeService.getTimeAgo({date: foundTutorial.createdAt}); | |
// Transform updatedAt in time ago format | |
foundTutorial.updated = DatetimeService.getTimeAgo({date: foundTutorial.updatedAt}); | |
// If not logged in set `me` property to `null` and pass the tutorial to the view | |
if (!req.session.userId) { | |
return res.view('tutorials-detail', { | |
me: null, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} | |
User.findOne(req.session.userId) | |
.exec(function(err, user) { | |
if (err) return res.negotiate(err); | |
if (!user) { | |
sails.log.verbose('Session refers to a user who no longer exists- did you delete a user, then try to refresh the page with an open tab logged-in as that user?'); | |
return res.view('tutorials-detail', { | |
me: null | |
}); | |
} | |
// We'll provide `me` as a local to the profile page view. | |
// (this is so we can render the logged-in navbar state, etc.) | |
var me = { | |
gravatarURL: user.gravatarURL, | |
username: user.username, | |
admin: user.admin | |
}; | |
if (user.username === foundTutorial.owner) { | |
me.isMe = true; | |
return res.view('tutorials-detail', { | |
me: me, | |
showAddTutorialButton: true, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} else { | |
return res.view('tutorials-detail', { | |
me: { | |
gravatarURL: user.gravatarURL, | |
username: user.username, | |
admin: user.admin | |
}, | |
showAddTutorialButton: true, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rateTutorial: function(req, res) { | |
// Find the currently authenticated user | |
User.findOne({ | |
id: req.session.userId | |
}) | |
.exec(function(err, currentUser){ | |
if (err) return res.negotiate(err); | |
if (!currentUser) return res.notFound(); | |
// Find the tutorial being rated | |
Tutorial.findOne({ | |
id: +req.param('id') | |
}) | |
.populate('owner') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Assure that the owner of the tutorial cannot rate their own tutorial. | |
// Note that this is a back-up to the front-end which already prevents the UI from being displayed. | |
if (currentUser.id === foundTutorial.owner.id) { | |
return res.forbidden(); | |
} | |
// Find the rating, if any, of the tutorial from the currently logged in user. | |
Rating.findOne({ | |
byUser: currentUser.id, | |
byTutorial: foundTutorial.id | |
}).exec(function(err, foundRating){ | |
if (err) return res.negotiate(err); | |
// If the currently authenticated user-agent (user) has previously rated this | |
// tutorial update it with the new rating. | |
if (foundRating) { | |
Rating.update({ | |
id: foundRating.id | |
}).set({ | |
stars: req.param('stars') | |
}).exec(function(err, updatedRating){ | |
if (err) return res.negotiate(err); | |
if (!updatedRating) return res.notFound(); | |
// Re-find the tutorial whose being rated to get the latest | |
Tutorial.findOne({ | |
id: req.param('id') | |
}) | |
.populate('ratings') | |
.exec(function(err, foundTutorialAfterUpdate){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorialAfterUpdate) return res.notFound(); | |
var sumTutorialRatings = 0; | |
_.each(foundTutorialAfterUpdate.ratings, function(rating){ | |
sumTutorialRatings = sumTutorialRatings + rating.stars; | |
}); | |
foundTutorialAfterUpdate.averageRating = Math.floor(sumTutorialRatings / foundTutorialAfterUpdate.ratings.length); | |
return res.json({ | |
averageRating: foundTutorialAfterUpdate.averageRating | |
}); | |
}); | |
}); | |
// If the currently authenticated user-agent (user) has not already rated this | |
// tutorial create it with the new rating. | |
} else { | |
Rating.create({ | |
stars: req.param('stars'), | |
byUser: currentUser.id, | |
byTutorial: foundTutorial.id | |
}).exec(function(err, createdRating){ | |
if (err) return res.negotiate(err); | |
if (!createdRating) return res.notFound(); | |
// Re-Find the tutorial whose being rated to get the latest | |
Tutorial.findOne({ | |
id: req.param('id') | |
}) | |
.populate('ratings') | |
.exec(function(err, foundTutorialAfterUpdate){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorialAfterUpdate) return res.notFound(); | |
var sumTutorialRatings = 0; | |
_.each(foundTutorialAfterUpdate.ratings, function(rating){ | |
sumTutorialRatings = sumTutorialRatings + rating.stars; | |
}); | |
foundTutorialAfterUpdate.averageRating = Math.floor(sumTutorialRatings / foundTutorialAfterUpdate.ratings.length); | |
return res.json({ | |
averageRating: foundTutorialAfterUpdate.averageRating | |
}); | |
}); | |
}); | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rateTutorial: function(req, res) { | |
// Find the currently authenticated user | |
User.findOne({ | |
id: req.session.userId | |
}) | |
.exec(function(err, currentUser){ | |
if (err) return res.negotiate(err); | |
if (!currentUser) return res.notFound(); | |
// Find the tutorial being rated | |
Tutorial.findOne({ | |
id: +req.param('id') | |
}) | |
.populate('owner') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Assure that the owner of the tutorial cannot rate their own tutorial. | |
// Note that this is a back-up to the front-end which already prevents the UI from being displayed. | |
if (currentUser.id === foundTutorial.owner.id) { | |
return res.forbidden(); | |
} | |
// Find the rating, if any, of the tutorial from the currently logged in user. | |
Rating.findOne({ | |
byUser: currentUser.id, | |
byTutorial: foundTutorial.id | |
}).exec(function(err, foundRating){ | |
if (err) return res.negotiate(err); | |
// If the currently authenticated user-agent (user) has previously rated this | |
// tutorial update it with the new rating. | |
if (foundRating) { | |
Rating.update({ | |
id: foundRating.id | |
}).set({ | |
stars: req.param('stars') | |
}).exec(function(err, updatedRating){ | |
if (err) return res.negotiate(err); | |
if (!updatedRating) return res.notFound(); | |
// Re-find the tutorial whose being rated to get the latest | |
Tutorial.findOne({ | |
id: req.param('id') | |
}) | |
.populate('ratings') | |
.exec(function(err, foundTutorialAfterUpdate){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorialAfterUpdate) return res.notFound(); | |
return res.json({ | |
averageRating: MathService.calculateAverage({ratings: foundTutorialAfterUpdate.ratings}) | |
}); | |
}); | |
}); | |
// If the currently authenticated user-agent (user) has not already rated this | |
// tutorial create it with the new rating. | |
} else { | |
Rating.create({ | |
stars: req.param('stars'), | |
byUser: currentUser.id, | |
byTutorial: foundTutorial.id | |
}).exec(function(err, createdRating){ | |
if (err) return res.negotiate(err); | |
if (!createdRating) return res.notFound(); | |
// Re-Find the tutorial whose being rated to get the latest | |
Tutorial.findOne({ | |
id: req.param('id') | |
}) | |
.populate('ratings') | |
.exec(function(err, foundTutorialAfterUpdate){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorialAfterUpdate) return res.notFound(); | |
return res.json({ | |
averageRating: MathService.calculateAverage({ratings: foundTutorialAfterUpdate.ratings}) | |
}); | |
}); | |
}); | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tutorialDetail: function(req, res) { | |
// Find the tutorial that will be displayed | |
Tutorial.findOne({ | |
id: req.param('id') | |
}) | |
.populate('owner') | |
.populate('videos') | |
.populate('ratings') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Find all ratings made by the currently authenticated user agent | |
Rating.find({ | |
byUser: req.session.userId | |
}).exec(function(err, foundRating){ | |
if (err) return res.negotiate(err); | |
// If the user agent hasn't made any ratings, assign myRating to null | |
if (foundRating.length === 0) { | |
foundTutorial.myRating = null; | |
} else { | |
// Iterate through ratings to determine whether the rating matches | |
// the id of the tutorial to be displayed. | |
_.each(foundRating, function(rating){ | |
if (foundTutorial.id === rating.byTutorial) { | |
foundTutorial.myRating = rating.stars; | |
return; | |
} | |
}); | |
} | |
// If the tutorial has no ratings assign averageRating to null. | |
if (foundTutorial.ratings.length === 0) { | |
foundTutorial.averageRating = null; | |
} else { | |
// Calculate the average rating | |
// Assign the average to foundTutorial.averageRating | |
foundTutorial.averageRating = MathService.calculateAverage({ratings: foundTutorial.ratings}); | |
} | |
// limit the owner attribute to the users name | |
foundTutorial.owner = foundTutorial.owner.username; | |
// Transform createdAt in time ago format | |
foundTutorial.created = DatetimeService.getTimeAgo({date: foundTutorial.createdAt}); | |
// Transform updatedAt in time ago format | |
foundTutorial.updated = DatetimeService.getTimeAgo({date: foundTutorial.updatedAt}); | |
// If not logged in set `me` property to `null` and pass the tutorial to the view | |
if (!req.session.userId) { | |
return res.view('tutorials-detail', { | |
me: null, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} | |
User.findOne(req.session.userId) | |
.exec(function(err, user) { | |
if (err) return res.negotiate(err); | |
if (!user) { | |
sails.log.verbose('Session refers to a user who no longer exists- did you delete a user, then try to refresh the page with an open tab logged-in as that user?'); | |
return res.view('tutorials-detail', { | |
me: null | |
}); | |
} | |
// We'll provide `me` as a local to the profile page view. | |
// (this is so we can render the logged-in navbar state, etc.) | |
var me = { | |
gravatarURL: user.gravatarURL, | |
username: user.username, | |
admin: user.admin | |
}; | |
if (user.username === foundTutorial.owner) { | |
me.isMe = true; | |
return res.view('tutorials-detail', { | |
me: me, | |
showAddTutorialButton: true, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} else { | |
return res.view('tutorials-detail', { | |
me: { | |
gravatarURL: user.gravatarURL, | |
username: user.username, | |
admin: user.admin | |
}, | |
showAddTutorialButton: true, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
newVideo: function(req, res) { | |
// Find the tutorial that will contain the added video | |
Tutorial.findOne({ | |
id: +req.param('id') | |
}) | |
.populate('owner') | |
.populate('ratings') | |
.populate('videos') | |
.exec(function (err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Find the currently authenticated user | |
User.findOne({ | |
id: req.session.userId | |
}).exec(function (err, foundUser) { | |
if (err) { | |
return res.negotiate(err); | |
} | |
if (!foundUser) { | |
sails.log.verbose('Session refers to a user who no longer exists.'); | |
return res.redirect('/'); | |
} | |
// TODO: Probably should be a policy | |
if (foundUser.username !== foundTutorial.owner.username) { | |
return res.redirect('/tutorials/'+foundTutorial.id); | |
} | |
/* | |
_____ __ | |
|_ _| __ __ _ _ __ ___ / _| ___ _ __ _ __ ___ | |
| || '__/ _` | '_ \/ __| |_ / _ \| '__| '_ ` _ \ | |
| || | | (_| | | | \__ \ _| (_) | | | | | | | | | |
|_||_| \__,_|_| |_|___/_| \___/|_| |_| |_| |_| | |
*/ | |
// Transform the `created` attribute into time ago format | |
foundTutorial.created = DatetimeService.getTimeAgo({date: foundTutorial.createdAt}); | |
/********************************************************************************** | |
Calculate the averge rating | |
**********************************************************************************/ | |
// Calculate the average of all existing ratings. | |
if (foundTutorial.ratings.length === 0) { | |
foundTutorial.averageRating = null; | |
} else { | |
// Assign the average to foundTutorial.stars | |
foundTutorial.stars = MathService.calculateAverage({ratings: foundTutorial.ratings}); | |
} | |
/************************************ | |
Tutorial & Video Length Formatting | |
*************************************/ | |
// Format the total time for each video and for the tutorial as a whole. | |
var totalSeconds = 0; | |
_.each(foundTutorial.videos, function(video){ | |
// Total the number of seconds for all videos for tutorial total time | |
totalSeconds = totalSeconds + video.lengthInSeconds; | |
// Format the total time for the tutorial | |
foundTutorial.totalTime = DatetimeService.getHoursMinutesSeconds({totalSeconds: totalSeconds}).hoursMinutesSeconds; | |
}); | |
return res.view('tutorials-detail-video-new', { | |
me: { | |
username: foundUser.username, | |
gravatarURL: foundUser.gravatarURL, | |
admin: foundUser.admin | |
}, | |
tutorial: { | |
id: foundTutorial.id, | |
title: foundTutorial.title, | |
description: foundTutorial.description, | |
owner: foundTutorial.owner.username, | |
created: foundTutorial.created, | |
totalTime: foundTutorial.totalTime, | |
stars: foundTutorial.stars | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
newVideo: function(req, res) { | |
// Find the tutorial that will contain the added video | |
Tutorial.findOne({ | |
id: +req.param('id') | |
}) | |
.populate('owner') | |
.populate('ratings') | |
.populate('videos') | |
.exec(function (err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Find the currently authenticated user | |
User.findOne({ | |
id: req.session.userId | |
}).exec(function (err, foundUser) { | |
if (err) { | |
return res.negotiate(err); | |
} | |
if (!foundUser) { | |
sails.log.verbose('Session refers to a user who no longer exists.'); | |
return res.redirect('/'); | |
} | |
// TODO: Probably should be a policy | |
if (foundUser.username !== foundTutorial.owner.username) { | |
return res.redirect('/tutorials/'+foundTutorial.id); | |
} | |
/* | |
_____ __ | |
|_ _| __ __ _ _ __ ___ / _| ___ _ __ _ __ ___ | |
| || '__/ _` | '_ \/ __| |_ / _ \| '__| '_ ` _ \ | |
| || | | (_| | | | \__ \ _| (_) | | | | | | | | | |
|_||_| \__,_|_| |_|___/_| \___/|_| |_| |_| |_| | |
*/ | |
// Transform the `created` attribute into time ago format | |
foundTutorial.created = DatetimeService.getTimeAgo({date: foundTutorial.createdAt}); | |
/********************************************************************************** | |
Calculate the averge rating | |
**********************************************************************************/ | |
// Calculate the average of all existing ratings. | |
if (foundTutorial.ratings.length === 0) { | |
foundTutorial.averageRating = null; | |
} else { | |
// Assign the average to foundTutorial.stars | |
foundTutorial.stars = MathService.calculateAverage({ratings: foundTutorial.ratings}); | |
} | |
/************************************ | |
Tutorial & Video Length Formatting | |
*************************************/ | |
// Format the total time for each video and for the tutorial as a whole. | |
var totalSeconds = 0; | |
_.each(foundTutorial.videos, function(video){ | |
// Total the number of seconds for all videos for tutorial total time | |
totalSeconds = totalSeconds + video.lengthInSeconds; | |
// Format the total time for the tutorial | |
foundTutorial.totalTime = DatetimeService.getHoursMinutesSeconds({totalSeconds: totalSeconds}).hoursMinutesSeconds; | |
}); | |
return res.view('tutorials-detail-video-new', { | |
me: { | |
username: foundUser.username, | |
gravatarURL: foundUser.gravatarURL, | |
admin: foundUser.admin | |
}, | |
tutorial: { | |
id: foundTutorial.id, | |
title: foundTutorial.title, | |
description: foundTutorial.description, | |
owner: foundTutorial.owner.username, | |
created: foundTutorial.created, | |
totalTime: foundTutorial.totalTime, | |
stars: foundTutorial.stars | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tutorialDetail: function(req, res) { | |
// Find the tutorial that will be displayed | |
Tutorial.findOne({ | |
id: req.param('id') | |
}) | |
.populate('owner') | |
.populate('videos') | |
.populate('ratings') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Find all ratings made by the currently authenticated user agent | |
Rating.find({ | |
byUser: req.session.userId | |
}).exec(function(err, foundRating){ | |
if (err) return res.negotiate(err); | |
// If the user agent hasn't made any ratings, assign myRating to null | |
if (foundRating.length === 0) { | |
foundTutorial.myRating = null; | |
} else { | |
// Iterate through ratings to determine whether the rating matches | |
// the id of the tutorial to be displayed. | |
_.each(foundRating, function(rating){ | |
if (foundTutorial.id === rating.byTutorial) { | |
foundTutorial.myRating = rating.stars; | |
return; | |
} | |
}); | |
} | |
// If the tutorial has no ratings assign averageRating to null. | |
if (foundTutorial.ratings.length === 0) { | |
foundTutorial.averageRating = null; | |
} else { | |
// Calculate the average rating | |
// Assign the average to foundTutorial.averageRating | |
foundTutorial.averageRating = MathService.calculateAverage({ratings: foundTutorial.ratings}); | |
} | |
var totalSeconds = 0; | |
_.each(foundTutorial.videos, function(video){ | |
totalSeconds = totalSeconds + video.lengthInSeconds; | |
video.totalTime = DatetimeService.getHoursMinutesSeconds({totalSeconds: video.lengthInSeconds}).hoursMinutesSeconds; | |
foundTutorial.totalTime = DatetimeService.getHoursMinutesSeconds({totalSeconds: totalSeconds}).hoursMinutesSeconds; | |
}); | |
// limit the owner attribute to the users name | |
foundTutorial.owner = foundTutorial.owner.username; | |
// Transform createdAt in time ago format | |
foundTutorial.created = DatetimeService.getTimeAgo({date: foundTutorial.createdAt}); | |
// Transform updatedAt in time ago format | |
foundTutorial.updated = DatetimeService.getTimeAgo({date: foundTutorial.updatedAt}); | |
// If not logged in set `me` property to `null` and pass the tutorial to the view | |
if (!req.session.userId) { | |
return res.view('tutorials-detail', { | |
me: null, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} | |
User.findOne(req.session.userId) | |
.exec(function(err, user) { | |
if (err) return res.negotiate(err); | |
if (!user) { | |
sails.log.verbose('Session refers to a user who no longer exists- did you delete a user, then try to refresh the page with an open tab logged-in as that user?'); | |
return res.view('tutorials-detail', { | |
me: null | |
}); | |
} | |
// We'll provide `me` as a local to the profile page view. | |
// (this is so we can render the logged-in navbar state, etc.) | |
var me = { | |
gravatarURL: user.gravatarURL, | |
username: user.username, | |
admin: user.admin | |
}; | |
if (user.username === foundTutorial.owner) { | |
me.isMe = true; | |
return res.view('tutorials-detail', { | |
me: me, | |
showAddTutorialButton: true, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} else { | |
return res.view('tutorials-detail', { | |
me: { | |
gravatarURL: user.gravatarURL, | |
username: user.username, | |
admin: user.admin | |
}, | |
showAddTutorialButton: true, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
addVideo: function(req, res) { | |
if (!_.isNumber(req.param('hours')) || !_.isNumber(req.param('minutes')) || !_.isNumber(req.param('seconds'))) { | |
return res.badRequest(); | |
} | |
if (!_.isString(req.param('src')) || !_.isString(req.param('title'))) { | |
return res.badRequest(); | |
} | |
Tutorial.findOne({ | |
id: +req.param('tutorialId') | |
}) | |
.populate('owner') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
if (foundTutorial.owner.id !== req.session.userId) { | |
return res.forbidden(); | |
} | |
Video.create({ | |
tutorialAssoc: foundTutorial.id, | |
title: req.param('title'), | |
src: req.param('src'), | |
lengthInSeconds: req.param('hours') * 60 * 60 + req.param('minutes') * 60 + req.param('seconds') | |
}).exec(function (err, createdVideo) { | |
if (err) return res.negotiate(err); | |
return res.ok(); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
editVideo: function(req, res) { | |
Tutorial.findOne({ | |
id: +req.param('tutorialId') | |
}) | |
.populate('videos') | |
.populate('owner') | |
.populate('ratings') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
User.findOne({ | |
id: req.session.userId | |
}).exec(function (err, foundUser) { | |
if (err) { | |
return res.negotiate(err); | |
} | |
if (!foundUser) { | |
sails.log.verbose('Session refers to a user who no longer exists- did you delete a user, then try to refresh the page with an open tab logged-in as that user?'); | |
return res.redirect('/'); | |
} | |
if (foundUser.username !== foundTutorial.owner.username) { | |
return res.redirect('/tutorials/'+foundTutorial.id); | |
} | |
/* | |
_____ __ | |
|_ _| __ __ _ _ __ ___ / _| ___ _ __ _ __ ___ | |
| || '__/ _` | '_ \/ __| |_ / _ \| '__| '_ ` _ \ | |
| || | | (_| | | | \__ \ _| (_) | | | | | | | | | |
|_||_| \__,_|_| |_|___/_| \___/|_| |_| |_| |_| | |
*/ | |
// Transform the `created` attribute into time ago format | |
foundTutorial.created = DatetimeService.getTimeAgo({date: foundTutorial.createdAt}); | |
/********************************************************************************** | |
Calculate the averge rating | |
**********************************************************************************/ | |
// Perform Average Ratings calculation if there are ratings | |
if (foundTutorial.ratings.length === 0) { | |
foundTutorial.averageRating = null; | |
} else { | |
var sumTutorialRatings = 0; | |
// Total the number of ratings for the Tutorial | |
_.each(foundTutorial.ratings, function(rating){ | |
sumTutorialRatings = sumTutorialRatings + rating.stars; | |
}); | |
// Assign the average to the tutorial | |
foundTutorial.averageRating = sumTutorialRatings / foundTutorial.ratings.length; | |
} | |
/************************************ | |
Tutorial & Video Length Formatting | |
*************************************/ | |
var totalSeconds = 0; | |
_.each(foundTutorial.videos, function(video){ | |
totalSeconds = totalSeconds + video.lengthInSeconds; | |
foundTutorial.totalTime = DatetimeService.getHoursMinutesSeconds({totalSeconds: totalSeconds}).hoursMinutesSeconds; | |
}); | |
var videoToUpdate = _.find(foundTutorial.videos, function(video){ | |
return video.id === +req.param('id'); | |
}); | |
/* | |
_____ | |
| __ \ | |
| |__) |___ ___ _ __ ___ _ __ ___ ___ | |
| _ // _ \/ __| '_ \ / _ \| '_ \/ __|/ _ \ | |
| | \ \ __/\__ \ |_) | (_) | | | \__ \ __/ | |
|_| \_\___||___/ .__/ \___/|_| |_|___/\___| | |
| | | |
|_| | |
*/ | |
return res.view('tutorials-detail-video-edit', { | |
me: { | |
username: foundUser.username, | |
gravatarURL: foundUser.gravatarURL, | |
admin: foundUser.admin | |
}, | |
tutorial: { | |
id: foundTutorial.id, | |
title: foundTutorial.title, | |
description: foundTutorial.description, | |
owner: foundTutorial.owner.username, | |
created: foundTutorial.created, | |
totalTime: foundTutorial.totalTime, | |
averageRating: foundTutorial.averageRating, | |
video: { | |
id: videoToUpdate.id, | |
title: videoToUpdate.title, | |
src: videoToUpdate.src, | |
hours: DatetimeService.getHoursMinutesSeconds({totalSeconds: videoToUpdate.lengthInSeconds}).hours, | |
minutes: DatetimeService.getHoursMinutesSeconds({totalSeconds: videoToUpdate.lengthInSeconds}).minutes, | |
seconds: DatetimeService.getHoursMinutesSeconds({totalSeconds: videoToUpdate.lengthInSeconds}).seconds | |
} | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
updateVideo: function(req, res) { | |
/* | |
__ __ _ _ _ _ _ | |
\ \ / /_ _| (_)__| |__ _| |_(_)___ _ _ | |
\ V / _` | | / _` / _` | _| / _ \ ' \ | |
\_/\__,_|_|_\__,_\__,_|\__|_\___/_||_| | |
*/ | |
if (!_.isString(req.param('title'))) { | |
return res.badRequest(); | |
} | |
if (!_.isString(req.param('src'))) { | |
return res.badRequest(); | |
} | |
if (!_.isNumber(req.param('hours')) || !_.isNumber(req.param('minutes')) || !_.isNumber(req.param('seconds'))) { | |
return res.badRequest(); | |
} | |
// Coerce the hours, minutes, seconds parameter to integers | |
var hours = +req.param('hours'); | |
var minutes = +req.param('minutes'); | |
var seconds = +req.param('seconds'); | |
// Calculate the total seconds of the video and store that value as lengthInSeconds | |
var convertedToSeconds = hours * 60 * 60 + minutes * 60 + seconds; | |
Video.findOne({ | |
id: +req.param('id') | |
}) | |
.populate('tutorialAssoc') | |
.exec(function (err, foundVideo){ | |
if (err) return res.negotiate (err); | |
if (!foundVideo) return res.notFound(); | |
// Assure that the currently logged in user is the owner of the tutorial | |
if (req.session.userId !== foundVideo.tutorialAssoc.owner) { | |
return res.forbidden(); | |
} | |
// Update the video | |
Video.update({ | |
id: +req.param('id') | |
}, { | |
title: req.param('title'), | |
src: req.param('src'), | |
lengthInSeconds: convertedToSeconds | |
}).exec(function (err, updatedUser){ | |
if (err) return res.negotiate(err); | |
if (!updatedUser) return res.notFound(); | |
return res.ok(); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
createTutorial: function(req, res) { | |
/* | |
__ __ _ _ _ _ _ | |
\ \ / /_ _| (_)__| |__ _| |_(_)___ _ _ | |
\ V / _` | | / _` / _` | _| / _ \ ' \ | |
\_/\__,_|_|_\__,_\__,_|\__|_\___/_||_| | |
*/ | |
if (!_.isString(req.param('title'))) { | |
return res.badRequest(); | |
} | |
if (!_.isString(req.param('description'))) { | |
return res.badRequest(); | |
} | |
// Find the user that's adding a tutorial | |
User.findOne({ | |
id: req.session.userId | |
}).exec(function(err, foundUser){ | |
if (err) return res.negotiate; | |
if (!foundUser) return res.notFound(); | |
Tutorial.create({ | |
title: req.param('title'), | |
description: req.param('description'), | |
owner: foundUser.id, | |
videoOrder: [] | |
}) | |
.exec(function(err, createdTutorial){ | |
if (err) return res.negotiate(err); | |
return res.json({id: createdTutorial.id}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
addVideo: function(req, res) { | |
if (!_.isNumber(req.param('hours')) || !_.isNumber(req.param('minutes')) || !_.isNumber(req.param('seconds'))) { | |
return res.badRequest(); | |
} | |
if (!_.isString(req.param('src')) || !_.isString(req.param('title'))) { | |
return res.badRequest(); | |
} | |
Tutorial.findOne({ | |
id: +req.param('tutorialId') | |
}) | |
.populate('owner') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
if (foundTutorial.owner.id !== req.session.userId) { | |
return res.forbidden(); | |
} | |
Video.create({ | |
tutorialAssoc: foundTutorial.id, | |
title: req.param('title'), | |
src: req.param('src'), | |
lengthInSeconds: req.param('hours') * 60 * 60 + req.param('minutes') * 60 + req.param('seconds') | |
}).exec(function (err, createdVideo) { | |
if (err) return res.negotiate(err); | |
// Add this video to the `videoOrder` array embedded in our tutorial . | |
// (We always add new videos to the bottom of the list) | |
foundTutorial.videoOrder.push(createdVideo.id); | |
return res.ok(); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
tutorialDetail: function(req, res) { | |
// Find the tutorial that will be displayed | |
Tutorial.findOne({ | |
id: req.param('id') | |
}) | |
.populate('owner') | |
.populate('videos') | |
.populate('ratings') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Find all ratings made by the currently authenticated user agent | |
Rating.find({ | |
byUser: req.session.userId | |
}).exec(function(err, foundRating){ | |
if (err) return res.negotiate(err); | |
// If the user agent hasn't made any ratings, assign myRating to null | |
if (foundRating.length === 0) { | |
foundTutorial.myRating = null; | |
} else { | |
// Iterate through ratings to determine whether the rating matches | |
// the id of the tutorial to be displayed. | |
_.each(foundRating, function(rating){ | |
if (foundTutorial.id === rating.byTutorial) { | |
foundTutorial.myRating = rating.stars; | |
return; | |
} | |
}); | |
} | |
// If the tutorial has no ratings assign averageRating to null. | |
if (foundTutorial.ratings.length === 0) { | |
foundTutorial.averageRating = null; | |
} else { | |
// Calculate the average rating | |
// Assign the average to foundTutorial.averageRating | |
foundTutorial.averageRating = MathService.calculateAverage({ratings: foundTutorial.ratings}); | |
} | |
var totalSeconds = 0; | |
_.each(foundTutorial.videos, function(video){ | |
totalSeconds = totalSeconds + video.lengthInSeconds; | |
video.totalTime = DatetimeService.getHoursMinutesSeconds({totalSeconds: video.lengthInSeconds}).hoursMinutesSeconds; | |
foundTutorial.totalTime = DatetimeService.getHoursMinutesSeconds({totalSeconds: totalSeconds}).hoursMinutesSeconds; | |
}); | |
// limit the owner attribute to the users name | |
foundTutorial.owner = foundTutorial.owner.username; | |
// Transform createdAt in time ago format | |
foundTutorial.created = DatetimeService.getTimeAgo({date: foundTutorial.createdAt}); | |
// Transform updatedAt in time ago format | |
foundTutorial.updated = DatetimeService.getTimeAgo({date: foundTutorial.updatedAt}); | |
/************** | |
Video Order | |
***************/ | |
// Use the embedded `videoOrder` array to apply the manual sort order | |
// to our videos. | |
foundTutorial.videos = _.sortBy(foundTutorial.videos, function getRank (video) { | |
// We use the index of this video id within the `videoOrder` array as our sort rank. | |
// Because that array is in the proper order, if we use the index of this video id as | |
// the rank, then the newly sorted `tutorial.videos` array will be in the same order. | |
return _.indexOf(foundTutorial.videoOrder,video.id); | |
}); | |
// Given (e.g.): | |
// tutorial.videoOrder= [3, 4, 5] | |
// tutorial.videos = [{id: 5}, {id: 4}, {id: 3}] | |
// | |
// Yields (e.g.): | |
// tutorial.videos <== [{id: 3}, {id: 4}, {id: 5}] | |
// If not logged in set `me` property to `null` and pass the tutorial to the view | |
if (!req.session.userId) { | |
return res.view('tutorials-detail', { | |
me: null, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} | |
User.findOne(req.session.userId) | |
.exec(function(err, user) { | |
if (err) return res.negotiate(err); | |
if (!user) { | |
sails.log.verbose('Session refers to a user who no longer exists- did you delete a user, then try to refresh the page with an open tab logged-in as that user?'); | |
return res.view('tutorials-detail', { | |
me: null | |
}); | |
} | |
// We'll provide `me` as a local to the profile page view. | |
// (this is so we can render the logged-in navbar state, etc.) | |
var me = { | |
gravatarURL: user.gravatarURL, | |
username: user.username, | |
admin: user.admin | |
}; | |
if (user.username === foundTutorial.owner) { | |
me.isMe = true; | |
return res.view('tutorials-detail', { | |
me: me, | |
showAddTutorialButton: true, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} else { | |
return res.view('tutorials-detail', { | |
me: { | |
gravatarURL: user.gravatarURL, | |
username: user.username, | |
admin: user.admin | |
}, | |
showAddTutorialButton: true, | |
stars: foundTutorial.stars, | |
tutorial: foundTutorial | |
}); | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
reorderVideoUp: function(req, res) { | |
// Look up the video with the specified id | |
// (and populate the tutorial it belongs to) | |
Video.findOne({ | |
id: +req.param('id') | |
}) | |
.populate('tutorialAssoc') // consider renaming this association to `partOfTutorial` | |
.exec(function (err, foundVideo){ | |
if (err) return res.negotiate(err); | |
if (!foundVideo) return res.notFound(); | |
// Assure that the owner of the tutorial cannot rate their own tutorial. | |
// Note that this is a back-up to the front-end which already prevents the UI from being displayed. | |
if (req.session.userId !== foundVideo.tutorialAssoc.owner) { | |
return res.forbidden(); | |
} | |
// Modify the tutorial's `videoOrder` to move the video with the | |
// specified id up in the list. | |
// Find the index of the video id within the array. | |
var indexOfVideo = _.indexOf(foundVideo.tutorialAssoc.videoOrder, +req.param('id')); | |
// If this is already the first video in the list, consider this a bad request. | |
// (this should have been prevented on the front-end already, but we're just being safe) | |
if (indexOfVideo === 0) { | |
return res.badRequest('This video is already at the top of the list.'); | |
} | |
// Remove the video id from its current position in the array | |
foundVideo.tutorialAssoc.videoOrder.splice(indexOfVideo, 1); | |
// Insert the video id at the new position within the array | |
foundVideo.tutorialAssoc.videoOrder.splice(indexOfVideo-1, 0, +req.param('id')); | |
// Persist the tutorial record back to the database. | |
foundVideo.tutorialAssoc.save(function (err) { | |
if (err) return res.negotiate(err); | |
return res.ok(); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
reorderVideoDown: function(req, res) { | |
// Look up the video with the specified id | |
// (and populate the tutorial it belongs to) | |
Video.findOne({ | |
id: +req.param('id') | |
}) | |
.populate('tutorialAssoc') // consider renaming this association to `partOfTutorial` | |
.exec(function (err, foundVideo){ | |
if (err) return res.negotiate(err); | |
if (!foundVideo) return res.notFound(); | |
// Assure that the owner of the tutorial cannot rate their own tutorial. | |
// Note that this is a back-up to the front-end which already prevents the UI from being displayed. | |
if (req.session.userId !== foundVideo.tutorialAssoc.owner) { | |
return res.forbidden(); | |
} | |
// Modify the tutorial's `videoOrder` to move the video with the | |
// specified id up in the list. | |
// Find the index of the video id within the array. | |
var indexOfVideo = _.indexOf(foundVideo.tutorialAssoc.videoOrder, +req.param('id')); | |
var numberOfTutorials = foundVideo.tutorialAssoc.videoOrder.length; | |
// If this is already the last video in the list, consider this a bad request. | |
// (this should have been prevented on the front-end already, but we're just being safe) | |
if (indexOfVideo === numberOfTutorials) { | |
return res.badRequest('This video is already at the bottom of the list.'); | |
} | |
// Remove the video id from its current position in the array | |
foundVideo.tutorialAssoc.videoOrder.splice(indexOfVideo, 1); | |
// Insert the video id at the new position within the array | |
foundVideo.tutorialAssoc.videoOrder.splice(indexOfVideo+1, 0, +req.param('id')); | |
// Persist the tutorial record back to the database. | |
foundVideo.tutorialAssoc.save(function (err) { | |
if (err) return res.negotiate(err); | |
return res.ok(); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
showVideo: function(req, res) { | |
// Simulating a found video | |
var video = { | |
id: 34, | |
title: 'Crockford on JavaScript - Volume 1: The Early Years', | |
src: 'https://www.youtube.com/embed/JxAXlJEmNMg' | |
}; | |
FAKE_CHAT = [{ | |
username: 'sailsinaction', | |
message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum ornare.', | |
created: '2 minutes ago', | |
gravatarURL: 'http://www.gravatar.com/avatar/ef3eac6c71fdf24b13db12d8ff8d1264' | |
}, { | |
username: 'nikolatesla', | |
message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum ornare.', | |
created: '2 minutes ago', | |
gravatarURL: 'http://www.gravatar.com/avatar/c06112bbecd8a290a00441bf181a24d3?' | |
}, { | |
username: 'sailsinaction', | |
message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum ornare.', | |
created: '2 minutes ago', | |
gravatarURL: 'http://www.gravatar.com/avatar/ef3eac6c71fdf24b13db12d8ff8d1264' | |
}, { | |
username: 'nikolatesla', | |
message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum ornare.', | |
created: '2 minutes ago', | |
gravatarURL: 'http://www.gravatar.com/avatar/c06112bbecd8a290a00441bf181a24d3?' | |
}, { | |
username: 'sailsinaction', | |
message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum ornare.', | |
created: '2 minutes ago', | |
gravatarURL: 'http://www.gravatar.com/avatar/ef3eac6c71fdf24b13db12d8ff8d1264' | |
}, { | |
username: 'nikolatesla', | |
message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum ornare.', | |
created: '2 minutes ago', | |
gravatarURL: 'http://www.gravatar.com/avatar/c06112bbecd8a290a00441bf181a24d3?' | |
}, { | |
username: 'sailsinaction', | |
message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum ornare.', | |
created: '2 minutes ago', | |
gravatarURL: 'http://www.gravatar.com/avatar/ef3eac6c71fdf24b13db12d8ff8d1264' | |
}, { | |
username: 'nikolatesla', | |
message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum ornare.', | |
created: '2 minutes ago', | |
gravatarURL: 'http://www.gravatar.com/avatar/c06112bbecd8a290a00441bf181a24d3?' | |
}, { | |
username: 'sailsinaction', | |
message: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur bibendum ornare.', | |
created: '2 minutes ago', | |
gravatarURL: 'http://www.gravatar.com/avatar/ef3eac6c71fdf24b13db12d8ff8d1264' | |
}]; | |
// If not logged in | |
if (!req.session.userId) { | |
return res.view('show-video', { | |
me: null, | |
video: video, | |
tutorialId: req.param('tutorialId'), | |
chats: FAKE_CHAT | |
}); | |
} | |
// If logged in... | |
User.findOne({ | |
id: +req.session.userId | |
}).exec(function (err, foundUser) { | |
if (err) { | |
return res.negotiate(err); | |
} | |
if (!foundUser) { | |
sails.log.verbose('Session refers to a user who no longer exists- did you delete a user, then try to refresh the page with an open tab logged-in as that user?'); | |
} | |
return res.view('show-video', { | |
me: { | |
username: foundUser.username, | |
gravatarURL: foundUser.gravatarURL, | |
admin: foundUser.admin | |
}, | |
video: video, | |
tutorialId: req.param('tutorialId'), | |
chats: FAKE_CHAT | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
deleteTutorial: function(req, res) { | |
// Find the currently logged in user and her tutorials | |
User.findOne({ | |
id: req.session.userId | |
}).exec(function (err, foundUser){ | |
if (err) return res.negotiate(err); | |
if (!foundUser) return res.notFound(); | |
Tutorial.findOne({ | |
id: +req.param('id') | |
}) | |
.populate('owner') | |
.populate ('ratings') | |
.populate('videos') | |
.exec(function(err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Check ownership | |
if (foundUser.id != foundTutorial.owner.id) { | |
return res.forbidden(); | |
} | |
// Destroy the tutorial | |
Tutorial.destroy({ | |
id: req.param('id') | |
}).exec(function(err){ | |
if (err) return res.negotiate(err); | |
// Destroy videos | |
Video.destroy({ | |
id: _.pluck(foundTutorial.videos, 'id') | |
}).exec(function (err){ | |
if (err) return res.negotiate(err); | |
// Destroy ratings | |
Rating.destroy({ | |
id: _.pluck(foundTutorial.ratings, 'id') | |
}).exec(function (err){ | |
if (err) return res.negotiate(err); | |
// Return the username of the user using the userId of the session. | |
return res.json({username: foundUser.username}); | |
}); | |
}); | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
removeVideo: function(req, res) { | |
Tutorial.findOne({ | |
id: +req.param('tutorialId') | |
}) | |
.exec(function (err, foundTutorial){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorial) return res.notFound(); | |
// Check ownership | |
if (req.session.userId !== foundTutorial.owner) { | |
return res.forbidden(); | |
} | |
// Remove the reference to this video from our tutorial record. | |
foundTutorial.videos.remove(+req.param('id')); | |
// Remove this video id from the `videoOrder` array | |
foundTutorial.videoOrder = _.without(foundTutorial.videoOrder, +req.param('id')); | |
// Persist our tutorial back to the database. | |
foundTutorial.save(function (err){ | |
if (err) return res.negotiate(err); | |
Video.destroy({ | |
id: +req.param('id') | |
}).exec(function(err){ | |
if (err) return res.negotiate(err); | |
return res.ok(); | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
profile: function(req, res) { | |
User.findOne({ | |
username: req.param('username') | |
}) | |
.populate("followers") | |
.populate("following") | |
.exec(function (err, foundUser){ | |
if (err) return res.negotiate(err); | |
if (!foundUser) return res.notFound(); | |
Tutorial.find({where: { | |
owner: foundUser.id | |
}, sort: 'title ASC'}) | |
.populate('ratings') | |
.populate('videos') | |
.exec(function (err, foundTutorials){ | |
if (err) return res.negotiate(err); | |
if (!foundTutorials) return res.notFound(); | |
/* | |
_____ __ | |
|_ _| __ __ _ _ __ ___ / _| ___ _ __ _ __ ___ | |
| || '__/ _` | '_ \/ __| |_ / _ \| '__| '_ ` _ \ | |
| || | | (_| | | | \__ \ _| (_) | | | | | | | | | |
|_||_| \__,_|_| |_|___/_| \___/|_| |_| |_| |_| | |
*/ | |
_.each(foundTutorials, function(tutorial){ | |
// sync owner | |
tutorial.owner = foundUser.username; | |
// Format the createdAt attributes and assign them to the tutorial | |
tutorial.created = DatetimeService.getTimeAgo({date: tutorial.createdAt}); | |
// Format Videos | |
var totalSeconds = 0; | |
_.each(tutorial.videos, function(video){ | |
// Total the number of seconds for all videos for tutorial total time | |
totalSeconds = totalSeconds + video.lengthInSeconds; | |
tutorial.totalTime = DatetimeService.getHoursMinutesSeconds({totalSeconds: totalSeconds}).hoursMinutesSeconds; | |
}); | |
// Format average ratings | |
var totalRating = 0; | |
_.each(tutorial.ratings, function(rating){ | |
totalRating = totalRating + rating.stars; | |
}); | |
var averageRating = 0; | |
if (tutorial.ratings.length < 1) { | |
averageRating = 0; | |
} else { | |
averageRating = totalRating / tutorial.ratings.length; | |
} | |
tutorial.averageRating = averageRating; | |
}); | |
// The logged out case | |
if (!req.session.userId) { | |
return res.view('profile', { | |
// This is for the navigation bar | |
me: null, | |
// This is for profile body | |
username: foundUser.username, | |
gravatarURL: foundUser.gravatarURL, | |
frontEnd: { | |
numOfTutorials: foundTutorials.length, | |
numOfFollowers: foundUser.followers.length, | |
numOfFollowing: foundUser.following.length | |
}, | |
// This is for the list of tutorials | |
tutorials: foundTutorials | |
}); | |
} | |
// Otherwise the user-agent IS logged in. | |
// Look up the logged-in user from the database. | |
User.findOne({ | |
id: req.session.userId | |
}) | |
.exec(function (err, loggedInUser){ | |
if (err) { | |
return res.negotiate(err); | |
} | |
if (!loggedInUser) { | |
return res.serverError('User record from logged in user is missing?'); | |
} | |
// Is the logged in user is currently following the owner of this tutorial? | |
var cachedFollower = _.find(foundUser.followers, function(follower){ | |
return follower.id === loggedInUser.id; | |
}); | |
var followedByLoggedInUser = false; | |
if (cachedFollower) { | |
followedByLoggedInUser = true; | |
} | |
// We'll provide `me` as a local to the profile page view. | |
// (this is so we can render the logged-in navbar state, etc.) | |
var me = { | |
username: loggedInUser.username, | |
email: loggedInUser.email, | |
gravatarURL: loggedInUser.gravatarURL, | |
admin: loggedInUser.admin | |
}; | |
// We'll provide the `isMe` flag to the profile page view | |
// if the logged-in user is the same as the user whose profile we looked up earlier. | |
if (req.session.userId === foundUser.id) { | |
me.isMe = true; | |
} else { | |
me.isMe = false; | |
} | |
// Return me property for the nav and the remaining properties for the profile page. | |
return res.view('profile', { | |
me: me, | |
showAddTutorialButton: true, | |
username: foundUser.username, | |
gravatarURL: foundUser.gravatarURL, | |
frontEnd: { | |
numOfTutorials: foundTutorials.length, | |
numOfFollowers: foundUser.followers.length, | |
numOfFollowing: foundUser.following.length, | |
followedByLoggedInUser: followedByLoggedInUser | |
}, | |
tutorials: foundTutorials | |
}); | |
}); //</ User.findOne({id: req.session.userId}) | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
profileFollower: function(req, res) { | |
User.findOne({ | |
username: req.param('username') | |
}) | |
.populate("followers") | |
.populate("following") | |
.populate("tutorials") | |
.exec(function (err, foundUser){ | |
if (err) return res.negotiate(err); | |
if (!foundUser) return res.notFound(); | |
// The logged out case | |
if (!req.session.userId) { | |
return res.view('profile-followers', { | |
// This is for the navigation bar | |
me: null, | |
// This is for profile body | |
username: foundUser.username, | |
gravatarURL: foundUser.gravatarURL, | |
frontEnd: { | |
numOfTutorials: foundUser.tutorials.length, | |
numOfFollowers: foundUser.followers.length, | |
numOfFollowing: foundUser.following.length, | |
followers: foundUser.followers | |
}, | |
// This is for the list of followers | |
followers: foundUser.followers | |
}); | |
} | |
// Otherwise the user-agent IS logged in. | |
// Look up the logged-in user from the database. | |
User.findOne({ | |
id: req.session.userId | |
}) | |
.populate('following') | |
.exec(function (err, loggedInUser){ | |
if (err) { | |
return res.negotiate(err); | |
} | |
if (!loggedInUser) { | |
return res.serverError('User record from logged in user is missing?'); | |
} | |
// Is the logged in user currently following the owner of this tutorial? | |
var cachedFollower = _.find(foundUser.followers, function(follower){ | |
return follower.id === loggedInUser.id; | |
}); | |
// Set the display toggle (followedByLoggedInUser) based upon whether | |
// the currently logged in user is following the owner of the tutorial. | |
var followedByLoggedInUser = false; | |
if (cachedFollower) { | |
followedByLoggedInUser = true; | |
} | |
// We'll provide `me` as a local to the profile page view. | |
// (this is so we can render the logged-in navbar state, etc.) | |
var me = { | |
username: loggedInUser.username, | |
email: loggedInUser.email, | |
gravatarURL: loggedInUser.gravatarURL, | |
admin: loggedInUser.admin | |
}; | |
// We'll provide the `isMe` flag to the profile page view | |
// if the logged-in user is the same as the user whose profile we looked up earlier. | |
if (req.session.userId === foundUser.id) { | |
me.isMe = true; | |
} else { | |
me.isMe = false; | |
} | |
// Return me property for the nav and the remaining properties for the profile page. | |
return res.view('profile-followers', { | |
me: me, | |
showAddTutorialButton: true, | |
username: foundUser.username, | |
gravatarURL: foundUser.gravatarURL, | |
frontEnd: { | |
numOfTutorials: foundUser.tutorials.length, | |
numOfFollowers: foundUser.followers.length, | |
numOfFollowing: foundUser.following.length, | |
followedByLoggedInUser: followedByLoggedInUser, | |
followers: foundUser.followers | |
}, | |
followers: foundUser.followers | |
}); | |
}); //</ User.findOne({id: req.session.userId}) | |
}); | |
}, | |
profileFollowing: function(req, res) { | |
User.findOne({ | |
username: req.param('username') | |
}) | |
.populate("followers") | |
.populate("following") | |
.populate("tutorials") | |
.exec(function (err, foundUser){ | |
if (err) return res.negotiate(err); | |
if (!foundUser) return res.notFound(); | |
// The logged out case | |
if (!req.session.userId) { | |
return res.view('profile-following', { | |
// This is for the navigation bar | |
me: null, | |
// This is for profile body | |
username: foundUser.username, | |
gravatarURL: foundUser.gravatarURL, | |
frontEnd: { | |
numOfTutorials: foundUser.tutorials.length, | |
numOfFollowers: foundUser.followers.length, | |
numOfFollowing: foundUser.following.length, | |
following: foundUser.following | |
}, | |
// This is for the list of following | |
following: foundUser.following | |
}); | |
} | |
// Otherwise the user-agent IS logged in. | |
// Look up the logged-in user from the database. | |
User.findOne({ | |
id: req.session.userId | |
}) | |
.populate('following') | |
.exec(function (err, loggedInUser){ | |
if (err) { | |
return res.negotiate(err); | |
} | |
if (!loggedInUser) { | |
return res.serverError('User record from logged in user is missing?'); | |
} | |
// Is the logged in user currently following the owner of this tutorial? | |
var cachedFollower = _.find(foundUser.followers, function(follower){ | |
return follower.id === loggedInUser.id; | |
}); | |
// Set the display toggle (followedByLoggedInUser) based upon whether | |
// the currently logged in user is following the owner of the tutorial. | |
var followedByLoggedInUser = false; | |
if (cachedFollower) { | |
followedByLoggedInUser = true; | |
} | |
// We'll provide `me` as a local to the profile page view. | |
// (this is so we can render the logged-in navbar state, etc.) | |
var me = { | |
username: loggedInUser.username, | |
email: loggedInUser.email, | |
gravatarURL: loggedInUser.gravatarURL, | |
admin: loggedInUser.admin | |
}; | |
// We'll provide the `isMe` flag to the profile page view | |
// if the logged-in user is the same as the user whose profile we looked up earlier. | |
if (req.session.userId === foundUser.id) { | |
me.isMe = true; | |
} else { | |
me.isMe = false; | |
} | |
// Return me property for the nav and the remaining properties for the profile page. | |
return res.view('profile-following', { | |
me: me, | |
showAddTutorialButton: true, | |
username: foundUser.username, | |
gravatarURL: foundUser.gravatarURL, | |
frontEnd: { | |
numOfTutorials: foundUser.tutorials.length, | |
numOfFollowers: foundUser.followers.length, | |
numOfFollowing: foundUser.following.length, | |
followedByLoggedInUser: followedByLoggedInUser, | |
following: foundUser.following | |
}, | |
following: foundUser.following | |
}); | |
}); //</ User.findOne({id: req.session.userId}) | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
searchTutorials: function(req, res) { | |
Tutorial.count().exec(function(err, found){ | |
if (err) return res.negotiate(err); | |
if (!found) return res.notFound(); | |
Tutorial.find({ | |
or : [ | |
{ | |
title: { | |
'contains': req.param('searchCriteria') | |
}, | |
}, | |
{ | |
description: { | |
'contains': req.param('searchCriteria') | |
} | |
} | |
], | |
limit: 10, | |
skip: req.param('skip') | |
}) | |
.populate('owner') | |
.populate('ratings') | |
.populate('videos') | |
.exec(function(err, tutorials){ | |
// Iterate through tutorials to format the owner and created attributes | |
_.each(tutorials, function(tutorial){ | |
tutorial.owner = tutorial.owner.username; | |
tutorial.created = DatetimeService.getTimeAgo({date: tutorial.createdAt}); | |
// Determine the total seconds for all videos and each video | |
var totalSeconds = 0; | |
_.each(tutorial.videos, function(video){ | |
// Total the number of seconds for all videos for tutorial total time | |
totalSeconds = totalSeconds + video.lengthInSeconds; | |
tutorial.totalTime = DatetimeService.getHoursMinutesSeconds({totalSeconds: totalSeconds}).hoursMinutesSeconds; | |
// Format average ratings | |
var totalRating = 0; | |
_.each(tutorial.ratings, function(rating){ | |
totalRating = totalRating + rating.stars; | |
}); | |
var averageRating = 0; | |
if (tutorial.ratings.length < 1) { | |
averageRating = 0; | |
} else { | |
averageRating = totalRating / tutorial.ratings.length; | |
} | |
tutorial.averageRating = averageRating; | |
}); | |
}); | |
return res.json({ | |
options: { | |
totalTutorials: found, | |
updatedTutorials: tutorials | |
} | |
}); | |
}); | |
}); | |
}, |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
browseTutorials: function(req, res) { | |
Tutorial.count().exec(function (err, numberOfTutorials){ | |
if (err) return res.negotiate(err); | |
if (!numberOfTutorials) return res.notFound(); | |
Tutorial.find({ | |
limit: 10, | |
skip: req.param('skip') | |
}) | |
.populate('owner') | |
.populate('ratings') | |
.populate('videos') | |
.exec(function(err, foundTutorials){ | |
_.each(foundTutorials, function(tutorial){ | |
tutorial.owner = tutorial.owner.username; | |
tutorial.created = DatetimeService.getTimeAgo({date: tutorial.createdAt}); | |
var totalSeconds = 0; | |
_.each(tutorial.videos, function(video){ | |
// Total the number of seconds for all videos for tutorial total time | |
totalSeconds = totalSeconds + video.lengthInSeconds; | |
tutorial.totalTime = DatetimeService.getHoursMinutesSeconds({totalSeconds: totalSeconds}).hoursMinutesSeconds; | |
// Format average ratings | |
var totalRating = 0; | |
_.each(tutorial.ratings, function(rating){ | |
totalRating = totalRating + rating.stars; | |
}); | |
var averageRating = 0; | |
if (tutorial.ratings.length < 1) { | |
averageRating = 0; | |
} else { | |
averageRating = totalRating / tutorial.ratings.length; | |
} | |
tutorial.averageRating = averageRating; | |
}); | |
}); | |
return res.json({ | |
options: { | |
totalTutorials: numberOfTutorials, | |
updatedTutorials: foundTutorials | |
} | |
}); | |
}); | |
}); | |
}, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment