2014-11-29 11:14:44 +09:00
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------- //
|
|
|
|
// ----------------------------------------- Schema ----------------------------------------- //
|
|
|
|
// ------------------------------------------------------------------------------------------- //
|
|
|
|
|
2015-01-22 10:59:13 +09:00
|
|
|
PostSchemaObject = {
|
2014-06-22 12:58:41 +09:00
|
|
|
_id: {
|
|
|
|
type: String,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
createdAt: {
|
|
|
|
type: Date,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
2014-07-03 13:15:23 +09:00
|
|
|
postedAt: {
|
2014-06-22 12:58:41 +09:00
|
|
|
type: Date,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-08 18:38:01 +09:00
|
|
|
group: 'admin',
|
2014-11-28 11:19:55 +09:00
|
|
|
type: "bootstrap-datetimepicker"
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
url: {
|
|
|
|
type: String,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-11-28 15:18:55 +09:00
|
|
|
editable: true,
|
|
|
|
type: "bootstrap-url"
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-12-03 00:06:00 -08:00
|
|
|
},
|
2014-11-29 15:24:01 +09:00
|
|
|
title: {
|
|
|
|
type: String,
|
|
|
|
optional: false,
|
|
|
|
autoform: {
|
|
|
|
editable: true
|
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
body: {
|
|
|
|
type: String,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
|
|
|
editable: true,
|
|
|
|
rows: 5
|
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
2014-08-31 16:11:48 +09:00
|
|
|
htmlBody: {
|
|
|
|
type: String,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-08-31 16:11:48 +09:00
|
|
|
},
|
2014-10-16 00:32:08 +02:00
|
|
|
viewCount: {
|
2014-06-22 12:58:41 +09:00
|
|
|
type: Number,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
2014-10-16 00:32:08 +02:00
|
|
|
commentCount: {
|
2014-06-22 12:58:41 +09:00
|
|
|
type: Number,
|
2014-11-28 11:19:55 +09:00
|
|
|
optional: true,
|
2014-11-26 11:22:54 +09:00
|
|
|
autoform: {
|
|
|
|
omit: true
|
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
2014-08-22 10:31:05 +09:00
|
|
|
commenters: {
|
|
|
|
type: [String],
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-08-22 10:31:05 +09:00
|
|
|
},
|
2014-07-22 10:29:37 +09:00
|
|
|
lastCommentedAt: {
|
2014-07-19 15:08:28 +09:00
|
|
|
type: Date,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-07-19 15:08:28 +09:00
|
|
|
},
|
2014-10-16 00:32:08 +02:00
|
|
|
clickCount: {
|
2014-07-03 17:13:22 +09:00
|
|
|
type: Number,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-07-03 17:13:22 +09:00
|
|
|
},
|
2014-06-22 12:58:41 +09:00
|
|
|
baseScore: {
|
|
|
|
type: Number,
|
|
|
|
decimal: true,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
upvotes: {
|
|
|
|
type: Number,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
upvoters: {
|
|
|
|
type: [String], // XXX
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
downvotes: {
|
|
|
|
type: Number,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
downvoters: {
|
|
|
|
type: [String], // XXX
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
score: {
|
|
|
|
type: Number,
|
|
|
|
decimal: true,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
status: {
|
|
|
|
type: Number,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoValue: function () {
|
2014-12-05 09:44:50 +09:00
|
|
|
// only provide a default value
|
|
|
|
// 1) this is an insert operation
|
|
|
|
// 2) status field is not set in the document being inserted
|
2015-01-07 08:22:46 +01:00
|
|
|
var user = Meteor.users.findOne(this.userId);
|
2014-12-10 10:52:40 +09:00
|
|
|
if (this.isInsert && !this.isSet)
|
|
|
|
return getDefaultPostStatus(user);
|
2014-10-05 17:20:15 +09:00
|
|
|
},
|
|
|
|
autoform: {
|
|
|
|
noselect: true,
|
|
|
|
options: postStatuses,
|
|
|
|
group: 'admin'
|
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
sticky: {
|
|
|
|
type: Boolean,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
2014-12-08 19:51:06 +09:00
|
|
|
defaultValue: false,
|
2014-10-05 17:20:15 +09:00
|
|
|
autoform: {
|
2014-10-06 11:10:50 +09:00
|
|
|
group: 'admin',
|
|
|
|
leftLabel: "Sticky"
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
|
|
|
inactive: {
|
|
|
|
type: Boolean,
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
2014-10-06 10:23:46 +09:00
|
|
|
omit: true
|
2014-10-05 17:20:15 +09:00
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
},
|
2014-11-28 15:18:55 +09:00
|
|
|
author: {
|
|
|
|
type: String,
|
|
|
|
optional: true,
|
|
|
|
autoform: {
|
|
|
|
omit: true
|
|
|
|
}
|
|
|
|
},
|
2014-06-22 12:58:41 +09:00
|
|
|
userId: {
|
|
|
|
type: String, // XXX
|
2014-10-05 17:20:15 +09:00
|
|
|
optional: true,
|
|
|
|
autoform: {
|
|
|
|
group: 'admin',
|
|
|
|
options: function () {
|
|
|
|
return Meteor.users.find().map(function (user) {
|
|
|
|
return {
|
|
|
|
value: user._id,
|
|
|
|
label: getDisplayName(user)
|
2014-12-03 00:06:00 -08:00
|
|
|
}
|
2014-10-05 17:20:15 +09:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2014-06-22 12:58:41 +09:00
|
|
|
}
|
2014-09-17 21:11:59 +02:00
|
|
|
};
|
2014-06-22 12:58:41 +09:00
|
|
|
|
|
|
|
// add any extra properties to postSchemaObject (provided by packages for example)
|
|
|
|
_.each(addToPostSchema, function(item){
|
2015-01-22 10:59:13 +09:00
|
|
|
PostSchemaObject[item.propertyName] = item.propertySchema;
|
2014-06-22 12:58:41 +09:00
|
|
|
});
|
|
|
|
|
2014-09-17 20:10:43 +02:00
|
|
|
Posts = new Meteor.Collection("posts");
|
2014-09-17 21:11:59 +02:00
|
|
|
|
2015-01-22 10:59:13 +09:00
|
|
|
PostSchema = new SimpleSchema(PostSchemaObject);
|
2014-12-31 17:44:21 +09:00
|
|
|
|
2014-09-17 20:20:23 +02:00
|
|
|
Posts.attachSchema(PostSchema);
|
2014-05-10 16:57:17 +09:00
|
|
|
|
2014-11-29 11:14:44 +09:00
|
|
|
// ------------------------------------------------------------------------------------------- //
|
|
|
|
// ----------------------------------------- Helpers ----------------------------------------- //
|
|
|
|
// ------------------------------------------------------------------------------------------- //
|
2013-11-06 10:11:35 +09:00
|
|
|
|
2014-11-29 11:14:44 +09:00
|
|
|
getPostProperties = function (post) {
|
2014-08-04 09:47:10 +09:00
|
|
|
|
2014-09-16 15:18:27 -04:00
|
|
|
var postAuthor = Meteor.users.findOne(post.userId);
|
2014-08-04 09:47:10 +09:00
|
|
|
var p = {
|
|
|
|
postAuthorName : getDisplayName(postAuthor),
|
|
|
|
postTitle : cleanUp(post.title),
|
2014-12-03 00:06:00 -08:00
|
|
|
profileUrl: getProfileUrlBySlugOrId(post.userId),
|
2014-08-12 16:16:44 +09:00
|
|
|
postUrl: getPostPageUrl(post),
|
2014-08-04 11:22:43 +09:00
|
|
|
thumbnailUrl: post.thumbnailUrl,
|
|
|
|
linkUrl: !!post.url ? getOutgoingUrl(post.url) : getPostPageUrl(post._id)
|
2014-08-04 09:47:10 +09:00
|
|
|
};
|
2014-12-03 00:06:00 -08:00
|
|
|
|
2014-08-04 09:47:10 +09:00
|
|
|
if(post.url)
|
|
|
|
p.url = post.url;
|
|
|
|
|
2014-08-31 16:11:48 +09:00
|
|
|
if(post.htmlBody)
|
|
|
|
p.htmlBody = post.htmlBody;
|
2014-08-04 09:47:10 +09:00
|
|
|
|
|
|
|
return p;
|
2014-09-16 15:18:27 -04:00
|
|
|
};
|
2014-08-04 09:47:10 +09:00
|
|
|
|
2014-12-10 10:52:40 +09:00
|
|
|
// default status for new posts
|
|
|
|
getDefaultPostStatus = function (user) {
|
2014-12-18 15:09:30 +09:00
|
|
|
var hasAdminRights = typeof user === 'undefined' ? false : isAdmin(user);
|
|
|
|
if (hasAdminRights || !getSetting('requirePostsApproval', false)) {
|
2014-12-10 10:52:40 +09:00
|
|
|
// if user is admin, or else post approval is not required
|
|
|
|
return STATUS_APPROVED
|
|
|
|
} else {
|
|
|
|
// else
|
|
|
|
return STATUS_PENDING
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-04 11:22:43 +09:00
|
|
|
getPostPageUrl = function(post){
|
|
|
|
return getSiteUrl()+'posts/'+post._id;
|
|
|
|
};
|
|
|
|
|
|
|
|
getPostEditUrl = function(id){
|
|
|
|
return getSiteUrl()+'posts/'+id+'/edit';
|
|
|
|
};
|
|
|
|
|
|
|
|
// for a given post, return its link if it has one, or else its post page URL
|
|
|
|
getPostLink = function (post) {
|
|
|
|
return !!post.url ? getOutgoingUrl(post.url) : getPostPageUrl(post);
|
2014-09-16 15:18:27 -04:00
|
|
|
};
|
2014-08-04 11:22:43 +09:00
|
|
|
|
2014-12-28 12:13:13 +09:00
|
|
|
// we need the current user so we know who to upvote the existing post as
|
|
|
|
checkForPostsWithSameUrl = function (url, currentUser) {
|
2014-11-29 11:14:44 +09:00
|
|
|
|
|
|
|
// check that there are no previous posts with the same link in the past 6 months
|
|
|
|
var sixMonthsAgo = moment().subtract(6, 'months').toDate();
|
|
|
|
var postWithSameLink = Posts.findOne({url: url, postedAt: {$gte: sixMonthsAgo}});
|
|
|
|
|
|
|
|
if(typeof postWithSameLink !== 'undefined'){
|
2014-12-28 12:13:13 +09:00
|
|
|
upvoteItem(Posts, postWithSameLink, currentUser);
|
|
|
|
|
2014-12-03 00:06:00 -08:00
|
|
|
// note: error.details returns undefined on the client, so add post ID to reason
|
2014-11-29 11:14:44 +09:00
|
|
|
throw new Meteor.Error('603', i18n.t('this_link_has_already_been_posted') + '|' + postWithSameLink._id, postWithSameLink._id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-20 17:34:15 +09:00
|
|
|
// when on a post page, return the current post
|
|
|
|
currentPost = function () {
|
|
|
|
return Posts.findOne(Router.current().data()._id);
|
|
|
|
}
|
2014-12-24 10:13:48 +09:00
|
|
|
|
2014-11-29 11:14:44 +09:00
|
|
|
// ------------------------------------------------------------------------------------------- //
|
|
|
|
// ------------------------------------------ Hooks ------------------------------------------ //
|
|
|
|
// ------------------------------------------------------------------------------------------- //
|
|
|
|
|
2014-08-31 16:11:48 +09:00
|
|
|
Posts.before.insert(function (userId, doc) {
|
2014-12-30 13:47:14 +09:00
|
|
|
if(!!doc.body)
|
2014-09-02 14:54:04 +09:00
|
|
|
doc.htmlBody = sanitize(marked(doc.body));
|
2014-08-31 16:11:48 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
Posts.before.update(function (userId, doc, fieldNames, modifier, options) {
|
|
|
|
// if body is being modified, update htmlBody too
|
2014-09-11 14:10:57 +09:00
|
|
|
if (Meteor.isServer && modifier.$set && modifier.$set.body) {
|
2014-08-31 16:11:48 +09:00
|
|
|
modifier.$set = modifier.$set || {};
|
|
|
|
modifier.$set.htmlBody = sanitize(marked(modifier.$set.body));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2014-12-22 11:49:35 +09:00
|
|
|
postAfterSubmitMethodCallbacks.push(function (post) {
|
|
|
|
|
|
|
|
var userId = post.userId,
|
|
|
|
postAuthor = Meteor.users.findOne(userId);
|
|
|
|
|
|
|
|
// increment posts count
|
|
|
|
Meteor.users.update({_id: userId}, {$inc: {postCount: 1}});
|
|
|
|
upvoteItem(Posts, post, postAuthor);
|
2015-01-07 08:22:46 +01:00
|
|
|
|
2014-12-22 11:49:35 +09:00
|
|
|
return post;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2014-12-18 15:09:30 +09:00
|
|
|
// ------------------------------------------------------------------------------------------- //
|
|
|
|
// --------------------------------------- Submit Post --------------------------------------- //
|
|
|
|
// ------------------------------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
submitPost = function (post) {
|
2014-12-18 16:01:18 +09:00
|
|
|
|
2014-12-18 15:09:30 +09:00
|
|
|
var userId = post.userId, // at this stage, a userId is expected
|
|
|
|
user = Meteor.users.findOne(userId);
|
2014-12-24 10:13:48 +09:00
|
|
|
|
2014-12-18 15:09:30 +09:00
|
|
|
// ------------------------------ 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)
|
2014-12-28 12:13:13 +09:00
|
|
|
checkForPostsWithSameUrl(post.url, user);
|
2014-12-18 15:09:30 +09:00
|
|
|
|
|
|
|
// ------------------------------ Properties ------------------------------ //
|
|
|
|
|
|
|
|
defaultProperties = {
|
|
|
|
createdAt: new Date(),
|
|
|
|
author: getDisplayNameById(userId),
|
|
|
|
upvotes: 0,
|
|
|
|
downvotes: 0,
|
|
|
|
commentCount: 0,
|
|
|
|
clickCount: 0,
|
|
|
|
viewCount: 0,
|
|
|
|
baseScore: 0,
|
|
|
|
score: 0,
|
|
|
|
inactive: false,
|
|
|
|
sticky: false,
|
|
|
|
status: getDefaultPostStatus(),
|
|
|
|
postedAt: new Date()
|
|
|
|
};
|
|
|
|
|
|
|
|
post = _.extend(defaultProperties, post);
|
|
|
|
|
|
|
|
// clean up post title
|
|
|
|
post.title = cleanUp(post.title);
|
|
|
|
|
|
|
|
// ------------------------------ Callbacks ------------------------------ //
|
|
|
|
|
|
|
|
// run all post submit server callbacks on post object successively
|
|
|
|
post = postSubmitMethodCallbacks.reduce(function(result, currentFunction) {
|
|
|
|
return currentFunction(result);
|
|
|
|
}, post);
|
|
|
|
|
2014-12-24 10:13:48 +09:00
|
|
|
// -------------------------------- Insert ------------------------------- //
|
2014-12-18 15:09:30 +09:00
|
|
|
|
|
|
|
post._id = Posts.insert(post);
|
|
|
|
|
2014-12-24 10:13:48 +09:00
|
|
|
// --------------------- Server-Side Async Callbacks --------------------- //
|
2014-12-18 15:09:30 +09:00
|
|
|
|
2014-12-22 11:49:35 +09:00
|
|
|
if (Meteor.isServer) {
|
2014-12-29 18:24:26 +09:00
|
|
|
Meteor.defer(function () { // use defer to avoid holding up client
|
2014-12-22 11:49:35 +09:00
|
|
|
// run all post submit server callbacks on post object successively
|
|
|
|
post = postAfterSubmitMethodCallbacks.reduce(function(result, currentFunction) {
|
|
|
|
return currentFunction(result);
|
|
|
|
}, post);
|
2014-12-29 18:24:26 +09:00
|
|
|
});
|
2014-12-24 10:13:48 +09:00
|
|
|
}
|
2014-12-18 15:09:30 +09:00
|
|
|
|
|
|
|
return post;
|
|
|
|
}
|
|
|
|
|
2014-11-29 11:14:44 +09:00
|
|
|
// ------------------------------------------------------------------------------------------- //
|
|
|
|
// ----------------------------------------- Methods ----------------------------------------- //
|
|
|
|
// ------------------------------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
postClicks = [];
|
|
|
|
postViews = [];
|
|
|
|
|
2012-10-04 11:45:12 +10:00
|
|
|
Meteor.methods({
|
2014-11-29 10:25:11 +09:00
|
|
|
|
2014-12-29 18:24:26 +09:00
|
|
|
submitPost: function(post){
|
2014-12-18 15:09:30 +09:00
|
|
|
|
|
|
|
// 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 = isAdmin(user);
|
2014-07-03 13:15:23 +09:00
|
|
|
|
|
|
|
// ------------------------------ Checks ------------------------------ //
|
2013-11-06 09:33:56 +09:00
|
|
|
|
2012-10-30 12:01:11 +09:00
|
|
|
// check that user can post
|
2015-01-07 08:22:46 +01:00
|
|
|
if (!user || !can.post(user))
|
2014-11-19 00:00:09 +08:00
|
|
|
throw new Meteor.Error(601, i18n.t('you_need_to_login_or_be_invited_to_post_new_stories'));
|
2012-10-10 08:32:49 +09:00
|
|
|
|
2014-11-29 11:14:44 +09:00
|
|
|
// --------------------------- Rate Limiting -------------------------- //
|
2012-10-06 13:15:55 +09:00
|
|
|
|
2014-12-24 10:13:48 +09:00
|
|
|
if(!hasAdminRights){
|
2015-01-07 08:22:46 +01:00
|
|
|
|
2014-12-24 10:13:48 +09:00
|
|
|
var timeSinceLastPost=timeSinceLast(user, Posts),
|
2014-12-18 15:09:30 +09:00
|
|
|
numberOfPostsInPast24Hours=numberOfItemsInPast24Hours(user, Posts),
|
|
|
|
postInterval = Math.abs(parseInt(getSetting('postInterval', 30))),
|
|
|
|
maxPostsPer24Hours = Math.abs(parseInt(getSetting('maxPostsPerDay', 30)));
|
|
|
|
|
2013-01-13 19:18:01 +09:00
|
|
|
// check that user waits more than X seconds between posts
|
2014-12-24 10:13:48 +09:00
|
|
|
if(timeSinceLastPost < postInterval)
|
2014-11-19 00:00:09 +08:00
|
|
|
throw new Meteor.Error(604, i18n.t('please_wait')+(postInterval-timeSinceLastPost)+i18n.t('seconds_before_posting_again'));
|
2012-10-24 11:04:42 +09:00
|
|
|
|
2013-01-13 19:18:01 +09:00
|
|
|
// check that the user doesn't post more than Y posts per day
|
2014-12-24 10:13:48 +09:00
|
|
|
if(numberOfPostsInPast24Hours > maxPostsPer24Hours)
|
2014-11-19 00:00:09 +08:00
|
|
|
throw new Meteor.Error(605, i18n.t('sorry_you_cannot_submit_more_than')+maxPostsPer24Hours+i18n.t('posts_per_day'));
|
2015-01-07 08:22:46 +01:00
|
|
|
|
2013-01-13 19:18:01 +09:00
|
|
|
}
|
2012-10-23 12:24:38 +09:00
|
|
|
|
2014-07-03 13:15:23 +09:00
|
|
|
// ------------------------------ Properties ------------------------------ //
|
|
|
|
|
2014-12-18 15:09:30 +09:00
|
|
|
// admin-only properties
|
|
|
|
// status
|
|
|
|
// postedAt
|
|
|
|
// userId
|
|
|
|
// sticky (default to false)
|
|
|
|
|
2015-01-22 10:59:13 +09:00
|
|
|
// if user is not admin, go over each schema property and clear it if it's not editable
|
2014-12-18 15:09:30 +09:00
|
|
|
if (!hasAdminRights) {
|
2015-01-22 10:59:13 +09:00
|
|
|
_.keys(post).forEach(function (propertyName) {
|
|
|
|
var property = PostSchemaObject[propertyName];
|
|
|
|
if (!property || !property.autoform || !property.autoform.editable) {
|
|
|
|
console.log("// Disallowed property detected: "+propertyName+" (nice try!)");
|
|
|
|
delete post[propertyName]
|
|
|
|
}
|
|
|
|
});
|
2014-07-03 13:15:23 +09:00
|
|
|
}
|
|
|
|
|
2014-12-18 15:09:30 +09:00
|
|
|
// if no post status has been set, set it now
|
|
|
|
if (!post.status) {
|
|
|
|
post.status = getDefaultPostStatus(user);
|
2014-07-03 13:15:23 +09:00
|
|
|
}
|
|
|
|
|
2014-12-18 15:09:30 +09:00
|
|
|
// if no userId has been set, default to current user id
|
|
|
|
if (!post.userId) {
|
|
|
|
post.userId = user._id
|
2013-01-13 08:52:35 +09:00
|
|
|
}
|
2015-01-07 08:22:46 +01:00
|
|
|
|
2014-12-18 15:09:30 +09:00
|
|
|
return submitPost(post);
|
2013-01-13 08:52:35 +09:00
|
|
|
},
|
2014-11-29 10:25:11 +09:00
|
|
|
|
2014-12-22 11:49:35 +09:00
|
|
|
editPost: function (post, modifier, postId) {
|
2014-11-29 10:25:11 +09:00
|
|
|
|
2014-11-29 11:14:44 +09:00
|
|
|
var user = Meteor.user();
|
2014-11-29 10:25:11 +09:00
|
|
|
|
|
|
|
// ------------------------------ Checks ------------------------------ //
|
|
|
|
|
2014-11-29 11:14:44 +09:00
|
|
|
// check that user can edit
|
2015-01-07 08:22:46 +01:00
|
|
|
if (!user || !can.edit(user, Posts.findOne(postId)))
|
2014-11-29 11:14:44 +09:00
|
|
|
throw new Meteor.Error(601, i18n.t('sorry_you_cannot_edit_this_post'));
|
2014-11-29 10:25:11 +09:00
|
|
|
|
|
|
|
// ------------------------------ Callbacks ------------------------------ //
|
|
|
|
|
2014-12-22 09:50:45 +09:00
|
|
|
// run all post submit server callbacks on modifier successively
|
|
|
|
modifier = postEditMethodCallbacks.reduce(function(result, currentFunction) {
|
2014-11-29 11:14:44 +09:00
|
|
|
return currentFunction(result);
|
2014-12-22 09:50:45 +09:00
|
|
|
}, modifier);
|
2014-11-29 10:25:11 +09:00
|
|
|
|
|
|
|
// ------------------------------ Update ------------------------------ //
|
|
|
|
|
2014-12-22 09:50:45 +09:00
|
|
|
Posts.update(postId, modifier);
|
2014-11-29 10:25:11 +09:00
|
|
|
|
|
|
|
// ------------------------------ Callbacks ------------------------------ //
|
|
|
|
|
2014-12-22 09:50:45 +09:00
|
|
|
// run all post submit server callbacks on modifier object successively
|
|
|
|
modifier = postAfterEditMethodCallbacks.reduce(function(result, currentFunction) {
|
2014-11-29 11:14:44 +09:00
|
|
|
return currentFunction(result);
|
2014-12-22 09:50:45 +09:00
|
|
|
}, modifier);
|
2014-11-29 10:25:11 +09:00
|
|
|
|
|
|
|
// ------------------------------ After Update ------------------------------ //
|
|
|
|
|
|
|
|
return Posts.findOne(postId);
|
|
|
|
|
|
|
|
},
|
|
|
|
|
2014-07-03 13:15:23 +09:00
|
|
|
setPostedAt: function(post, customPostedAt){
|
2014-07-03 16:17:36 +09:00
|
|
|
|
2014-07-03 13:15:23 +09:00
|
|
|
var postedAt = new Date(); // default to current date and time
|
2014-12-03 00:06:00 -08:00
|
|
|
|
2014-07-03 13:15:23 +09:00
|
|
|
if(isAdmin(Meteor.user()) && typeof customPostedAt !== 'undefined') // if user is admin and a custom datetime has been set
|
2014-09-16 15:18:27 -04:00
|
|
|
postedAt = customPostedAt;
|
2014-07-03 16:17:36 +09:00
|
|
|
|
2014-07-03 13:15:23 +09:00
|
|
|
Posts.update(post._id, {$set: {postedAt: postedAt}});
|
|
|
|
},
|
2014-11-29 10:25:11 +09:00
|
|
|
|
2014-05-23 13:08:52 +09:00
|
|
|
approvePost: function(post){
|
|
|
|
if(isAdmin(Meteor.user())){
|
2014-12-08 16:39:10 +09:00
|
|
|
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();
|
2015-01-07 08:22:46 +01:00
|
|
|
|
2014-12-08 16:39:10 +09:00
|
|
|
var result = Posts.update(post._id, {$set: set}, {validate: false});
|
2015-01-21 16:47:02 +09:00
|
|
|
|
|
|
|
// --------------------- Server-Side Async Callbacks --------------------- //
|
|
|
|
if (Meteor.isServer) {
|
|
|
|
Meteor.defer(function () { // use defer to avoid holding up client
|
|
|
|
// run all post submit server callbacks on post object successively
|
|
|
|
post = postApproveCallbacks.reduce(function(result, currentFunction) {
|
|
|
|
return currentFunction(result);
|
|
|
|
}, post);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-05-23 13:08:52 +09:00
|
|
|
}else{
|
Replace "throwError" with "flashMessage" and type
Currently, ``throwError`` is used for all manner of messages, including
errors, "success" messages, and "info" messages. This makes appropriate
styling of the error message difficult. In addition, the name
``throwError`` seems to create confusion, implying that an error will
actually be thrown (e.g. stopping execution when a user isn't logged in
[0][1]), when in fact it just displays a message.
Replace ``throwError`` with ``flashMessage``, and reliably include a
message "type" (e.g. "error", "success", "info") every time. rename
``lib/errors.js`` to ``lib/messages.js`` to more accurately reflect its
function.
This commit doesn't rename the message collection (``Errors``), nor the
template responsible for rendering the messages (``error_item.html``) --
that should probably still be done, but has higher likelihood of
trouble for existing alternate themes and installations.
[0] https://github.com/TelescopeJS/Telescope/blob/6ccf7d7d4704d6a8e821fe48128f81c19983ffc9/client/views/users/user_edit.js#L43
[1] https://github.com/TelescopeJS/Telescope/blob/083a4c4dc48eca15fe9d4472e24e6b4e8adfc8d6/client/views/users/user_email.js#L13
2014-11-05 13:12:09 -07:00
|
|
|
flashMessage('You need to be an admin to do that.', "error");
|
2014-05-23 13:08:52 +09:00
|
|
|
}
|
|
|
|
},
|
2014-11-29 10:25:11 +09:00
|
|
|
|
2014-05-23 13:08:52 +09:00
|
|
|
unapprovePost: function(post){
|
|
|
|
if(isAdmin(Meteor.user())){
|
|
|
|
Posts.update(post._id, {$set: {status: 1}});
|
|
|
|
}else{
|
Replace "throwError" with "flashMessage" and type
Currently, ``throwError`` is used for all manner of messages, including
errors, "success" messages, and "info" messages. This makes appropriate
styling of the error message difficult. In addition, the name
``throwError`` seems to create confusion, implying that an error will
actually be thrown (e.g. stopping execution when a user isn't logged in
[0][1]), when in fact it just displays a message.
Replace ``throwError`` with ``flashMessage``, and reliably include a
message "type" (e.g. "error", "success", "info") every time. rename
``lib/errors.js`` to ``lib/messages.js`` to more accurately reflect its
function.
This commit doesn't rename the message collection (``Errors``), nor the
template responsible for rendering the messages (``error_item.html``) --
that should probably still be done, but has higher likelihood of
trouble for existing alternate themes and installations.
[0] https://github.com/TelescopeJS/Telescope/blob/6ccf7d7d4704d6a8e821fe48128f81c19983ffc9/client/views/users/user_edit.js#L43
[1] https://github.com/TelescopeJS/Telescope/blob/083a4c4dc48eca15fe9d4472e24e6b4e8adfc8d6/client/views/users/user_email.js#L13
2014-11-05 13:12:09 -07:00
|
|
|
flashMessage('You need to be an admin to do that.', "error");
|
2014-05-23 13:08:52 +09:00
|
|
|
}
|
|
|
|
},
|
2014-11-29 10:25:11 +09:00
|
|
|
|
2014-10-15 21:23:43 +02:00
|
|
|
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);
|
2014-10-16 00:32:08 +02:00
|
|
|
Posts.update(postId, { $inc: { viewCount: 1 }});
|
2014-10-15 21:23:43 +02:00
|
|
|
}
|
|
|
|
},
|
2014-11-29 10:25:11 +09:00
|
|
|
|
|
|
|
increasePostClicks: function(postId, sessionId){
|
2014-10-15 21:23:43 +02:00
|
|
|
this.unblock();
|
|
|
|
|
2013-11-06 10:11:35 +09:00
|
|
|
// only let clients increment a post's click counter once per session
|
2014-10-15 21:23:43 +02:00
|
|
|
var click = {_id: postId, userId: this.userId, sessionId: sessionId};
|
|
|
|
|
|
|
|
if(_.where(postClicks, click).length == 0){
|
|
|
|
postClicks.push(click);
|
2014-10-16 00:32:08 +02:00
|
|
|
Posts.update(postId, { $inc: { clickCount: 1 }});
|
2013-11-06 10:11:35 +09:00
|
|
|
}
|
2013-07-19 14:30:39 +03:00
|
|
|
},
|
2014-11-29 10:25:11 +09:00
|
|
|
|
2013-07-19 14:30:39 +03:00
|
|
|
deletePostById: function(postId) {
|
|
|
|
// remove post comments
|
2013-11-08 11:10:23 +09:00
|
|
|
// if(!this.isSimulation) {
|
|
|
|
// Comments.remove({post: postId});
|
|
|
|
// }
|
2014-09-16 15:18:27 -04:00
|
|
|
// NOTE: actually, keep comments after all
|
2013-11-08 11:10:23 +09:00
|
|
|
|
2013-11-11 20:53:02 +02:00
|
|
|
var post = Posts.findOne({_id: postId});
|
2015-01-07 08:22:46 +01:00
|
|
|
|
|
|
|
if(!Meteor.userId() || !can.editById(Meteor.userId(), post)) throw new Meteor.Error(606, 'You need permission to edit or delete a post');
|
|
|
|
|
2014-12-08 16:10:32 +09:00
|
|
|
// decrement post count
|
2013-11-11 21:15:04 +02:00
|
|
|
Meteor.users.update({_id: post.userId}, {$inc: {postCount: -1}});
|
2015-01-07 08:22:46 +01:00
|
|
|
|
2014-12-08 16:10:32 +09:00
|
|
|
// delete post
|
2013-07-19 14:30:39 +03:00
|
|
|
Posts.remove(postId);
|
2012-10-04 11:45:12 +10:00
|
|
|
}
|
2014-11-29 10:25:11 +09:00
|
|
|
|
2013-07-19 14:30:39 +03:00
|
|
|
});
|