mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 10:01:40 -05:00
clean up callbacks by moving logic to mutations and schema (autoValue)
This commit is contained in:
parent
dd32c36f28
commit
8689a4de73
17 changed files with 817 additions and 784 deletions
|
@ -1,2 +1,2 @@
|
|||
import './fragments/users.js';
|
||||
// import './fragments/users.js';
|
||||
import './fragments/categories.js';
|
|
@ -1,313 +0,0 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import marked from 'marked';
|
||||
import Posts from "meteor/nova:posts";
|
||||
import Comments from './collection.js';
|
||||
import Users from 'meteor/nova:users';
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Collection Hooks //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
// Comments.before.insert(function (userId, doc) {
|
||||
// // note: only actually sanitizes on the server
|
||||
// doc.htmlBody = Telescope.utils.sanitize(marked(doc.body));
|
||||
// });
|
||||
|
||||
// Comments.before.update(function (userId, doc, fieldNames, modifier) {
|
||||
// // if body is being modified, update htmlBody too
|
||||
// if (Meteor.isServer && modifier.$set && modifier.$set.body) {
|
||||
// modifier.$set = modifier.$set || {};
|
||||
// modifier.$set.htmlBody = Telescope.utils.sanitize(marked(modifier.$set.body));
|
||||
// }
|
||||
// });
|
||||
|
||||
/**
|
||||
* @summary Disallow $rename
|
||||
*/
|
||||
Comments.before.update(function (userId, doc, fieldNames, modifier) {
|
||||
if (!!modifier.$rename) {
|
||||
throw new Meteor.Error("illegal $rename operator detected!");
|
||||
}
|
||||
});
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Callbacks //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/*
|
||||
|
||||
### comments.new.validate
|
||||
|
||||
- CommentsNewUserCheck
|
||||
- CommentsNewRateLimit
|
||||
- CommentsNewSubmittedPropertiesCheck
|
||||
|
||||
### comments.new.sync
|
||||
|
||||
- CommentsNewRequiredPropertiesCheck
|
||||
|
||||
### comments.new.async
|
||||
|
||||
- CommentsNewOperations
|
||||
- CommentsNewUpvoteOwnComment
|
||||
- CommentsNewNotifications
|
||||
|
||||
### comments.edit.validate
|
||||
|
||||
- CommentsEditUserCheck
|
||||
- CommentsEditSubmittedPropertiesCheck
|
||||
|
||||
### comments.edit.sync
|
||||
|
||||
### comments.edit.async
|
||||
|
||||
### users.remove.async
|
||||
|
||||
- UsersRemoveDeleteComments
|
||||
|
||||
*/
|
||||
|
||||
// ------------------------------------- comments.new.validate -------------------------------- //
|
||||
|
||||
function CommentsNewUserCheck (comment, user) {
|
||||
// check that user can post
|
||||
if (!user || !Users.canDo(user, "comments.new"))
|
||||
throw new Meteor.Error(601, 'you_need_to_login_or_be_invited_to_post_new_comments');
|
||||
return comment;
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.sync", CommentsNewUserCheck);
|
||||
|
||||
function CommentsNewRateLimit (comment, user) {
|
||||
if (!Users.isAdmin(user)) {
|
||||
const timeSinceLastComment = Users.timeSinceLast(user, Comments);
|
||||
const commentInterval = Math.abs(parseInt(Telescope.settings.get('commentInterval',15)));
|
||||
// check that user waits more than 15 seconds between comments
|
||||
if((timeSinceLastComment < commentInterval)) {
|
||||
throw new Meteor.Error("CommentsNewRateLimit", "comments.rate_limit_error", commentInterval-timeSinceLastComment);
|
||||
}
|
||||
}
|
||||
return comment;
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.validate", CommentsNewRateLimit);
|
||||
|
||||
function CommentsNewSubmittedPropertiesCheck (comment, user) {
|
||||
// admin-only properties
|
||||
// userId
|
||||
const schema = Comments.simpleSchema()._schema;
|
||||
|
||||
// clear restricted properties
|
||||
_.keys(comment).forEach(function (fieldName) {
|
||||
|
||||
// make an exception for postId, which should be setable but not modifiable
|
||||
if (fieldName === "postId") {
|
||||
// ok
|
||||
} else {
|
||||
var field = schema[fieldName];
|
||||
if (!Users.canSubmitField (user, field)) {
|
||||
throw new Meteor.Error("disallowed_property", 'disallowed_property_detected' + ": " + fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// if no userId has been set, default to current user id
|
||||
if (!comment.userId) {
|
||||
comment.userId = user._id;
|
||||
}
|
||||
return comment;
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.validate", CommentsNewSubmittedPropertiesCheck);
|
||||
|
||||
// ------------------------------------- comments.new.sync -------------------------------- //
|
||||
|
||||
/**
|
||||
* @summary Check for required properties
|
||||
*/
|
||||
function CommentsNewRequiredPropertiesCheck (comment, user) {
|
||||
|
||||
var userId = comment.userId; // at this stage, a userId is expected
|
||||
|
||||
// Don't allow empty comments
|
||||
if (!comment.body)
|
||||
throw new Meteor.Error(704, 'your_comment_is_empty');
|
||||
|
||||
var defaultProperties = {
|
||||
createdAt: new Date(),
|
||||
postedAt: new Date(),
|
||||
upvotes: 0,
|
||||
downvotes: 0,
|
||||
baseScore: 0,
|
||||
score: 0,
|
||||
author: Users.getDisplayNameById(userId)
|
||||
};
|
||||
|
||||
comment = _.extend(defaultProperties, comment);
|
||||
|
||||
return comment;
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.sync", CommentsNewRequiredPropertiesCheck);
|
||||
|
||||
function CommentsNewGenerateHTMLBody (comment, user) {
|
||||
comment.htmlBody = Telescope.utils.sanitize(marked(comment.body));
|
||||
return comment;
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.sync", CommentsNewGenerateHTMLBody);
|
||||
|
||||
// ------------------------------------- comments.new.async -------------------------------- //
|
||||
|
||||
function CommentsNewOperations (comment) {
|
||||
|
||||
var userId = comment.userId;
|
||||
|
||||
// increment comment count
|
||||
Users.update({_id: userId}, {
|
||||
$inc: {'__commentCount': 1}
|
||||
});
|
||||
|
||||
// update post
|
||||
Posts.update(comment.postId, {
|
||||
$inc: {commentCount: 1},
|
||||
$set: {lastCommentedAt: new Date()},
|
||||
$addToSet: {commenters: userId}
|
||||
});
|
||||
|
||||
return comment;
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.async", CommentsNewOperations);
|
||||
|
||||
function CommentsNewUpvoteOwnComment (comment) {
|
||||
|
||||
if (typeof Telescope.operateOnItem !== "undefined") {
|
||||
|
||||
var commentAuthor = Users.findOne(comment.userId);
|
||||
|
||||
// upvote comment
|
||||
Telescope.operateOnItem(Comments, comment, commentAuthor, "upvote");
|
||||
|
||||
return comment;
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.async", CommentsNewUpvoteOwnComment);
|
||||
|
||||
// add new comment notification callback on comment submit
|
||||
function CommentsNewNotifications (comment) {
|
||||
|
||||
if (typeof Telescope.notifications !== "undefined") {
|
||||
|
||||
// note: dummy content has disableNotifications set to true
|
||||
if(Meteor.isServer && !comment.disableNotifications){
|
||||
|
||||
var post = Posts.findOne(comment.postId),
|
||||
postAuthor = Users.findOne(post.userId),
|
||||
userIdsNotified = [],
|
||||
notificationData = {
|
||||
comment: _.pick(comment, '_id', 'userId', 'author', 'htmlBody', 'postId'),
|
||||
post: _.pick(post, '_id', 'userId', 'title', 'url')
|
||||
};
|
||||
|
||||
|
||||
// 1. Notify author of post (if they have new comment notifications turned on)
|
||||
// but do not notify author of post if they're the ones posting the comment
|
||||
if (Users.getSetting(postAuthor, "notifications_comments", true) && comment.userId !== postAuthor._id) {
|
||||
Telescope.notifications.create(post.userId, 'newComment', notificationData);
|
||||
userIdsNotified.push(post.userId);
|
||||
}
|
||||
|
||||
// 2. Notify author of comment being replied to
|
||||
if (!!comment.parentCommentId) {
|
||||
|
||||
var parentComment = Comments.findOne(comment.parentCommentId);
|
||||
|
||||
// do not notify author of parent comment if they're also post author or comment author
|
||||
// (someone could be replying to their own comment)
|
||||
if (parentComment.userId !== post.userId && parentComment.userId !== comment.userId) {
|
||||
|
||||
var parentCommentAuthor = Users.findOne(parentComment.userId);
|
||||
|
||||
// do not notify parent comment author if they have reply notifications turned off
|
||||
if (Users.getSetting(parentCommentAuthor, "notifications_replies", true)) {
|
||||
|
||||
// add parent comment to notification data
|
||||
notificationData.parentComment = _.pick(parentComment, '_id', 'userId', 'author', 'htmlBody');
|
||||
|
||||
Telescope.notifications.create(parentComment.userId, 'newReply', notificationData);
|
||||
userIdsNotified.push(parentComment.userId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.async", CommentsNewNotifications);
|
||||
|
||||
// ------------------------------------- comments.edit.validate -------------------------------- //
|
||||
|
||||
function CommentsEditUserCheck (modifier, comment, user) {
|
||||
if (!user || !Users.canEdit(user, comment)) {
|
||||
throw new Meteor.Error(601, 'sorry_you_cannot_edit_this_comment');
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("comments.edit.validate", CommentsEditUserCheck);
|
||||
|
||||
function CommentsEditSubmittedPropertiesCheck (modifier, comment, user) {
|
||||
const schema = Posts.simpleSchema()._schema;
|
||||
// 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.canEditField(user, field, comment)) {
|
||||
throw new Meteor.Error("disallowed_property", 'disallowed_property_detected' + ": " + fieldName);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("comments.edit.validate", CommentsEditSubmittedPropertiesCheck);
|
||||
|
||||
|
||||
// ------------------------------------- comments.edit.sync -------------------------------- //
|
||||
|
||||
function CommentsEditGenerateHTMLBody (modifier, comment, user) {
|
||||
// if body is being modified, update htmlBody too
|
||||
if (modifier.$set && modifier.$set.body) {
|
||||
modifier.$set.htmlBody = Telescope.utils.sanitize(marked(modifier.$set.body));
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("comments.edit.sync", CommentsEditGenerateHTMLBody);
|
||||
|
||||
// ------------------------------------- comments.edit.async -------------------------------- //
|
||||
|
||||
|
||||
|
||||
// ------------------------------------- users.remove.async -------------------------------- //
|
||||
|
||||
function UsersRemoveDeleteComments (user, options) {
|
||||
if (options.deleteComments) {
|
||||
var deletedComments = Comments.remove({userId: userId});
|
||||
} else {
|
||||
// not sure if anything should be done in that scenario yet
|
||||
// Comments.update({userId: userId}, {$set: {author: "\[deleted\]"}}, {multi: true});
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("users.remove.async", UsersRemoveDeleteComments);
|
||||
|
||||
// Add to posts.single publication
|
||||
|
||||
function PostsSingleAddCommentsUsers (users, post) {
|
||||
// get IDs from all commenters on the post
|
||||
const comments = Comments.find({postId: post._id}).fetch();
|
||||
if (comments.length) {
|
||||
users = users.concat(_.pluck(comments, "userId"));
|
||||
}
|
||||
return users;
|
||||
}
|
||||
Telescope.callbacks.add("posts.single.getUsers", PostsSingleAddCommentsUsers);
|
|
@ -0,0 +1,45 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import Posts from "meteor/nova:posts";
|
||||
import Comments from '../collection.js';
|
||||
import Users from 'meteor/nova:users';
|
||||
|
||||
// ------------------------------------- comments.edit.validate -------------------------------- //
|
||||
|
||||
function CommentsEditUserCheck (modifier, comment, user) {
|
||||
if (!user || !Users.canEdit(user, comment)) {
|
||||
throw new Meteor.Error(601, 'sorry_you_cannot_edit_this_comment');
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("comments.edit.validate", CommentsEditUserCheck);
|
||||
|
||||
function CommentsEditSubmittedPropertiesCheck (modifier, comment, user) {
|
||||
const schema = Posts.simpleSchema()._schema;
|
||||
// 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.canEditField(user, field, comment)) {
|
||||
throw new Meteor.Error("disallowed_property", 'disallowed_property_detected' + ": " + fieldName);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("comments.edit.validate", CommentsEditSubmittedPropertiesCheck);
|
||||
|
||||
|
||||
// ------------------------------------- comments.edit.sync -------------------------------- //
|
||||
|
||||
function CommentsEditGenerateHTMLBody (modifier, comment, user) {
|
||||
// if body is being modified, update htmlBody too
|
||||
if (modifier.$set && modifier.$set.body) {
|
||||
modifier.$set.htmlBody = Telescope.utils.sanitize(marked(modifier.$set.body));
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("comments.edit.sync", CommentsEditGenerateHTMLBody);
|
179
packages/nova-comments/lib/callbacks/callbacks_comments_new.js
Normal file
179
packages/nova-comments/lib/callbacks/callbacks_comments_new.js
Normal file
|
@ -0,0 +1,179 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import Posts from "meteor/nova:posts";
|
||||
import Comments from '../collection.js';
|
||||
import Users from 'meteor/nova:users';
|
||||
|
||||
// ------------------------------------- comments.new.validate -------------------------------- //
|
||||
|
||||
// function CommentsNewUserCheck (comment, user) {
|
||||
// // check that user can post
|
||||
// if (!user || !Users.canDo(user, "comments.new"))
|
||||
// throw new Meteor.Error(601, 'you_need_to_login_or_be_invited_to_post_new_comments');
|
||||
// return comment;
|
||||
// }
|
||||
// Telescope.callbacks.add("comments.new.sync", CommentsNewUserCheck);
|
||||
|
||||
function CommentsNewRateLimit (comment, user) {
|
||||
if (!Users.isAdmin(user)) {
|
||||
const timeSinceLastComment = Users.timeSinceLast(user, Comments);
|
||||
const commentInterval = Math.abs(parseInt(Telescope.settings.get('commentInterval',15)));
|
||||
// check that user waits more than 15 seconds between comments
|
||||
if((timeSinceLastComment < commentInterval)) {
|
||||
throw new Meteor.Error("CommentsNewRateLimit", "comments.rate_limit_error", commentInterval-timeSinceLastComment);
|
||||
}
|
||||
}
|
||||
return comment;
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.validate", CommentsNewRateLimit);
|
||||
|
||||
// function CommentsNewSubmittedPropertiesCheck (comment, user) {
|
||||
// // admin-only properties
|
||||
// // userId
|
||||
// const schema = Comments.simpleSchema()._schema;
|
||||
|
||||
// // clear restricted properties
|
||||
// _.keys(comment).forEach(function (fieldName) {
|
||||
|
||||
// // make an exception for postId, which should be setable but not modifiable
|
||||
// if (fieldName === "postId") {
|
||||
// // ok
|
||||
// } else {
|
||||
// var field = schema[fieldName];
|
||||
// if (!Users.canSubmitField (user, field)) {
|
||||
// throw new Meteor.Error("disallowed_property", 'disallowed_property_detected' + ": " + fieldName);
|
||||
// }
|
||||
// }
|
||||
|
||||
// });
|
||||
|
||||
// // if no userId has been set, default to current user id
|
||||
// if (!comment.userId) {
|
||||
// comment.userId = user._id;
|
||||
// }
|
||||
// return comment;
|
||||
// }
|
||||
// Telescope.callbacks.add("comments.new.validate", CommentsNewSubmittedPropertiesCheck);
|
||||
|
||||
// ------------------------------------- comments.new.sync -------------------------------- //
|
||||
|
||||
/**
|
||||
* @summary Check for required properties
|
||||
*/
|
||||
// function CommentsNewRequiredPropertiesCheck (comment, user) {
|
||||
|
||||
// var userId = comment.userId; // at this stage, a userId is expected
|
||||
|
||||
// // Don't allow empty comments
|
||||
// if (!comment.body)
|
||||
// throw new Meteor.Error(704, 'your_comment_is_empty');
|
||||
|
||||
// var defaultProperties = {
|
||||
// createdAt: new Date(),
|
||||
// postedAt: new Date(),
|
||||
// upvotes: 0,
|
||||
// downvotes: 0,
|
||||
// baseScore: 0,
|
||||
// score: 0,
|
||||
// author: Users.getDisplayNameById(userId)
|
||||
// };
|
||||
|
||||
// comment = _.extend(defaultProperties, comment);
|
||||
|
||||
// return comment;
|
||||
// }
|
||||
// Telescope.callbacks.add("comments.new.sync", CommentsNewRequiredPropertiesCheck);
|
||||
|
||||
// function CommentsNewGenerateHTMLBody (comment, user) {
|
||||
// comment.htmlBody = Telescope.utils.sanitize(marked(comment.body));
|
||||
// return comment;
|
||||
// }
|
||||
// Telescope.callbacks.add("comments.new.sync", CommentsNewGenerateHTMLBody);
|
||||
|
||||
// ------------------------------------- comments.new.async -------------------------------- //
|
||||
|
||||
function CommentsNewOperations (comment) {
|
||||
|
||||
var userId = comment.userId;
|
||||
|
||||
// increment comment count
|
||||
Users.update({_id: userId}, {
|
||||
$inc: {'__commentCount': 1}
|
||||
});
|
||||
|
||||
// update post
|
||||
Posts.update(comment.postId, {
|
||||
$inc: {commentCount: 1},
|
||||
$set: {lastCommentedAt: new Date()},
|
||||
$addToSet: {commenters: userId}
|
||||
});
|
||||
|
||||
return comment;
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.async", CommentsNewOperations);
|
||||
|
||||
function CommentsNewUpvoteOwnComment (comment) {
|
||||
|
||||
if (typeof Telescope.operateOnItem !== "undefined") {
|
||||
|
||||
var commentAuthor = Users.findOne(comment.userId);
|
||||
|
||||
// upvote comment
|
||||
Telescope.operateOnItem(Comments, comment, commentAuthor, "upvote");
|
||||
|
||||
return comment;
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.async", CommentsNewUpvoteOwnComment);
|
||||
|
||||
// add new comment notification callback on comment submit
|
||||
function CommentsNewNotifications (comment) {
|
||||
|
||||
if (typeof Telescope.notifications !== "undefined") {
|
||||
|
||||
// note: dummy content has disableNotifications set to true
|
||||
if(Meteor.isServer && !comment.disableNotifications){
|
||||
|
||||
var post = Posts.findOne(comment.postId),
|
||||
postAuthor = Users.findOne(post.userId),
|
||||
userIdsNotified = [],
|
||||
notificationData = {
|
||||
comment: _.pick(comment, '_id', 'userId', 'author', 'htmlBody', 'postId'),
|
||||
post: _.pick(post, '_id', 'userId', 'title', 'url')
|
||||
};
|
||||
|
||||
|
||||
// 1. Notify author of post (if they have new comment notifications turned on)
|
||||
// but do not notify author of post if they're the ones posting the comment
|
||||
if (Users.getSetting(postAuthor, "notifications_comments", true) && comment.userId !== postAuthor._id) {
|
||||
Telescope.notifications.create(post.userId, 'newComment', notificationData);
|
||||
userIdsNotified.push(post.userId);
|
||||
}
|
||||
|
||||
// 2. Notify author of comment being replied to
|
||||
if (!!comment.parentCommentId) {
|
||||
|
||||
var parentComment = Comments.findOne(comment.parentCommentId);
|
||||
|
||||
// do not notify author of parent comment if they're also post author or comment author
|
||||
// (someone could be replying to their own comment)
|
||||
if (parentComment.userId !== post.userId && parentComment.userId !== comment.userId) {
|
||||
|
||||
var parentCommentAuthor = Users.findOne(parentComment.userId);
|
||||
|
||||
// do not notify parent comment author if they have reply notifications turned off
|
||||
if (Users.getSetting(parentCommentAuthor, "notifications_replies", true)) {
|
||||
|
||||
// add parent comment to notification data
|
||||
notificationData.parentComment = _.pick(parentComment, '_id', 'userId', 'author', 'htmlBody');
|
||||
|
||||
Telescope.notifications.create(parentComment.userId, 'newReply', notificationData);
|
||||
userIdsNotified.push(parentComment.userId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("comments.new.async", CommentsNewNotifications);
|
26
packages/nova-comments/lib/callbacks/callbacks_other.js
Normal file
26
packages/nova-comments/lib/callbacks/callbacks_other.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import Posts from "meteor/nova:posts";
|
||||
import Comments from '../collection.js';
|
||||
import Users from 'meteor/nova:users';
|
||||
|
||||
function UsersRemoveDeleteComments (user, options) {
|
||||
if (options.deleteComments) {
|
||||
var deletedComments = Comments.remove({userId: userId});
|
||||
} else {
|
||||
// not sure if anything should be done in that scenario yet
|
||||
// Comments.update({userId: userId}, {$set: {author: "\[deleted\]"}}, {multi: true});
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("users.remove.async", UsersRemoveDeleteComments);
|
||||
|
||||
// Add to posts.single publication
|
||||
|
||||
function PostsSingleAddCommentsUsers (users, post) {
|
||||
// get IDs from all commenters on the post
|
||||
const comments = Comments.find({postId: post._id}).fetch();
|
||||
if (comments.length) {
|
||||
users = users.concat(_.pluck(comments, "userId"));
|
||||
}
|
||||
return users;
|
||||
}
|
||||
Telescope.callbacks.add("posts.single.getUsers", PostsSingleAddCommentsUsers);
|
|
@ -2,7 +2,9 @@ import Comments from './collection.js';
|
|||
|
||||
import './schema.js';
|
||||
import './methods.js';
|
||||
import './callbacks.js';
|
||||
import './callbacks/callbacks_comments_new.js';
|
||||
import './callbacks/callbacks_comments_edit.js';
|
||||
import './callbacks/callbacks_other.js';
|
||||
import './views.js';
|
||||
import './parameters.js';
|
||||
import './notifications.js';
|
||||
|
|
|
@ -8,6 +8,7 @@ Comments.mutations = {
|
|||
|
||||
commentsNew(root, {document}, context) {
|
||||
return newMutation({
|
||||
action: 'comments.new',
|
||||
collection: context.Comments,
|
||||
document: document,
|
||||
currentUser: context.currentUser,
|
||||
|
@ -16,7 +17,12 @@ Comments.mutations = {
|
|||
},
|
||||
|
||||
commentsEdit(root, {documentId, set, unset}, context) {
|
||||
|
||||
const document = Comments.findOne(documentId);
|
||||
const action = Users.owns(context.currentUser, document) ? 'comments.edit.own' : 'comments.edit.all';
|
||||
|
||||
return editMutation({
|
||||
action: action,
|
||||
collection: context.Comments,
|
||||
documentId: documentId,
|
||||
set: set,
|
||||
|
@ -27,7 +33,12 @@ Comments.mutations = {
|
|||
},
|
||||
|
||||
commentsRemove(root, {documentId}, context) {
|
||||
|
||||
const document = Comments.findOne(documentId);
|
||||
const action = Users.owns(context.currentUser, document) ? 'comments.remove.own' : 'comments.remove.all';
|
||||
|
||||
return removeMutation({
|
||||
action: action,
|
||||
collection: context.Comments,
|
||||
documentId: documentId,
|
||||
currentUser: context.currentUser,
|
||||
|
|
|
@ -64,6 +64,9 @@ Comments.schema = new SimpleSchema({
|
|||
optional: true,
|
||||
publish: false,
|
||||
viewableIf: canEditAll,
|
||||
autoValue: (documentOrModifier) => {
|
||||
if (documentOrModifier && !documentOrModifier.$set) return new Date() // if this is an insert, set createdAt to current timestamp
|
||||
}
|
||||
},
|
||||
/**
|
||||
The timestamp of the comment being posted. For now, comments are always created and posted at the same time
|
||||
|
@ -72,7 +75,10 @@ Comments.schema = new SimpleSchema({
|
|||
type: Date,
|
||||
optional: true,
|
||||
publish: true,
|
||||
viewableIf: alwaysPublic,
|
||||
viewableIf: alwaysPublic,
|
||||
autoValue: (documentOrModifier) => {
|
||||
if (documentOrModifier && !documentOrModifier.$set) return new Date() // if this is an insert, set createdAt to current timestamp
|
||||
}
|
||||
},
|
||||
/**
|
||||
The comment body (Markdown)
|
||||
|
@ -103,6 +109,11 @@ Comments.schema = new SimpleSchema({
|
|||
optional: true,
|
||||
publish: true,
|
||||
viewableIf: alwaysPublic,
|
||||
autoValue: (documentOrModifier) => {
|
||||
// if userId is changing, change the author name too
|
||||
const userId = documentOrModifier.userId || documentOrModifier.$set && documentOrModifier.$set.userId
|
||||
if (userId) return Users.getDisplayNameById(userId)
|
||||
}
|
||||
},
|
||||
/**
|
||||
Whether the comment is inactive. Inactive comments' scores gets recalculated less often
|
||||
|
|
|
@ -5,8 +5,13 @@ Mutations have four steps:
|
|||
1. Validation
|
||||
|
||||
If the mutation call is not trusted (i.e. it comes from a GraphQL mutation),
|
||||
we'll run all validate callbacks. In any case, we'll also validate the
|
||||
arguments against our schema.
|
||||
we'll run all validate steps:
|
||||
|
||||
- Check that the current user is defined and has permission to perform the action.
|
||||
- Check that the current user has permission to insert/edit each field.
|
||||
- Validate document against collection schema.
|
||||
- Add userId to document (insert only).
|
||||
- Run validation callbacks.
|
||||
|
||||
2. Sync Callbacks
|
||||
|
||||
|
@ -25,21 +30,43 @@ to the client.
|
|||
*/
|
||||
|
||||
|
||||
const newMutation = ({ collection, document, currentUser, validate }) => {
|
||||
const newMutation = ({ action, collection, document, currentUser, validate }) => {
|
||||
|
||||
console.log("// newMutation")
|
||||
console.log(action)
|
||||
console.log(collection._name)
|
||||
console.log(document)
|
||||
|
||||
const collectionName = collection._name;
|
||||
|
||||
// if document is not trusted, run validation callbacks
|
||||
const collectionName = collection._name;
|
||||
const schema = collection.simpleSchema()._schema;
|
||||
|
||||
// if document is not trusted, run validation steps
|
||||
if (validate) {
|
||||
|
||||
// check if current user has permission to perform the current action
|
||||
if (!currentUser || !Users.canDo(currentUser, action)) {
|
||||
throw new Meteor.Error(601, `Sorry, you don't have the proper permissions to perform this action`);
|
||||
}
|
||||
|
||||
// check that the current user has permission to insert each field
|
||||
_.keys(document).forEach(function (fieldName) {
|
||||
var field = schema[fieldName];
|
||||
if (!Users.canSubmitField (currentUser, field)) {
|
||||
throw new Meteor.Error('disallowed_property', `disallowed_property_detected: ${fieldName}`);
|
||||
}
|
||||
});
|
||||
|
||||
// validate document against schema
|
||||
collection.simpleSchema().namedContext(`${collectionName}.new`).validate(document);
|
||||
|
||||
// add userId to document
|
||||
document.userId = currentUser._id;
|
||||
|
||||
// run validation callbacks
|
||||
document = Telescope.callbacks.run(`${collectionName}.new.validate`, document, currentUser);
|
||||
}
|
||||
|
||||
// validate document against schema
|
||||
collection.simpleSchema().namedContext(`${collectionName}.new`).validate(document);
|
||||
|
||||
// TODO: find that info in GraphQL mutations
|
||||
// if (Meteor.isServer && this.connection) {
|
||||
|
@ -60,18 +87,22 @@ const newMutation = ({ collection, document, currentUser, validate }) => {
|
|||
// note: query for document to get fresh document with collection-hooks effects applied
|
||||
Telescope.callbacks.runAsync(`${collectionName}.new.async`, newDocument, currentUser);
|
||||
|
||||
console.log("// new mutation finished:")
|
||||
console.log(newDocument)
|
||||
return document;
|
||||
}
|
||||
|
||||
const editMutation = ({ collection, documentId, set, unset, currentUser, validate }) => {
|
||||
const editMutation = ({ action, collection, documentId, set, unset, currentUser, validate }) => {
|
||||
|
||||
console.log("// editMutation")
|
||||
console.log(action)
|
||||
console.log(collection._name)
|
||||
console.log(documentId)
|
||||
console.log(set)
|
||||
console.log(unset)
|
||||
|
||||
const collectionName = collection._name;
|
||||
const schema = collection.simpleSchema()._schema;
|
||||
|
||||
// build mongo modifier from arguments
|
||||
let modifier = {$set: set, $unset: unset};
|
||||
|
@ -79,14 +110,30 @@ const editMutation = ({ collection, documentId, set, unset, currentUser, validat
|
|||
// get original document from database
|
||||
let document = collection.findOne(documentId);
|
||||
|
||||
// if document is not trusted, run validation callbacks
|
||||
// if document is not trusted, run validation steps
|
||||
if (validate) {
|
||||
|
||||
// check if current user has permission to perform the current action
|
||||
if (!currentUser || !Users.canDo(currentUser, action)) {
|
||||
throw new Meteor.Error(601, `Sorry, you don't have the proper permissions to perform this action`);
|
||||
}
|
||||
|
||||
// check that the current user has permission to edit each field
|
||||
const modifiedProperties = _.keys(set).concat(_.keys(unset));
|
||||
modifiedProperties.forEach(function (fieldName) {
|
||||
var field = schema[fieldName];
|
||||
if (!Users.canEditField(currentUser, field, document)) {
|
||||
throw new Meteor.Error('disallowed_property', `disallowed_property_detected: ${fieldName}`);
|
||||
}
|
||||
});
|
||||
|
||||
// validate modifier against schema
|
||||
collection.simpleSchema().namedContext(`${collectionName}.edit`).validate(modifier, {modifier: true});
|
||||
|
||||
// run validation callbacks
|
||||
document = Telescope.callbacks.run(`${collectionName}.edit.validate`, modifier, document, currentUser);
|
||||
}
|
||||
|
||||
// validate modifier against schema
|
||||
collection.simpleSchema().namedContext(`${collectionName}.edit`).validate(modifier, {modifier: true});
|
||||
|
||||
// run sync callbacks (on mongo modifier)
|
||||
modifier = Telescope.callbacks.run(`${collectionName}.edit.sync`, modifier, document, currentUser);
|
||||
|
||||
|
@ -99,10 +146,13 @@ const editMutation = ({ collection, documentId, set, unset, currentUser, validat
|
|||
// run async callbacks
|
||||
Telescope.callbacks.runAsync(`${collectionName}.edit.async`, newDocument, document, currentUser);
|
||||
|
||||
console.log("// edit mutation finished")
|
||||
console.log(newDocument)
|
||||
|
||||
return newDocument;
|
||||
}
|
||||
|
||||
const removeMutation = ({ collection, documentId, currentUser, validate }) => {
|
||||
const removeMutation = ({ action, collection, documentId, currentUser, validate }) => {
|
||||
|
||||
console.log("// removeMutation")
|
||||
console.log(collection._name)
|
||||
|
|
|
@ -1,414 +1,46 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import Posts from './collection.js'
|
||||
import marked from 'marked';
|
||||
import Users from 'meteor/nova:users';
|
||||
// import Telescope from 'meteor/nova:lib';
|
||||
// import Posts from './collection.js'
|
||||
// import marked from 'marked';
|
||||
// import Users from 'meteor/nova:users';
|
||||
|
||||
// //////////////////////////////////////////////////////
|
||||
// // Collection Hooks //
|
||||
// //////////////////////////////////////////////////////
|
||||
|
||||
// /**
|
||||
// * @summary Generate HTML body and excerpt from Markdown on post insert
|
||||
// */
|
||||
// Posts.before.insert(function (userId, doc) {
|
||||
// if(!!doc.body) {
|
||||
// const htmlBody = Telescope.utils.sanitize(marked(doc.body));
|
||||
// doc.htmlBody = htmlBody;
|
||||
// doc.excerpt = Telescope.utils.trimHTML(htmlBody,30);
|
||||
// }
|
||||
// });
|
||||
|
||||
// /**
|
||||
// * @summary Generate HTML body and excerpt from Markdown when post body is updated
|
||||
// */
|
||||
// Posts.before.update(function (userId, doc, fieldNames, modifier) {
|
||||
// // if body is being modified or $unset, update htmlBody too
|
||||
// if (Meteor.isServer && modifier.$set && modifier.$set.body) {
|
||||
// const htmlBody = Telescope.utils.sanitize(marked(modifier.$set.body));
|
||||
// modifier.$set.htmlBody = htmlBody;
|
||||
// modifier.$set.excerpt = Telescope.utils.trimHTML(htmlBody,30);
|
||||
// }
|
||||
// if (Meteor.isServer && modifier.$unset && (typeof modifier.$unset.body !== "undefined")) {
|
||||
// modifier.$unset.htmlBody = "";
|
||||
// modifier.$unset.excerpt = "";
|
||||
// }
|
||||
// });
|
||||
|
||||
// /**
|
||||
// * @summary Generate slug when post title is updated
|
||||
// */
|
||||
// Posts.before.update(function (userId, doc, fieldNames, modifier) {
|
||||
// // if title is being modified, update slug too
|
||||
// if (Meteor.isServer && modifier.$set && modifier.$set.title) {
|
||||
// modifier.$set.slug = Telescope.utils.slugify(modifier.$set.title);
|
||||
// }
|
||||
// });
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Collection Hooks //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* @summary Generate HTML body and excerpt from Markdown on post insert
|
||||
*/
|
||||
Posts.before.insert(function (userId, doc) {
|
||||
if(!!doc.body) {
|
||||
const htmlBody = Telescope.utils.sanitize(marked(doc.body));
|
||||
doc.htmlBody = htmlBody;
|
||||
doc.excerpt = Telescope.utils.trimHTML(htmlBody,30);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @summary Generate HTML body and excerpt from Markdown when post body is updated
|
||||
*/
|
||||
Posts.before.update(function (userId, doc, fieldNames, modifier) {
|
||||
// if body is being modified or $unset, update htmlBody too
|
||||
if (Meteor.isServer && modifier.$set && modifier.$set.body) {
|
||||
const htmlBody = Telescope.utils.sanitize(marked(modifier.$set.body));
|
||||
modifier.$set.htmlBody = htmlBody;
|
||||
modifier.$set.excerpt = Telescope.utils.trimHTML(htmlBody,30);
|
||||
}
|
||||
if (Meteor.isServer && modifier.$unset && (typeof modifier.$unset.body !== "undefined")) {
|
||||
modifier.$unset.htmlBody = "";
|
||||
modifier.$unset.excerpt = "";
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @summary Generate slug when post title is updated
|
||||
*/
|
||||
Posts.before.update(function (userId, doc, fieldNames, modifier) {
|
||||
// if title is being modified, update slug too
|
||||
if (Meteor.isServer && modifier.$set && modifier.$set.title) {
|
||||
modifier.$set.slug = Telescope.utils.slugify(modifier.$set.title);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @summary Disallow $rename
|
||||
*/
|
||||
Posts.before.update(function (userId, doc, fieldNames, modifier) {
|
||||
if (!!modifier.$rename) {
|
||||
throw new Meteor.Error("illegal $rename operator detected!");
|
||||
}
|
||||
});
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// Callbacks //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
|
||||
### posts.new.validate
|
||||
|
||||
- PostsNewUserCheck
|
||||
- PostsNewRateLimit
|
||||
- PostsNewSubmittedPropertiesCheck
|
||||
|
||||
### posts.new.sync
|
||||
|
||||
- PostsNewDuplicateLinksCheck
|
||||
- PostsNewRequiredPropertiesCheck
|
||||
|
||||
### posts.new.async
|
||||
|
||||
- PostsNewIncrementPostCount
|
||||
- PostsNewUpvoteOwnPost
|
||||
- PostsNewNotifications
|
||||
|
||||
### posts.edit.validate
|
||||
|
||||
- PostsEditUserCheck
|
||||
- PostsEditSubmittedPropertiesCheck
|
||||
|
||||
### posts.edit.sync
|
||||
|
||||
- PostsEditDuplicateLinksCheck
|
||||
- PostsEditForceStickyToFalse
|
||||
|
||||
### posts.edit.async
|
||||
|
||||
- PostsEditSetPostedAt
|
||||
- PostsEditRunPostApprovedCallbacks
|
||||
|
||||
### posts.approve.async
|
||||
|
||||
- PostsApprovedNotification
|
||||
|
||||
### users.remove.async
|
||||
|
||||
- UsersRemoveDeletePosts
|
||||
|
||||
*/
|
||||
|
||||
// ------------------------------------- posts.new.validate -------------------------------- //
|
||||
|
||||
/**
|
||||
* @summary Check that the current user can post
|
||||
*/
|
||||
function PostsNewUserCheck (post, user) {
|
||||
// check that user can post
|
||||
if (!user || !Users.canDo(user, "posts.new"))
|
||||
throw new Meteor.Error(601, 'you_need_to_login_or_be_invited_to_post_new_stories');
|
||||
return post;
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.validate", PostsNewUserCheck);
|
||||
|
||||
/**
|
||||
* @summary Rate limiting
|
||||
*/
|
||||
function PostsNewRateLimit (post, user) {
|
||||
|
||||
if(!Users.isAdmin(user)){
|
||||
|
||||
var timeSinceLastPost = Users.timeSinceLast(user, Posts),
|
||||
numberOfPostsInPast24Hours = Users.numberOfItemsInPast24Hours(user, Posts),
|
||||
postInterval = Math.abs(parseInt(Telescope.settings.get('postInterval', 30))),
|
||||
maxPostsPer24Hours = Math.abs(parseInt(Telescope.settings.get('maxPostsPerDay', 30)));
|
||||
|
||||
// check that user waits more than X seconds between posts
|
||||
if(timeSinceLastPost < postInterval)
|
||||
throw new Meteor.Error(604, 'please_wait'+(postInterval-timeSinceLastPost)+'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, 'sorry_you_cannot_submit_more_than'+maxPostsPer24Hours+'posts_per_day');
|
||||
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.validate", PostsNewRateLimit);
|
||||
|
||||
/**
|
||||
* @summary Properties
|
||||
*/
|
||||
function PostsNewSubmittedPropertiesCheck (post, user) {
|
||||
|
||||
// admin-only properties
|
||||
// status
|
||||
// postedAt
|
||||
// userId
|
||||
// sticky (default to false)
|
||||
|
||||
const schema = Posts.simpleSchema()._schema;
|
||||
|
||||
// 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.canSubmitField (user, field)) {
|
||||
throw new Meteor.Error("disallowed_property", 'disallowed_property_detected' + ": " + fieldName);
|
||||
}
|
||||
|
||||
});
|
||||
// note: not needed there anymore, this is already set in the next callback 'posts.new.sync' with other related properties (status, createdAt)
|
||||
// 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 post;
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.validate", PostsNewSubmittedPropertiesCheck);
|
||||
|
||||
// ------------------------------------- posts.new.sync -------------------------------- //
|
||||
|
||||
/**
|
||||
* @summary Check for duplicate links
|
||||
*/
|
||||
function PostsNewDuplicateLinksCheck (post, user) {
|
||||
if(!!post.url) {
|
||||
Posts.checkForSameUrl(post.url);
|
||||
}
|
||||
return post;
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.sync", PostsNewDuplicateLinksCheck);
|
||||
|
||||
/**
|
||||
* @summary Check for necessary properties
|
||||
*/
|
||||
function PostsNewRequiredPropertiesCheck (post, user) {
|
||||
|
||||
// initialize default properties
|
||||
const defaultProperties = {
|
||||
createdAt: new Date(),
|
||||
author: Users.getDisplayNameById(post.userId),
|
||||
status: Posts.getDefaultStatus(user)
|
||||
};
|
||||
|
||||
post = _.extend(defaultProperties, post);
|
||||
|
||||
// generate slug
|
||||
post.slug = Telescope.utils.slugify(post.title);
|
||||
|
||||
// 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 (Posts.isApproved(post) && !post.postedAt) {
|
||||
post.postedAt = new Date();
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.sync", PostsNewRequiredPropertiesCheck);
|
||||
|
||||
/**
|
||||
* @summary Set the post's isFuture to true if necessary
|
||||
*/
|
||||
function PostsNewSetFuture (post, user) {
|
||||
post.isFuture = post.postedAt && new Date(post.postedAt).getTime() > new Date(post.createdAt).getTime() + 1000; // round up to the second
|
||||
return post;
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.sync", PostsNewSetFuture);
|
||||
|
||||
// ------------------------------------- posts.new.async -------------------------------- //
|
||||
|
||||
/**
|
||||
* @summary Increment the user's post count
|
||||
*/
|
||||
function PostsNewIncrementPostCount (post) {
|
||||
var userId = post.userId;
|
||||
Users.update({_id: userId}, {$inc: {"__postCount": 1}});
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.async", PostsNewIncrementPostCount);
|
||||
|
||||
/**
|
||||
* @summary Make users upvote their own new posts
|
||||
*/
|
||||
function PostsNewUpvoteOwnPost (post) {
|
||||
if (typeof Telescope.operateOnItem !== "undefined") {
|
||||
var postAuthor = Users.findOne(post.userId);
|
||||
Telescope.operateOnItem(Posts, post, postAuthor, "upvote");
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.async", PostsNewUpvoteOwnPost);
|
||||
|
||||
/**
|
||||
* @summary Add new post notification callback on post submit
|
||||
*/
|
||||
function PostsNewNotifications (post) {
|
||||
|
||||
if (typeof Telescope.notifications !== "undefined") {
|
||||
|
||||
var adminIds = _.pluck(Users.adminUsers({fields: {_id:1}}), '_id');
|
||||
var notifiedUserIds = _.pluck(Users.find({'__notifications_posts': true}, {fields: {_id:1}}).fetch(), '_id');
|
||||
var notificationData = {
|
||||
post: _.pick(post, '_id', 'userId', 'title', 'url', 'slug')
|
||||
};
|
||||
|
||||
// remove post author ID from arrays
|
||||
adminIds = _.without(adminIds, post.userId);
|
||||
notifiedUserIds = _.without(notifiedUserIds, post.userId);
|
||||
|
||||
if (post.status === Posts.config.STATUS_PENDING && !!adminIds.length) {
|
||||
// if post is pending, only notify admins
|
||||
Telescope.notifications.create(adminIds, 'newPendingPost', notificationData);
|
||||
} else if (!!notifiedUserIds.length) {
|
||||
// if post is approved, notify everybody
|
||||
Telescope.notifications.create(notifiedUserIds, 'newPost', notificationData);
|
||||
}
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.async", PostsNewNotifications);
|
||||
|
||||
// ------------------------------------- posts.edit.validate -------------------------------- //
|
||||
|
||||
function PostsEditUserCheck (modifier, post, user) {
|
||||
// check that user can edit document
|
||||
if (!user || !Users.canEdit(user, post)) {
|
||||
throw new Meteor.Error(601, 'sorry_you_cannot_edit_this_post');
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("posts.edit.validate", PostsEditUserCheck);
|
||||
|
||||
function PostsEditSubmittedPropertiesCheck (modifier, post, user) {
|
||||
const schema = Posts.simpleSchema()._schema;
|
||||
// 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.canEditField(user, field, post)) {
|
||||
throw new Meteor.Error("disallowed_property", 'disallowed_property_detected' + ": " + fieldName);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("posts.edit.validate", PostsEditSubmittedPropertiesCheck);
|
||||
|
||||
// ------------------------------------- posts.edit.sync -------------------------------- //
|
||||
|
||||
/**
|
||||
* @summary Check for duplicate links
|
||||
*/
|
||||
const PostsEditDuplicateLinksCheck = (modifier, post) => {
|
||||
if(post.url !== modifier.$set.url && !!modifier.$set.url) {
|
||||
Posts.checkForSameUrl(modifier.$set.url);
|
||||
}
|
||||
return modifier;
|
||||
};
|
||||
Telescope.callbacks.add("posts.edit.sync", PostsEditDuplicateLinksCheck);
|
||||
|
||||
/**
|
||||
* @summary Force sticky to default to false when it's not specified
|
||||
* (simpleSchema's defaultValue does not work on edit, so do it manually in callback)
|
||||
*/
|
||||
function PostsEditForceStickyToFalse (modifier, post) {
|
||||
if (!modifier.$set.sticky) {
|
||||
if (modifier.$unset && modifier.$unset.sticky) {
|
||||
delete modifier.$unset.sticky;
|
||||
}
|
||||
modifier.$set.sticky = false;
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("posts.edit.sync", PostsEditForceStickyToFalse);
|
||||
|
||||
/**
|
||||
* @summary Set status
|
||||
*/
|
||||
function PostsEditSetIsFuture (modifier, post) {
|
||||
// if a post's postedAt date is in the future, set isFuture to true
|
||||
modifier.$set.isFuture = modifier.$set.postedAt && new Date(modifier.$set.postedAt).getTime() > new Date().getTime() + 1000;
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("posts.edit.sync", PostsEditSetIsFuture);
|
||||
|
||||
/**
|
||||
* @summary Set postedAt date
|
||||
*/
|
||||
function PostsEditSetPostedAt (modifier, 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 (Posts.isApproved(post) && !post.postedAt) {
|
||||
modifier.$set.postedAt = new Date();
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("posts.edit.sync", PostsEditSetPostedAt);
|
||||
|
||||
// ------------------------------------- posts.edit.async -------------------------------- //
|
||||
|
||||
function PostsEditRunPostApprovedCallbacks (post, oldPost) {
|
||||
var now = new Date();
|
||||
|
||||
if (Posts.isApproved(post) && !Posts.isApproved(oldPost)) {
|
||||
Telescope.callbacks.runAsync("posts.approve.async", post);
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("posts.edit.async", PostsEditRunPostApprovedCallbacks);
|
||||
|
||||
// ------------------------------------- posts.remove.validate -------------------------------- //
|
||||
|
||||
function PostsRemoveValidation (post, currentUser) {
|
||||
if (!currentUser || !Users.canEdit(currentUser, post)){
|
||||
throw new Meteor.Error(606, 'You need permission to edit or delete a post');
|
||||
}
|
||||
return post;
|
||||
}
|
||||
Telescope.callbacks.add("posts.remove.validate", PostsRemoveValidation);
|
||||
|
||||
// ------------------------------------- posts.remove.sync -------------------------------- //
|
||||
|
||||
function PostsRemoveOperations (post) {
|
||||
Users.update({_id: post.userId}, {$inc: {"__postCount": -1}});
|
||||
}
|
||||
Telescope.callbacks.add("posts.remove.sync", PostsRemoveOperations);
|
||||
|
||||
// ------------------------------------- posts.approve.async -------------------------------- //
|
||||
|
||||
/**
|
||||
* @summary Add notification callback when a post is approved
|
||||
*/
|
||||
function PostsApprovedNotification (post) {
|
||||
if (typeof Telescope.notifications !== "undefined") {
|
||||
var notificationData = {
|
||||
post: _.pick(post, '_id', 'userId', 'title', 'url')
|
||||
};
|
||||
|
||||
Telescope.notifications.create(post.userId, 'postApproved', notificationData);
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("posts.approve.async", PostsApprovedNotification);
|
||||
|
||||
// ------------------------------------- users.remove.async -------------------------------- //
|
||||
|
||||
function UsersRemoveDeletePosts (user, options) {
|
||||
if (options.deletePosts) {
|
||||
var deletedPosts = Posts.remove({userId: userId});
|
||||
} else {
|
||||
// not sure if anything should be done in that scenario yet
|
||||
// Posts.update({userId: userId}, {$set: {author: "\[deleted\]"}}, {multi: true});
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("users.remove.async", UsersRemoveDeletePosts);
|
||||
|
|
48
packages/nova-posts/lib/callbacks/callbacks_other.js
Normal file
48
packages/nova-posts/lib/callbacks/callbacks_other.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import Posts from '../collection.js'
|
||||
import Users from 'meteor/nova:users';
|
||||
|
||||
// // ------------------------------------- posts.remove.validate -------------------------------- //
|
||||
|
||||
// function PostsRemoveValidation (post, currentUser) {
|
||||
// if (!currentUser || !Users.canEdit(currentUser, post)){
|
||||
// throw new Meteor.Error(606, 'You need permission to edit or delete a post');
|
||||
// }
|
||||
// return post;
|
||||
// }
|
||||
// Telescope.callbacks.add("posts.remove.validate", PostsRemoveValidation);
|
||||
|
||||
// ------------------------------------- posts.remove.sync -------------------------------- //
|
||||
|
||||
function PostsRemoveOperations (post) {
|
||||
Users.update({_id: post.userId}, {$inc: {"__postCount": -1}});
|
||||
}
|
||||
Telescope.callbacks.add("posts.remove.sync", PostsRemoveOperations);
|
||||
|
||||
// ------------------------------------- posts.approve.async -------------------------------- //
|
||||
|
||||
/**
|
||||
* @summary Add notification callback when a post is approved
|
||||
*/
|
||||
function PostsApprovedNotification (post) {
|
||||
if (typeof Telescope.notifications !== "undefined") {
|
||||
var notificationData = {
|
||||
post: _.pick(post, '_id', 'userId', 'title', 'url')
|
||||
};
|
||||
|
||||
Telescope.notifications.create(post.userId, 'postApproved', notificationData);
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("posts.approve.async", PostsApprovedNotification);
|
||||
|
||||
// ------------------------------------- users.remove.async -------------------------------- //
|
||||
|
||||
function UsersRemoveDeletePosts (user, options) {
|
||||
if (options.deletePosts) {
|
||||
var deletedPosts = Posts.remove({userId: userId});
|
||||
} else {
|
||||
// not sure if anything should be done in that scenario yet
|
||||
// Posts.update({userId: userId}, {$set: {author: "\[deleted\]"}}, {multi: true});
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("users.remove.async", UsersRemoveDeletePosts);
|
107
packages/nova-posts/lib/callbacks/callbacks_posts_edit.js
Normal file
107
packages/nova-posts/lib/callbacks/callbacks_posts_edit.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import Posts from '../collection.js'
|
||||
import Users from 'meteor/nova:users';
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// posts.edit.validate //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// function PostsEditUserCheck (modifier, post, user) {
|
||||
// // check that user can edit document
|
||||
// if (!user || !Users.canEdit(user, post)) {
|
||||
// throw new Meteor.Error(601, 'sorry_you_cannot_edit_this_post');
|
||||
// }
|
||||
// return modifier;
|
||||
// }
|
||||
// Telescope.callbacks.add("posts.edit.validate", PostsEditUserCheck);
|
||||
|
||||
// function PostsEditSubmittedPropertiesCheck (modifier, post, user) {
|
||||
// const schema = Posts.simpleSchema()._schema;
|
||||
// // 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.canEditField(user, field, post)) {
|
||||
// throw new Meteor.Error("disallowed_property", 'disallowed_property_detected' + ": " + fieldName);
|
||||
// }
|
||||
|
||||
// });
|
||||
// });
|
||||
// return modifier;
|
||||
// }
|
||||
// Telescope.callbacks.add("posts.edit.validate", PostsEditSubmittedPropertiesCheck);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// posts.edit.sync //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* @summary Check for duplicate links
|
||||
*/
|
||||
const PostsEditDuplicateLinksCheck = (modifier, post) => {
|
||||
if(post.url !== modifier.$set.url && !!modifier.$set.url) {
|
||||
Posts.checkForSameUrl(modifier.$set.url);
|
||||
}
|
||||
return modifier;
|
||||
};
|
||||
Telescope.callbacks.add("posts.edit.sync", PostsEditDuplicateLinksCheck);
|
||||
|
||||
/**
|
||||
* @summary Force sticky to default to false when it's not specified
|
||||
* (simpleSchema's defaultValue does not work on edit, so do it manually in callback)
|
||||
*/
|
||||
function PostsEditForceStickyToFalse (modifier, post) {
|
||||
if (!modifier.$set.sticky) {
|
||||
if (modifier.$unset && modifier.$unset.sticky) {
|
||||
delete modifier.$unset.sticky;
|
||||
}
|
||||
modifier.$set.sticky = false;
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("posts.edit.sync", PostsEditForceStickyToFalse);
|
||||
|
||||
/**
|
||||
* @summary Set status
|
||||
*/
|
||||
function PostsEditSetIsFuture (modifier, post) {
|
||||
// if a post's postedAt date is in the future, set isFuture to true
|
||||
modifier.$set.isFuture = modifier.$set.postedAt && new Date(modifier.$set.postedAt).getTime() > new Date().getTime() + 1000;
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("posts.edit.sync", PostsEditSetIsFuture);
|
||||
|
||||
/**
|
||||
* @summary Set postedAt date
|
||||
*/
|
||||
function PostsEditSetPostedAt (modifier, 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 (Posts.isApproved(post) && !post.postedAt) {
|
||||
modifier.$set.postedAt = new Date();
|
||||
}
|
||||
return modifier;
|
||||
}
|
||||
Telescope.callbacks.add("posts.edit.sync", PostsEditSetPostedAt);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// posts.edit.async //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
function PostsEditRunPostApprovedCallbacks (post, oldPost) {
|
||||
var now = new Date();
|
||||
|
||||
if (Posts.isApproved(post) && !Posts.isApproved(oldPost)) {
|
||||
Telescope.callbacks.runAsync("posts.approve.async", post);
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("posts.edit.async", PostsEditRunPostApprovedCallbacks);
|
191
packages/nova-posts/lib/callbacks/callbacks_posts_new.js
Normal file
191
packages/nova-posts/lib/callbacks/callbacks_posts_new.js
Normal file
|
@ -0,0 +1,191 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import Posts from '../collection.js'
|
||||
import marked from 'marked';
|
||||
import Users from 'meteor/nova:users';
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// posts.new.validate //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* @summary Check that the current user can post
|
||||
*/
|
||||
// function PostsNewUserCheck (post, user) {
|
||||
// // check that user can post
|
||||
// if (!user || !Users.canDo(user, "posts.new"))
|
||||
// throw new Meteor.Error(601, 'you_need_to_login_or_be_invited_to_post_new_stories');
|
||||
// return post;
|
||||
// }
|
||||
// Telescope.callbacks.add("posts.new.validate", PostsNewUserCheck);
|
||||
|
||||
/**
|
||||
* @summary Rate limiting
|
||||
*/
|
||||
function PostsNewRateLimit (post, user) {
|
||||
|
||||
if(!Users.isAdmin(user)){
|
||||
|
||||
var timeSinceLastPost = Users.timeSinceLast(user, Posts),
|
||||
numberOfPostsInPast24Hours = Users.numberOfItemsInPast24Hours(user, Posts),
|
||||
postInterval = Math.abs(parseInt(Telescope.settings.get('postInterval', 30))),
|
||||
maxPostsPer24Hours = Math.abs(parseInt(Telescope.settings.get('maxPostsPerDay', 30)));
|
||||
|
||||
// check that user waits more than X seconds between posts
|
||||
if(timeSinceLastPost < postInterval)
|
||||
throw new Meteor.Error(604, 'please_wait'+(postInterval-timeSinceLastPost)+'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, 'sorry_you_cannot_submit_more_than'+maxPostsPer24Hours+'posts_per_day');
|
||||
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.validate", PostsNewRateLimit);
|
||||
|
||||
/**
|
||||
* @summary Properties
|
||||
*/
|
||||
// function PostsNewSubmittedPropertiesCheck (post, user) {
|
||||
|
||||
// // admin-only properties
|
||||
// // status
|
||||
// // postedAt
|
||||
// // userId
|
||||
// // sticky (default to false)
|
||||
|
||||
// const schema = Posts.simpleSchema()._schema;
|
||||
|
||||
// // 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.canSubmitField (user, field)) {
|
||||
// throw new Meteor.Error("disallowed_property", 'disallowed_property_detected' + ": " + fieldName);
|
||||
// }
|
||||
|
||||
// });
|
||||
// // note: not needed there anymore, this is already set in the next callback 'posts.new.sync' with other related properties (status, createdAt)
|
||||
// // 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 post;
|
||||
// }
|
||||
// Telescope.callbacks.add("posts.new.validate", PostsNewSubmittedPropertiesCheck);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// posts.new.sync //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* @summary Check for duplicate links
|
||||
*/
|
||||
function PostsNewDuplicateLinksCheck (post, user) {
|
||||
if(!!post.url) {
|
||||
Posts.checkForSameUrl(post.url);
|
||||
}
|
||||
return post;
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.sync", PostsNewDuplicateLinksCheck);
|
||||
|
||||
/**
|
||||
* @summary Check for necessary properties
|
||||
*/
|
||||
// function PostsNewRequiredPropertiesCheck (post, user) {
|
||||
|
||||
// // initialize default properties
|
||||
// const defaultProperties = {
|
||||
// createdAt: new Date(),
|
||||
// author: Users.getDisplayNameById(post.userId),
|
||||
// status: Posts.getDefaultStatus(user)
|
||||
// };
|
||||
|
||||
// post = _.extend(defaultProperties, post);
|
||||
|
||||
// // generate slug
|
||||
// post.slug = Telescope.utils.slugify(post.title);
|
||||
|
||||
// // 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 (Posts.isApproved(post) && !post.postedAt) {
|
||||
// post.postedAt = new Date();
|
||||
// }
|
||||
|
||||
// return post;
|
||||
// }
|
||||
// Telescope.callbacks.add("posts.new.sync", PostsNewRequiredPropertiesCheck);
|
||||
|
||||
/**
|
||||
* @summary Set the post's isFuture to true if necessary
|
||||
*/
|
||||
function PostsNewSetFuture (post, user) {
|
||||
post.isFuture = post.postedAt && new Date(post.postedAt).getTime() > new Date(post.createdAt).getTime() + 1000; // round up to the second
|
||||
return post;
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.sync", PostsNewSetFuture);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// posts.new.async //
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* @summary Increment the user's post count
|
||||
*/
|
||||
function PostsNewIncrementPostCount (post) {
|
||||
var userId = post.userId;
|
||||
Users.update({_id: userId}, {$inc: {"__postCount": 1}});
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.async", PostsNewIncrementPostCount);
|
||||
|
||||
/**
|
||||
* @summary Make users upvote their own new posts
|
||||
*/
|
||||
function PostsNewUpvoteOwnPost (post) {
|
||||
if (typeof Telescope.operateOnItem !== "undefined") {
|
||||
var postAuthor = Users.findOne(post.userId);
|
||||
Telescope.operateOnItem(Posts, post, postAuthor, "upvote");
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.async", PostsNewUpvoteOwnPost);
|
||||
|
||||
/**
|
||||
* @summary Add new post notification callback on post submit
|
||||
*/
|
||||
function PostsNewNotifications (post) {
|
||||
|
||||
if (typeof Telescope.notifications !== "undefined") {
|
||||
|
||||
var adminIds = _.pluck(Users.adminUsers({fields: {_id:1}}), '_id');
|
||||
var notifiedUserIds = _.pluck(Users.find({'__notifications_posts': true}, {fields: {_id:1}}).fetch(), '_id');
|
||||
var notificationData = {
|
||||
post: _.pick(post, '_id', 'userId', 'title', 'url', 'slug')
|
||||
};
|
||||
|
||||
// remove post author ID from arrays
|
||||
adminIds = _.without(adminIds, post.userId);
|
||||
notifiedUserIds = _.without(notifiedUserIds, post.userId);
|
||||
|
||||
if (post.status === Posts.config.STATUS_PENDING && !!adminIds.length) {
|
||||
// if post is pending, only notify admins
|
||||
Telescope.notifications.create(adminIds, 'newPendingPost', notificationData);
|
||||
} else if (!!notifiedUserIds.length) {
|
||||
// if post is approved, notify everybody
|
||||
Telescope.notifications.create(notifiedUserIds, 'newPost', notificationData);
|
||||
}
|
||||
}
|
||||
}
|
||||
Telescope.callbacks.add("posts.new.async", PostsNewNotifications);
|
|
@ -7,7 +7,9 @@ import './notifications.js';
|
|||
import './views.js';
|
||||
import './helpers.js';
|
||||
import './published_fields.js';
|
||||
import './callbacks.js';
|
||||
import './callbacks/callbacks_posts_new.js';
|
||||
import './callbacks/callbacks_posts_edit.js';
|
||||
import './callbacks/callbacks_other.js';
|
||||
import './emails.js';
|
||||
import './methods.js';
|
||||
import './permissions.js';
|
||||
|
|
|
@ -8,7 +8,8 @@ Posts.mutations = {
|
|||
|
||||
postsNew(root, {document}, context) {
|
||||
return newMutation({
|
||||
collection: context.Posts,
|
||||
action: 'posts.new',
|
||||
collection: context.Posts,
|
||||
document: document,
|
||||
currentUser: context.currentUser,
|
||||
validate: true
|
||||
|
@ -16,7 +17,12 @@ Posts.mutations = {
|
|||
},
|
||||
|
||||
postsEdit(root, {documentId, set, unset}, context) {
|
||||
|
||||
const document = Posts.findOne(documentId);
|
||||
const action = Users.owns(context.currentUser, document) ? 'posts.edit.own' : 'posts.edit.all';
|
||||
|
||||
return editMutation({
|
||||
action: action,
|
||||
collection: context.Posts,
|
||||
documentId: documentId,
|
||||
set: set,
|
||||
|
@ -27,7 +33,12 @@ Posts.mutations = {
|
|||
},
|
||||
|
||||
postsRemove(root, {documentId}, context) {
|
||||
|
||||
const document = Posts.findOne(documentId);
|
||||
const action = Users.owns(context.currentUser, document) ? 'posts.remove.own' : 'posts.remove.all';
|
||||
|
||||
return removeMutation({
|
||||
action: action,
|
||||
collection: context.Posts,
|
||||
documentId: documentId,
|
||||
currentUser: context.currentUser,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import Posts from './collection.js';
|
||||
import Users from 'meteor/nova:users';
|
||||
import marked from 'marked';
|
||||
|
||||
/**
|
||||
* @summary Posts config namespace
|
||||
|
@ -53,7 +54,10 @@ Posts.schemaJSON = {
|
|||
type: Date,
|
||||
optional: true,
|
||||
viewableIf: canEditAll,
|
||||
publish: true // publish so that admins can sort pending posts by createdAt
|
||||
publish: true, // publish so that admins can sort pending posts by createdAt
|
||||
autoValue: (documentOrModifier) => {
|
||||
if (documentOrModifier && !documentOrModifier.$set) return new Date() // if this is an insert, set createdAt to current timestamp
|
||||
}
|
||||
},
|
||||
/**
|
||||
Timestamp of post first appearing on the site (i.e. being approved)
|
||||
|
@ -104,6 +108,13 @@ Posts.schemaJSON = {
|
|||
optional: true,
|
||||
viewableIf: alwaysPublic,
|
||||
publish: true,
|
||||
autoValue: (documentOrModifier) => {
|
||||
// if title is changing, return new slug
|
||||
const newTitle = documentOrModifier.title || documentOrModifier.$set && documentOrModifier.$set.title
|
||||
if (newTitle) {
|
||||
return Telescope.utils.slugify(newTitle)
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
Post body (markdown)
|
||||
|
@ -127,6 +138,14 @@ Posts.schemaJSON = {
|
|||
optional: true,
|
||||
publish: true,
|
||||
viewableIf: alwaysPublic,
|
||||
autoValue(documentOrModifier) {
|
||||
const body = documentOrModifier.body || documentOrModifier.$set && documentOrModifier.$set.body;
|
||||
if (body) {
|
||||
return Telescope.utils.sanitize(marked(body))
|
||||
} else if (documentOrModifier.$unset && documentOrModifier.$unset.body) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
Post Excerpt
|
||||
|
@ -137,6 +156,14 @@ Posts.schemaJSON = {
|
|||
max: 255, //should not be changed the 255 is max we should load for each post/item
|
||||
publish: true,
|
||||
viewableIf: alwaysPublic,
|
||||
autoValue(documentOrModifier) {
|
||||
const body = documentOrModifier.body || documentOrModifier.$set && documentOrModifier.$set.body;
|
||||
if (body) {
|
||||
return Telescope.utils.trimHTML(Telescope.utils.sanitize(marked(body)), 30);
|
||||
} else if (documentOrModifier.$unset && documentOrModifier.$unset.body) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
Count of how many times the post's page was viewed
|
||||
|
@ -178,13 +205,12 @@ Posts.schemaJSON = {
|
|||
editableIf: canEditAll,
|
||||
control: "select",
|
||||
publish: true,
|
||||
defaultValue: function () {
|
||||
// only provide a default value
|
||||
// 1) this is an insert operation
|
||||
// 2) status field is not set in the document being inserted
|
||||
var user = Users.findOne(this.userId);
|
||||
if (this.isInsert && !this.isSet)
|
||||
autoValue(documentOrModifier) {
|
||||
// provide a default value if this is an insert operation and status field is not set in the document
|
||||
if (documentOrModifier && !documentOrModifier.$set && documentOrModifier.userId) {
|
||||
const user = Users.findOne(documentOrModifier.userId);
|
||||
return Posts.getDefaultStatus(user);
|
||||
}
|
||||
},
|
||||
form: {
|
||||
noselect: true,
|
||||
|
@ -254,6 +280,11 @@ Posts.schemaJSON = {
|
|||
optional: true,
|
||||
viewableIf: alwaysPublic,
|
||||
publish: true,
|
||||
autoValue: (documentOrModifier) => {
|
||||
// if userId is changing, change the author name too
|
||||
const userId = documentOrModifier.userId || documentOrModifier.$set && documentOrModifier.$set.userId
|
||||
if (userId) return Users.getDisplayNameById(userId)
|
||||
}
|
||||
},
|
||||
/**
|
||||
The post author's `_id`.
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import Posts from "meteor/nova:posts";
|
||||
import Comments from "meteor/nova:comments";
|
||||
// import Telescope from 'meteor/nova:lib';
|
||||
// import Posts from "meteor/nova:posts";
|
||||
// import Comments from "meteor/nova:comments";
|
||||
|
||||
Meteor.startup(function () {
|
||||
var scoreInterval = parseInt(Telescope.settings.get("scoreUpdateInterval")) || 30;
|
||||
if (scoreInterval > 0) {
|
||||
// Meteor.startup(function () {
|
||||
// var scoreInterval = parseInt(Telescope.settings.get("scoreUpdateInterval")) || 30;
|
||||
// if (scoreInterval > 0) {
|
||||
|
||||
// active items get updated every N seconds
|
||||
Meteor.setInterval(function () {
|
||||
// // active items get updated every N seconds
|
||||
// Meteor.setInterval(function () {
|
||||
|
||||
var updatedPosts = 0;
|
||||
var updatedComments = 0;
|
||||
// console.log('tick ('+scoreInterval+')');
|
||||
Posts.find({'status': 2,'inactive': {$ne : true}}).forEach(function (post) { // only run scoring on approved posts
|
||||
updatedPosts += Telescope.updateScore({collection: Posts, item: post});
|
||||
});
|
||||
Comments.find({'inactive': {$ne : true}}).forEach(function (comment) {
|
||||
updatedComments += Telescope.updateScore({collection: Comments, item: comment});
|
||||
});
|
||||
// console.log("Updated "+updatedPosts+"/"+Posts.find().count()+" Posts")
|
||||
// console.log("Updated "+updatedComments+"/"+Comments.find().count()+" Comments")
|
||||
}, scoreInterval * 1000);
|
||||
// var updatedPosts = 0;
|
||||
// var updatedComments = 0;
|
||||
// // console.log('tick ('+scoreInterval+')');
|
||||
// Posts.find({'status': 2,'inactive': {$ne : true}}).forEach(function (post) { // only run scoring on approved posts
|
||||
// updatedPosts += Telescope.updateScore({collection: Posts, item: post});
|
||||
// });
|
||||
// Comments.find({'inactive': {$ne : true}}).forEach(function (comment) {
|
||||
// updatedComments += Telescope.updateScore({collection: Comments, item: comment});
|
||||
// });
|
||||
// // console.log("Updated "+updatedPosts+"/"+Posts.find().count()+" Posts")
|
||||
// // console.log("Updated "+updatedComments+"/"+Comments.find().count()+" Comments")
|
||||
// }, scoreInterval * 1000);
|
||||
|
||||
// inactive items get updated every hour
|
||||
Meteor.setInterval(function () {
|
||||
var updatedPosts = 0;
|
||||
var updatedComments = 0;
|
||||
Posts.find({'inactive': true}).forEach(function (post) {
|
||||
updatedPosts += Telescope.updateScore({collection: Posts, item: post});
|
||||
});
|
||||
Comments.find({'inactive': true}).forEach(function (comment) {
|
||||
updatedComments += Telescope.updateScore({collection: Comments, item: comment});
|
||||
});
|
||||
}, 3600 * 1000);
|
||||
// // inactive items get updated every hour
|
||||
// Meteor.setInterval(function () {
|
||||
// var updatedPosts = 0;
|
||||
// var updatedComments = 0;
|
||||
// Posts.find({'inactive': true}).forEach(function (post) {
|
||||
// updatedPosts += Telescope.updateScore({collection: Posts, item: post});
|
||||
// });
|
||||
// Comments.find({'inactive': true}).forEach(function (comment) {
|
||||
// updatedComments += Telescope.updateScore({collection: Comments, item: comment});
|
||||
// });
|
||||
// }, 3600 * 1000);
|
||||
|
||||
}
|
||||
});
|
||||
// }
|
||||
// });
|
||||
|
|
Loading…
Add table
Reference in a new issue