mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 01:51:40 -05:00
Making notifications into their own package
This commit is contained in:
parent
075f861e8d
commit
2a911217e9
24 changed files with 461 additions and 72 deletions
|
@ -66,3 +66,5 @@ matb33:collection-hooks
|
|||
djedi:sanitize-html
|
||||
rajit:bootstrap3-datepicker
|
||||
telescope-update-prompt
|
||||
telescope-notifications
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ telescope-lib@0.2.9
|
|||
telescope-module-embedly@0.2.9
|
||||
telescope-module-share@0.0.0
|
||||
telescope-newsletter@0.1.0
|
||||
telescope-notifications@0.1.0
|
||||
telescope-rss@0.0.0
|
||||
telescope-search@0.0.0
|
||||
telescope-tags@0.0.0
|
||||
|
|
|
@ -28,16 +28,6 @@ adminNav = adminNav.concat([
|
|||
}
|
||||
]);
|
||||
|
||||
// Notifications - only load if user is logged in
|
||||
// Not mandatory, because server won't publish anything even if we try to load.
|
||||
// Remember about Deps.autorun - user can log in and log out several times
|
||||
Deps.autorun(function() {
|
||||
// userId() can be changed before user(), because loading profile takes time
|
||||
if(Meteor.userId()) {
|
||||
Meteor.subscribe('notifications');
|
||||
}
|
||||
});
|
||||
|
||||
// Sort postModules array position using modulePositions as index
|
||||
postModules = _.sortBy(postModules, function(module){return _.indexOf(modulePositions, module.position)});
|
||||
|
||||
|
|
|
@ -137,6 +137,16 @@ Meteor.methods({
|
|||
if(parentCommentId)
|
||||
comment.parentCommentId = parentCommentId;
|
||||
|
||||
|
||||
// ------------------------------ Callbacks ------------------------------ //
|
||||
|
||||
// run all post submit server callbacks on comment object successively
|
||||
comment = commentSubmitMethodCallbacks.reduce(function(result, currentFunction) {
|
||||
return currentFunction(result);
|
||||
}, comment);
|
||||
|
||||
// -------------------------------- Insert ------------------------------- //
|
||||
|
||||
var newCommentId=Comments.insert(comment);
|
||||
|
||||
// increment comment count
|
||||
|
@ -155,36 +165,6 @@ Meteor.methods({
|
|||
|
||||
Meteor.call('upvoteComment', comment);
|
||||
|
||||
var notificationProperties = {
|
||||
comment: _.pick(comment, '_id', 'userId', 'author', 'body'),
|
||||
post: _.pick(post, '_id', 'title', 'url')
|
||||
};
|
||||
|
||||
if(!this.isSimulation){
|
||||
if(parentCommentId){
|
||||
// child comment
|
||||
var parentComment = Comments.findOne(parentCommentId);
|
||||
var parentUser = Meteor.users.findOne(parentComment.userId);
|
||||
|
||||
notificationProperties.parentComment = _.pick(parentComment, '_id', 'userId', 'author');
|
||||
|
||||
// reply notification
|
||||
// do not notify users of their own actions (i.e. they're replying to themselves)
|
||||
if(parentUser._id != user._id)
|
||||
createNotification('newReply', notificationProperties, parentUser);
|
||||
|
||||
// comment notification
|
||||
// if the original poster is different from the author of the parent comment, notify them too
|
||||
if(postUser._id != user._id && parentComment.userId != post.userId)
|
||||
createNotification('newComment', notificationProperties, postUser);
|
||||
|
||||
}else{
|
||||
// root comment
|
||||
// don't notify users of their own comments
|
||||
if(postUser._id != user._id)
|
||||
createNotification('newComment', notificationProperties, postUser);
|
||||
}
|
||||
}
|
||||
return comment;
|
||||
},
|
||||
removeComment: function(commentId){
|
||||
|
|
|
@ -256,7 +256,7 @@ Meteor.methods({
|
|||
// ------------------------------ Callbacks ------------------------------ //
|
||||
|
||||
// run all post submit server callbacks on post object successively
|
||||
post = postSubmitServerCallbacks.reduce(function(result, currentFunction) {
|
||||
post = postSubmitMethodCallbacks.reduce(function(result, currentFunction) {
|
||||
return currentFunction(result);
|
||||
}, post);
|
||||
|
||||
|
@ -274,14 +274,6 @@ Meteor.methods({
|
|||
|
||||
Meteor.call('upvotePost', post, postAuthor);
|
||||
|
||||
// notify users of new posts
|
||||
if(Meteor.isServer && !!getSetting('emailNotifications', false)){
|
||||
// we don't want emails to hold up the post submission, so we make the whole thing async with setTimeout
|
||||
Meteor.setTimeout(function () {
|
||||
newPostNotification(post, [userId])
|
||||
}, 1);
|
||||
}
|
||||
|
||||
return post;
|
||||
},
|
||||
setPostedAt: function(post, customPostedAt){
|
||||
|
|
103
packages/telescope-lib/lib/permissions.js
Normal file
103
packages/telescope-lib/lib/permissions.js
Normal file
|
@ -0,0 +1,103 @@
|
|||
can = {};
|
||||
|
||||
// Permissions
|
||||
|
||||
// user: Defaults to Meteor.user()
|
||||
// returnError: If there's an error, should we return what the problem is?
|
||||
//
|
||||
// return true if all is well, false || an error string if not
|
||||
can.view = function(user){
|
||||
// console.log('canView', 'user:', user, 'returnError:', returnError, getSetting('requireViewInvite'));
|
||||
|
||||
if(getSetting('requireViewInvite', false)){
|
||||
|
||||
if(Meteor.isClient){
|
||||
// on client only, default to the current user
|
||||
var user=(typeof user === 'undefined') ? Meteor.user() : user;
|
||||
}
|
||||
|
||||
if(user && (isAdmin(user) || isInvited(user))){
|
||||
// if logged in AND either admin or invited
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
};
|
||||
can.viewById = function(userId, returnError){
|
||||
// if an invite is required to view, run permission check, else return true
|
||||
if(getSetting('requireViewInvite', false)){
|
||||
// if user is logged in, then run canView, else return false
|
||||
return userId ? canView(Meteor.users.findOne(userId), returnError) : false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
can.post = function(user, returnError){
|
||||
var user=(typeof user === 'undefined') ? Meteor.user() : user;
|
||||
|
||||
// console.log('canPost', user, action, getSetting('requirePostInvite'));
|
||||
|
||||
if(!user){
|
||||
return returnError ? "no_account" : false;
|
||||
} else if (isAdmin(user)) {
|
||||
return true;
|
||||
} else if (getSetting('requirePostInvite')) {
|
||||
if (user.isInvited) {
|
||||
return true;
|
||||
} else {
|
||||
return returnError ? "no_invite" : false;
|
||||
}
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
can.postById = function(userId, returnError){
|
||||
var user = Meteor.users.findOne(userId);
|
||||
return canPost(user, returnError);
|
||||
};
|
||||
can.comment = function(user, returnError){
|
||||
return canPost(user, returnError);
|
||||
};
|
||||
can.commentById = function(userId, returnError){
|
||||
var user = Meteor.users.findOne(userId);
|
||||
return canComment(user, returnError);
|
||||
};
|
||||
can.upvote = function(user, collection, returnError){
|
||||
return canPost(user, returnError);
|
||||
};
|
||||
can.upvoteById = function(userId, returnError){
|
||||
var user = Meteor.users.findOne(userId);
|
||||
return canUpvote(user, returnError);
|
||||
};
|
||||
can.downvote = function(user, collection, returnError){
|
||||
return canPost(user, returnError);
|
||||
};
|
||||
can.downvoteById = function(userId, returnError){
|
||||
var user = Meteor.users.findOne(userId);
|
||||
return canDownvote(user, returnError);
|
||||
};
|
||||
can.edit = function(user, item, returnError){
|
||||
var user=(typeof user === 'undefined') ? Meteor.user() : user;
|
||||
|
||||
if (!user || !item){
|
||||
return returnError ? "no_rights" : false;
|
||||
} else if (isAdmin(user)) {
|
||||
return true;
|
||||
} else if (user._id!==item.userId) {
|
||||
return returnError ? "no_rights" : false;
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
can.editById = function(userId, item){
|
||||
var user = Meteor.users.findOne(userId);
|
||||
return canEdit(user, item);
|
||||
};
|
||||
can.currentUserEdit = function(item) {
|
||||
return canEdit(Meteor.user(), item);
|
||||
};
|
||||
can.invite = function(user){
|
||||
return isInvited(user) || isAdmin(user);
|
||||
};
|
|
@ -14,7 +14,12 @@ Package.onUse(function (api) {
|
|||
'jquery'
|
||||
], 'client');
|
||||
|
||||
api.add_files(['lib/lib.js', 'lib/deep_extend.js', 'lib/autolink.js'], ['client', 'server']);
|
||||
api.add_files([
|
||||
'lib/lib.js',
|
||||
'lib/deep_extend.js',
|
||||
'lib/autolink.js',
|
||||
'lib/permissions.js'
|
||||
], ['client', 'server']);
|
||||
|
||||
api.add_files(['lib/client/jquery.exists.js'], ['client']);
|
||||
|
||||
|
@ -26,6 +31,7 @@ Package.onUse(function (api) {
|
|||
'getSetting',
|
||||
'getThemeSetting',
|
||||
'getSiteUrl',
|
||||
'trimWords'
|
||||
'trimWords',
|
||||
'can'
|
||||
]);
|
||||
});
|
|
@ -62,4 +62,4 @@ var extendPost = function (post) {
|
|||
return post;
|
||||
}
|
||||
|
||||
postSubmitServerCallbacks.push(extendPost);
|
||||
postSubmitMethodCallbacks.push(extendPost);
|
1
packages/telescope-notifications/.gitignore
vendored
Normal file
1
packages/telescope-notifications/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.build*
|
|
@ -0,0 +1,9 @@
|
|||
// Notifications - only load if user is logged in
|
||||
// Not mandatory, because server won't publish anything even if we try to load.
|
||||
// Remember about Deps.autorun - user can log in and log out several times
|
||||
Tracker.autorun(function() {
|
||||
// userId() can be changed before user(), because loading profile takes time
|
||||
if(Meteor.userId()) {
|
||||
Meteor.subscribe('notifications');
|
||||
}
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
<template name="notificationItem">
|
||||
<li class="notification-item {{#if read}}read{{/if}}">
|
||||
<span class="notification-timestamp">{{nice_time}}</span>
|
||||
<span class="notification-timestamp">{{niceTime}}</span>
|
||||
<div class="notification-html">
|
||||
{{{notificationHTML}}}
|
||||
</div>
|
|
@ -1,5 +1,5 @@
|
|||
Template[getTemplate('notificationItem')].helpers({
|
||||
nice_time: function(){
|
||||
niceTime: function(){
|
||||
return moment(this.timestamp).fromNow();
|
||||
},
|
||||
properties: function(){
|
|
@ -1,4 +1,4 @@
|
|||
<template name="notification_new_comment">
|
||||
<template name="notificationNewComment">
|
||||
<p>
|
||||
<a href="{{profileUrl}}">{{author}}</a>
|
||||
left a new comment on
|
|
@ -1,4 +1,4 @@
|
|||
<template name="notification_new_reply">
|
||||
<template name="notificationNewReply">
|
||||
<p>
|
||||
<a href="{{profileUrl}}">{{author}}</a>
|
||||
has replied to your comment on
|
|
@ -21,12 +21,12 @@ Notifications = new Meteor.Collection('notifications');
|
|||
// });
|
||||
|
||||
Notifications.allow({
|
||||
insert: function(userId, doc){
|
||||
// new notifications can only be created via a Meteor method
|
||||
return false;
|
||||
}
|
||||
, update: canEditById
|
||||
, remove: canEditById
|
||||
insert: function(userId, doc){
|
||||
// new notifications can only be created via a Meteor method
|
||||
return false;
|
||||
},
|
||||
update: can.editById,
|
||||
remove: can.editById
|
||||
});
|
||||
|
||||
createNotification = function(event, properties, userToNotify) {
|
||||
|
@ -67,11 +67,11 @@ buildSiteNotification = function (notification) {
|
|||
|
||||
switch(event){
|
||||
case 'newReply':
|
||||
template = 'notification_new_reply';
|
||||
template = 'notificationNewReply';
|
||||
break;
|
||||
|
||||
case 'newComment':
|
||||
template = 'notification_new_comment';
|
||||
template = 'notificationNewComment';
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -97,4 +97,53 @@ Meteor.methods({
|
|||
{multi: true}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// add new post notification callback on post submit
|
||||
postSubmitMethodCallbacks.push(function (post) {
|
||||
if(Meteor.isServer && !!getSetting('emailNotifications', false)){
|
||||
// we don't want emails to hold up the post submission, so we make the whole thing async with setTimeout
|
||||
Meteor.setTimeout(function () {
|
||||
newPostNotification(post, [post.userId])
|
||||
}, 1);
|
||||
}
|
||||
return post;
|
||||
});
|
||||
|
||||
// add new comment notification callback on comment submit
|
||||
commentSubmitMethodCallbacks.push(function (comment) {
|
||||
if(Meteor.isServer){
|
||||
|
||||
var post = Posts.findOne(comment.postId);
|
||||
var parentCommentId = comment.parentCommentId;
|
||||
|
||||
var notificationProperties = {
|
||||
comment: _.pick(comment, '_id', 'userId', 'author', 'body'),
|
||||
post: _.pick(post, '_id', 'title', 'url')
|
||||
};
|
||||
|
||||
if(parentCommentId){
|
||||
// child comment
|
||||
var parentComment = Comments.findOne(parentCommentId);
|
||||
var parentUser = Meteor.users.findOne(parentComment.userId);
|
||||
|
||||
notificationProperties.parentComment = _.pick(parentComment, '_id', 'userId', 'author');
|
||||
|
||||
// reply notification
|
||||
// do not notify users of their own actions (i.e. they're replying to themselves)
|
||||
if(parentUser._id != user._id)
|
||||
createNotification('newReply', notificationProperties, parentUser);
|
||||
|
||||
// comment notification
|
||||
// if the original poster is different from the author of the parent comment, notify them too
|
||||
if(postUser._id != user._id && parentComment.userId != post.userId)
|
||||
createNotification('newComment', notificationProperties, postUser);
|
||||
|
||||
}else{
|
||||
// root comment
|
||||
// don't notify users of their own comments
|
||||
if(postUser._id != user._id)
|
||||
createNotification('newComment', notificationProperties, postUser);
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
Meteor.publish('notifications', function() {
|
||||
// only publish notifications belonging to the current user
|
||||
if(canViewById(this.userId)){
|
||||
return Notifications.find({userId:this.userId});
|
||||
}
|
||||
return [];
|
||||
});
|
58
packages/telescope-notifications/package.js
Normal file
58
packages/telescope-notifications/package.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
Package.describe({
|
||||
summary: "Telescope notifications package",
|
||||
version: '0.1.0',
|
||||
name: "telescope-notifications"
|
||||
});
|
||||
|
||||
Package.onUse(function (api) {
|
||||
|
||||
api.use([
|
||||
'telescope-lib',
|
||||
'telescope-base',
|
||||
'aldeed:simple-schema'
|
||||
], ['client', 'server']);
|
||||
|
||||
api.use([
|
||||
'jquery',
|
||||
'underscore',
|
||||
'iron:router',
|
||||
'templating',
|
||||
'tracker'
|
||||
], 'client');
|
||||
|
||||
api.use([
|
||||
'cmather:handlebars-server'
|
||||
], ['server']);
|
||||
|
||||
api.add_files([
|
||||
'lib/notifications.js',
|
||||
], ['client', 'server']);
|
||||
|
||||
api.add_files([
|
||||
'lib/client/notifications-client.js',
|
||||
'lib/client/templates/notification_item.html',
|
||||
'lib/client/templates/notification_item.js',
|
||||
'lib/client/templates/notification_new_comment.html',
|
||||
'lib/client/templates/notification_new_reply.html',
|
||||
'lib/client/templates/notifications_menu.html',
|
||||
'lib/client/templates/notifications_menu.js',
|
||||
'lib/client/templates/unsubscribe.html',
|
||||
'lib/client/templates/unsubscribe.js',
|
||||
], ['client']);
|
||||
|
||||
api.add_files([
|
||||
'lib/server/notifications-server.js',
|
||||
'lib/server/publication.js'
|
||||
], ['server']);
|
||||
|
||||
api.export([
|
||||
'createNotification',
|
||||
'buildSiteNotification',
|
||||
'newPostNotification',
|
||||
'buildEmailNotification',
|
||||
'getUnsubscribeLink',
|
||||
'postSubmitMethodCallbacks'
|
||||
]);
|
||||
});
|
||||
|
||||
// TODO: once user profile edit form is generated dynamically, add notification options from this package as well.
|
199
packages/telescope-notifications/versions.json
Normal file
199
packages/telescope-notifications/versions.json
Normal file
|
@ -0,0 +1,199 @@
|
|||
{
|
||||
"dependencies": [
|
||||
[
|
||||
"aldeed:simple-schema",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"application-configuration",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"base64",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"binary-heap",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"blaze",
|
||||
"2.0.0"
|
||||
],
|
||||
[
|
||||
"blaze-tools",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"boilerplate-generator",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"callback-hook",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"check",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"cmather:handlebars-server",
|
||||
"0.2.0"
|
||||
],
|
||||
[
|
||||
"ddp",
|
||||
"1.0.8"
|
||||
],
|
||||
[
|
||||
"deps",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"ejson",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"follower-livedata",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"geojson-utils",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"handlebars",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"html-tools",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"htmljs",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"id-map",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"iron:core",
|
||||
"0.3.4"
|
||||
],
|
||||
[
|
||||
"iron:dynamic-template",
|
||||
"0.4.1"
|
||||
],
|
||||
[
|
||||
"iron:layout",
|
||||
"0.4.1"
|
||||
],
|
||||
[
|
||||
"iron:router",
|
||||
"0.9.3"
|
||||
],
|
||||
[
|
||||
"jquery",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"json",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"logging",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"meteor",
|
||||
"1.1.0"
|
||||
],
|
||||
[
|
||||
"minifiers",
|
||||
"1.1.0"
|
||||
],
|
||||
[
|
||||
"minimongo",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"mongo",
|
||||
"1.0.5"
|
||||
],
|
||||
[
|
||||
"observe-sequence",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"ordered-dict",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"random",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"reactive-dict",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"reactive-var",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"retry",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"routepolicy",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"spacebars",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"spacebars-compiler",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"telescope-base",
|
||||
"0.0.0"
|
||||
],
|
||||
[
|
||||
"telescope-i18n",
|
||||
"0.0.0"
|
||||
],
|
||||
[
|
||||
"telescope-lib",
|
||||
"0.2.9"
|
||||
],
|
||||
[
|
||||
"templating",
|
||||
"1.0.6"
|
||||
],
|
||||
[
|
||||
"tracker",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"ui",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"underscore",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"webapp",
|
||||
"1.1.1"
|
||||
],
|
||||
[
|
||||
"webapp-hashing",
|
||||
"1.0.0"
|
||||
]
|
||||
],
|
||||
"pluginDependencies": [],
|
||||
"toolVersion": "meteor-tool@1.0.30",
|
||||
"format": "1.0"
|
||||
}
|
|
@ -11,14 +11,6 @@ Meteor.publish('settings', function() {
|
|||
return Settings.find({}, options);
|
||||
});
|
||||
|
||||
Meteor.publish('notifications', function() {
|
||||
// only publish notifications belonging to the current user
|
||||
if(canViewById(this.userId)){
|
||||
return Notifications.find({userId:this.userId});
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
Meteor.publish('invites', function(){
|
||||
if(canViewById(this.userId)){
|
||||
return Invites.find({invitingUserId:this.userId});
|
||||
|
|
Loading…
Add table
Reference in a new issue