Vulcan/packages/telescope-posts/lib/methods.js
Maxime Quandalle 94c6121d91 Improve jsHint consistency
This commit touch a lot of lines of code with the goal to be more
rigorous about JavaScript code conventions defined in the `.jshintrc`.

Some modification:

* Add a list of used global symbols in the corresponding section of
  `.jshintrc`
* Use local variables instead of global in a lot of places where the
  keyword `var` was mistakenly forgotten
* Add missing semi-colons after instructions
* Add new lines at the end of files
* Remove trailing whitespaces
* Use newer name of some Meteor APIs, eg `addFiles` instead of
  `add_files`
* Add missing `break` statements in `switch` blocks
* Use `===` instead of `==` and `!==` instead of `!=`
* Remove unused variables

This commit should also fix a few bugs due to this lack of rigor. One
example of that was the test `typeof navElements === "array"` that was
never true because in JavaScript, `typeof [] === "object"`, we
replaced this test by the `_.isArray` method provided by underscore.
It might also fix some potential collision related to global
variables.

There is still plenty of work until Telescope code base passes jsHint
validation, but at least this commit is a step in the right direction.
2015-05-01 18:38:27 +02:00

263 lines
8.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
*
* Post Methods
*
*/
/**
* Insert a post in the database (note: optional post properties not listed here)
* @param {Object} post the post being inserted
* @param {string} post.userId the id of the user the post belongs to
* @param {string} post.title - the post's title
*/
Posts.submit = function (post) {
var userId = post.userId, // at this stage, a userId is expected
user = Meteor.users.findOne(userId);
// ------------------------------ Checks ------------------------------ //
// check that a title was provided
if(!post.title)
throw new Meteor.Error(602, i18n.t('please_fill_in_a_title'));
// check that there are no posts with the same URL
if(!!post.url)
Posts.checkForSameUrl(post.url, user);
// ------------------------------ Properties ------------------------------ //
var defaultProperties = {
createdAt: new Date(),
author: Users.getDisplayNameById(userId),
upvotes: 0,
downvotes: 0,
commentCount: 0,
clickCount: 0,
viewCount: 0,
baseScore: 0,
score: 0,
inactive: false,
sticky: false,
status: Posts.getDefaultStatus()
};
post = _.extend(defaultProperties, post);
// if post is approved but doesn't have a postedAt date, give it a default date
// note: pending posts get their postedAt date only once theyre approved
if (post.status === Posts.config.STATUS_APPROVED && !post.postedAt)
post.postedAt = new Date();
// clean up post title
post.title = Telescope.utils.cleanUp(post.title);
// ------------------------------ Callbacks ------------------------------ //
// run all post submit server callbacks on post object successively
post = Telescope.callbacks.run("postSubmit", post);
// -------------------------------- Insert ------------------------------- //
post._id = Posts.insert(post);
// --------------------- Server-Side Async Callbacks --------------------- //
Telescope.callbacks.run("postSubmitAsync", post, true);
return post;
};
// ------------------------------------------------------------------------------------------- //
// ----------------------------------------- Methods ----------------------------------------- //
// ------------------------------------------------------------------------------------------- //
var postViews = [];
Meteor.methods({
submitPost: function(post){
// required properties:
// title
// optional properties
// URL
// body
// categories
// thumbnailUrl
// NOTE: the current user and the post author user might be two different users!
var user = Meteor.user(),
hasAdminRights = Users.is.admin(user),
schema = Posts.simpleSchema()._schema;
// ------------------------------ Checks ------------------------------ //
// check that user can post
if (!user || !Users.can.post(user))
throw new Meteor.Error(601, i18n.t('you_need_to_login_or_be_invited_to_post_new_stories'));
// --------------------------- Rate Limiting -------------------------- //
if(!hasAdminRights){
var timeSinceLastPost = Users.timeSinceLast(user, Posts),
numberOfPostsInPast24Hours = Users.numberOfItemsInPast24Hours(user, Posts),
postInterval = Math.abs(parseInt(Settings.get('postInterval', 30))),
maxPostsPer24Hours = Math.abs(parseInt(Settings.get('maxPostsPerDay', 30)));
// check that user waits more than X seconds between posts
if(timeSinceLastPost < postInterval)
throw new Meteor.Error(604, i18n.t('please_wait')+(postInterval-timeSinceLastPost)+i18n.t('seconds_before_posting_again'));
// check that the user doesn't post more than Y posts per day
if(numberOfPostsInPast24Hours > maxPostsPer24Hours)
throw new Meteor.Error(605, i18n.t('sorry_you_cannot_submit_more_than')+maxPostsPer24Hours+i18n.t('posts_per_day'));
}
// ------------------------------ Properties ------------------------------ //
// admin-only properties
// status
// postedAt
// userId
// sticky (default to false)
// go over each schema field and throw an error if it's not editable
_.keys(post).forEach(function (fieldName) {
var field = schema[fieldName];
if (!Users.can.submitField(user, field)) {
throw new Meteor.Error("disallowed_property", i18n.t('disallowed_property_detected') + ": " + fieldName);
}
});
// if no post status has been set, set it now
if (!post.status) {
post.status = Posts.getDefaultStatus(user);
}
// if no userId has been set, default to current user id
if (!post.userId) {
post.userId = user._id;
}
return Posts.submit(post);
},
editPost: function (modifier, postId) {
var user = Meteor.user(),
post = Posts.findOne(postId),
schema = Posts.simpleSchema()._schema;
// ------------------------------ Checks ------------------------------ //
// check that user can edit document
if (!user || !Users.can.edit(user, post)) {
throw new Meteor.Error(601, i18n.t('sorry_you_cannot_edit_this_post'));
}
// go over each field and throw an error if it's not editable
// loop over each operation ($set, $unset, etc.)
_.each(modifier, function (operation) {
// loop over each property being operated on
_.keys(operation).forEach(function (fieldName) {
var field = schema[fieldName];
if (!Users.can.editField(user, field, post)) {
throw new Meteor.Error("disallowed_property", i18n.t('disallowed_property_detected') + ": " + fieldName);
}
});
});
// ------------------------------ Callbacks ------------------------------ //
// run all post submit server callbacks on modifier successively
modifier = Telescope.callbacks.run("postEdit", modifier);
// ------------------------------ Update ------------------------------ //
Posts.update(postId, modifier);
// ------------------------------ Callbacks ------------------------------ //
Telescope.callbacks.run("postEditAsync", postId, true);
// ------------------------------ After Update ------------------------------ //
return Posts.findOne(postId);
},
setPostedAt: function(post, customPostedAt){
var postedAt = new Date(); // default to current date and time
if(Users.is.admin(Meteor.user()) && typeof customPostedAt !== 'undefined') // if user is admin and a custom datetime has been set
postedAt = customPostedAt;
Posts.update(post._id, {$set: {postedAt: postedAt}});
},
approvePost: function(post){
if(Users.is.admin(Meteor.user())){
var set = {status: 2};
// unless post is already scheduled and has a postedAt date, set its postedAt date to now
if (!post.postedAt)
set.postedAt = new Date();
Posts.update(post._id, {$set: set}, {validate: false});
// --------------------- Server-Side Async Callbacks --------------------- //
Telescope.callbacks.run("postApprovedAsync", post, true);
}else{
Messages.flash('You need to be an admin to do that.', "error");
}
},
unapprovePost: function(post){
if(Users.is.admin(Meteor.user())){
Posts.update(post._id, {$set: {status: 1}});
}else{
Messages.flash('You need to be an admin to do that.', "error");
}
},
increasePostViews: function(postId, sessionId){
this.unblock();
// only let users increment a post's view counter once per session
var view = {_id: postId, userId: this.userId, sessionId: sessionId};
if(_.where(postViews, view).length === 0){
postViews.push(view);
Posts.update(postId, { $inc: { viewCount: 1 }});
}
},
deletePostById: function(postId) {
// remove post comments
// if(!this.isSimulation) {
// Comments.remove({post: postId});
// }
// NOTE: actually, keep comments after all
var post = Posts.findOne({_id: postId});
if(!Meteor.userId() || !Users.can.editById(Meteor.userId(), post)) throw new Meteor.Error(606, 'You need permission to edit or delete a post');
// decrement post count
Meteor.users.update({_id: post.userId}, {$inc: {postCount: -1}});
// delete post
Posts.remove(postId);
}
});