mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 01:51:40 -05:00
adding subscribe-to-posts package
This commit is contained in:
parent
0b3cfeabed
commit
cf01d01dbd
16 changed files with 590 additions and 3 deletions
|
@ -83,5 +83,6 @@ telescope-invites
|
|||
telescope-post-by-feed
|
||||
telescope-releases
|
||||
telescope-getting-started
|
||||
telescope-subscribe-to-posts
|
||||
|
||||
# Custom Packages
|
||||
|
|
|
@ -128,6 +128,7 @@ telescope-releases@0.1.0
|
|||
telescope-rss@0.0.0
|
||||
telescope-search@0.0.0
|
||||
telescope-singleday@0.1.0
|
||||
telescope-subscribe-to-posts@0.1.0
|
||||
telescope-tags@0.0.0
|
||||
telescope-theme-base@0.0.0
|
||||
telescope-theme-hubble@0.0.0
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
{{/each}}
|
||||
</ul>
|
||||
{{#each threadModules}}
|
||||
{{> UI.dynamic template=getTemplate}}
|
||||
{{> UI.dynamic template=getTemplate data=..}}
|
||||
{{/each}}
|
||||
</template>
|
||||
|
|
|
@ -21,7 +21,7 @@ privacyOptions = { // true means exposed
|
|||
'votes.downvotedComments': true,
|
||||
'votes.downvotedPosts': true,
|
||||
'votes.upvotedComments': true,
|
||||
'votes.upvotedPosts': true,
|
||||
'votes.upvotedPosts': true
|
||||
};
|
||||
|
||||
// minimum required properties to display avatars
|
||||
|
@ -37,4 +37,4 @@ avatarOptions = {
|
|||
'services.facebook.id': true,
|
||||
'services.twitter.screenName': true,
|
||||
'services.github.screenName': true, // Github is not really used, but there are some mentions to it in the code
|
||||
}
|
||||
}
|
||||
|
|
1
packages/telescope-subscribe-to-posts/.gitignore
vendored
Normal file
1
packages/telescope-subscribe-to-posts/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.build*
|
5
packages/telescope-subscribe-to-posts/i18n/en.i18n.json
Normal file
5
packages/telescope-subscribe-to-posts/i18n/en.i18n.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"subscribed_posts": "Subscribed Posts",
|
||||
"subscribe_to_thread": "Subscribe to comment thread",
|
||||
"unsubscribe_from_thread": "Unsubscribe from comment thread"
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<template name="postSubscribe">
|
||||
{{#if canSubscribe}}
|
||||
<div class="post-subscribe module grid-block">
|
||||
{{#if subscribed}}
|
||||
<a class="unsubscribe-link" href="#">
|
||||
<span>{{_ 'unsubscribe_from_thread'}}</span>
|
||||
</a>
|
||||
{{else}}
|
||||
<a class="subscribe-link" href="#">
|
||||
<span>{{_ 'subscribe_to_thread'}}</span>
|
||||
</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</template>
|
|
@ -0,0 +1,47 @@
|
|||
Template[getTemplate('postSubscribe')].helpers({
|
||||
canSubscribe: function() {
|
||||
// you cannot subscribe to your own posts
|
||||
return Meteor.userId() && this.userId !== Meteor.userId();
|
||||
},
|
||||
subscribed: function() {
|
||||
var user = Meteor.user();
|
||||
if (!user) return false;
|
||||
|
||||
return _.include(this.subscribers, user._id);
|
||||
}
|
||||
});
|
||||
|
||||
Template[getTemplate('postSubscribe')].events({
|
||||
'click .subscribe-link': function(e, instance) {
|
||||
e.preventDefault();
|
||||
if (this.userId === Meteor.userId())
|
||||
return;
|
||||
|
||||
var post = this;
|
||||
|
||||
if (!Meteor.user()) {
|
||||
Router.go('atSignIn');
|
||||
flashMessage(i18n.t("please_log_in_first"), "info");
|
||||
}
|
||||
|
||||
Meteor.call('subscribePost', post._id, function(error, result) {
|
||||
if (result)
|
||||
trackEvent("post subscribed", {'_id': post._id});
|
||||
});
|
||||
},
|
||||
|
||||
'click .unsubscribe-link': function(e, instance) {
|
||||
e.preventDefault();
|
||||
var post = this;
|
||||
|
||||
if (!Meteor.user()) {
|
||||
Router.go('atSignIn');
|
||||
flashMessage(i18n.t("please_log_in_first"), "info");
|
||||
}
|
||||
|
||||
Meteor.call('unsubscribePost', post._id, function(error, result) {
|
||||
if (result)
|
||||
trackEvent("post unsubscribed", {'_id': post._id});
|
||||
});
|
||||
}
|
||||
});
|
|
@ -0,0 +1,26 @@
|
|||
<template name="userSubscribedPosts">
|
||||
<div class="grid-small grid-block dialog admin">
|
||||
<h3>{{_ "subscribed_posts"}}</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Post</td>
|
||||
<td>Subscribed At</td>
|
||||
</tr>
|
||||
</thead>
|
||||
{{#each posts}}
|
||||
<tr>
|
||||
<td><a href="{{pathFor route='post_page' _id=_id}}">{{title}}</a></td>
|
||||
<td>{{formatDate subscribedAt "MM/DD/YYYY, HH:mm"}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{#if hasMorePosts}}
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<a class="subscribedposts-more more-button grid-module" href="#"><span>{{_ "load_more"}}</span></a>
|
||||
</td>
|
||||
</tr>
|
||||
{{/if}}
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,52 @@
|
|||
Template[getTemplate('userSubscribedPosts')].created = function () {
|
||||
var user = this.data,
|
||||
instance = this;
|
||||
|
||||
// initialize the terms and posts local reactive variables
|
||||
instance.terms = new ReactiveVar({
|
||||
view: 'userSubscribedPosts',
|
||||
userId: user._id,
|
||||
limit: 5
|
||||
});
|
||||
instance.posts = new ReactiveVar({});
|
||||
|
||||
// will re-run when the "terms" local reactive variable changes
|
||||
this.autorun(function () {
|
||||
|
||||
// get the new terms and generate new parameters from them
|
||||
var terms = instance.terms.get();
|
||||
var parameters = getPostsParameters(terms);
|
||||
|
||||
// subscribe to the userPosts publication
|
||||
instance.subscription = Meteor.subscribe('userSubscribedPosts', terms);
|
||||
|
||||
// update the instance's "posts" cursor
|
||||
instance.posts.set(Posts.find(parameters.find, parameters.options));
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
Template[getTemplate('userSubscribedPosts')].helpers({
|
||||
posts: function () {
|
||||
var user = this,
|
||||
posts = Template.instance().posts.get().fetch();
|
||||
posts = _.map(posts, function (post) {
|
||||
var item = _.findWhere(user.subscribedItems.Posts, {itemId: post._id});
|
||||
post.subscribedAt = item.subscribedAt;
|
||||
return post;
|
||||
});
|
||||
return posts;
|
||||
},
|
||||
hasMorePosts: function () {
|
||||
return Template.instance().posts.get().count() >= Template.instance().terms.get().limit;
|
||||
}
|
||||
});
|
||||
|
||||
Template[getTemplate('userSubscribedPosts')].events({
|
||||
'click .subscribedposts-more': function (e) {
|
||||
e.preventDefault();
|
||||
var terms = Template.instance().terms.get();
|
||||
terms.limit += 5;
|
||||
Template.instance().terms.set(terms)
|
||||
}
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
Meteor.publish('userSubscribedPosts', function(terms) {
|
||||
var parameters = getPostsParameters(terms);
|
||||
var posts = Posts.find(parameters.find, parameters.options);
|
||||
return posts;
|
||||
});
|
134
packages/telescope-subscribe-to-posts/lib/subscribe-to-posts.js
Normal file
134
packages/telescope-subscribe-to-posts/lib/subscribe-to-posts.js
Normal file
|
@ -0,0 +1,134 @@
|
|||
threadModules.push(
|
||||
{
|
||||
template: 'postSubscribe',
|
||||
order: 10
|
||||
}
|
||||
);
|
||||
|
||||
addToPostSchema.push(
|
||||
{
|
||||
propertyName: 'subscribers',
|
||||
propertySchema: {
|
||||
type: [String],
|
||||
optional: true,
|
||||
autoform: {
|
||||
omit: true
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
addToPostSchema.push(
|
||||
{
|
||||
propertyName: 'subscriberCount',
|
||||
propertySchema: {
|
||||
type: Number,
|
||||
optional: true,
|
||||
autoform: {
|
||||
omit: true
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
userProfileEdit.push(
|
||||
{
|
||||
template: 'userSubscribedPosts',
|
||||
order: 5
|
||||
}
|
||||
);
|
||||
|
||||
viewParameters.userSubscribedPosts = function (terms) {
|
||||
var user = Meteor.users.findOne(terms.userId),
|
||||
postsIds = [];
|
||||
|
||||
if (user.subscribedItems && user.subscribedItems.Posts)
|
||||
postsIds = _.pluck(user.subscribedItems.Posts, "itemId");
|
||||
|
||||
return {
|
||||
find: {_id: {$in: postsIds}},
|
||||
options: {limit: 5, sort: {postedAt: -1}}
|
||||
};
|
||||
}
|
||||
|
||||
var hasSubscribedItem = function (item, user) {
|
||||
return item.subscribers && item.subscribers.indexOf(user._id) != -1;
|
||||
};
|
||||
|
||||
var addSubscribedItem = function (userId, item, collection) {
|
||||
var field = 'subscribedItems.' + collection;
|
||||
var add = {};
|
||||
add[field] = item;
|
||||
Meteor.users.update({_id: userId}, {
|
||||
$addToSet: add
|
||||
});
|
||||
};
|
||||
|
||||
var removeSubscribedItem = function (userId, itemId, collection) {
|
||||
var field = 'subscribedItems.' + collection;
|
||||
var remove = {};
|
||||
remove[field] = {itemId: itemId};
|
||||
Meteor.users.update({_id: userId}, {
|
||||
$pull: remove
|
||||
});
|
||||
};
|
||||
|
||||
var subscribeItem = function (collection, itemId) {
|
||||
var user = Meteor.user(),
|
||||
item = collection.findOne(itemId),
|
||||
collectionName = collection._name.slice(0,1).toUpperCase() + collection._name.slice(1);
|
||||
|
||||
if (!user || !item || hasSubscribedItem(item, user))
|
||||
return false;
|
||||
|
||||
// author can't subscribe item
|
||||
if (item.userId && item.userId === user._id)
|
||||
return false
|
||||
|
||||
// Subscribe
|
||||
var result = collection.update({_id: itemId, subscribers: { $ne: user._id }}, {
|
||||
$addToSet: {subscribers: user._id},
|
||||
$inc: {subscriberCount: 1}
|
||||
});
|
||||
|
||||
if (result > 0) {
|
||||
// Add item to list of subscribed items
|
||||
var obj = {
|
||||
itemId: item._id,
|
||||
subscribedAt: new Date()
|
||||
};
|
||||
addSubscribedItem(user._id, obj, collectionName);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
var unsubscribeItem = function (collection, itemId) {
|
||||
var user = Meteor.user(),
|
||||
item = collection.findOne(itemId),
|
||||
collectionName = collection._name.slice(0,1).toUpperCase()+collection._name.slice(1);
|
||||
|
||||
if (!user || !item || !hasSubscribedItem(item, user))
|
||||
return false;
|
||||
|
||||
// Unsubscribe
|
||||
var result = collection.update({_id: itemId, subscribers: user._id }, {
|
||||
$pull: {subscribers: user._id},
|
||||
$inc: {subscriberCount: -1}
|
||||
});
|
||||
|
||||
if (result > 0) {
|
||||
// Remove item from list of subscribed items
|
||||
removeSubscribedItem(user._id, itemId, collectionName);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Meteor.methods({
|
||||
subscribePost: function(postId) {
|
||||
return subscribeItem.call(this, Posts, postId);
|
||||
},
|
||||
unsubscribePost: function(postId) {
|
||||
return unsubscribeItem.call(this, Posts, postId);
|
||||
}
|
||||
});
|
5
packages/telescope-subscribe-to-posts/package-tap.i18n
Normal file
5
packages/telescope-subscribe-to-posts/package-tap.i18n
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"translation_function_name": "__",
|
||||
"helper_name": "_",
|
||||
"namespace": "project"
|
||||
}
|
68
packages/telescope-subscribe-to-posts/package.js
Normal file
68
packages/telescope-subscribe-to-posts/package.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
Package.describe({
|
||||
summary: 'Subscribe to posts to be notified when they get new comments',
|
||||
version: '0.1.0',
|
||||
name: 'telescope-subscribe-to-posts'
|
||||
});
|
||||
|
||||
|
||||
Package.onUse(function (api) {
|
||||
|
||||
// --------------------------- 1. Meteor packages dependencies ---------------------------
|
||||
|
||||
// automatic (let the package specify where it's needed)
|
||||
|
||||
api.use([
|
||||
'tap:i18n',
|
||||
'iron:router',
|
||||
'telescope-base',
|
||||
'telescope-lib',
|
||||
'telescope-i18n',
|
||||
'fourseven:scss',
|
||||
'telescope-notifications'
|
||||
]);
|
||||
|
||||
// client
|
||||
|
||||
api.use([
|
||||
'jquery', // useful for DOM interactions
|
||||
'underscore', // JavaScript swiss army knife library
|
||||
'templating' // required for client-side templates
|
||||
], ['client']);
|
||||
|
||||
// ---------------------------------- 2. Files to include ----------------------------------
|
||||
|
||||
// i18n config (must come first)
|
||||
|
||||
api.add_files([
|
||||
'package-tap.i18n'
|
||||
], ['client', 'server']);
|
||||
|
||||
// both
|
||||
|
||||
api.add_files([
|
||||
'lib/subscribe-to-posts.js',
|
||||
], ['client', 'server']);
|
||||
|
||||
// client
|
||||
|
||||
api.add_files([
|
||||
'lib/client/templates/post_subscribe.html',
|
||||
'lib/client/templates/post_subscribe.js',
|
||||
'lib/client/templates/user_subscribed_posts.html',
|
||||
'lib/client/templates/user_subscribed_posts.js',
|
||||
'lib/client/stylesheets/subscribe-to-posts.scss'
|
||||
], ['client']);
|
||||
|
||||
// server
|
||||
|
||||
api.add_files([
|
||||
'lib/server/publications.js'
|
||||
], ['server']);
|
||||
|
||||
// i18n languages (must come last)
|
||||
|
||||
api.add_files([
|
||||
'i18n/en.i18n.json',
|
||||
], ['client', 'server']);
|
||||
|
||||
});
|
227
packages/telescope-subscribe-to-posts/versions.json
Normal file
227
packages/telescope-subscribe-to-posts/versions.json
Normal file
|
@ -0,0 +1,227 @@
|
|||
{
|
||||
"dependencies": [
|
||||
[
|
||||
"application-configuration",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"base64",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"binary-heap",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"blaze",
|
||||
"2.0.3"
|
||||
],
|
||||
[
|
||||
"blaze-tools",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"boilerplate-generator",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"callback-hook",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"check",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"cmather:handlebars-server",
|
||||
"2.0.0"
|
||||
],
|
||||
[
|
||||
"coffeescript",
|
||||
"1.0.4"
|
||||
],
|
||||
[
|
||||
"ddp",
|
||||
"1.0.11"
|
||||
],
|
||||
[
|
||||
"deps",
|
||||
"1.0.5"
|
||||
],
|
||||
[
|
||||
"ejson",
|
||||
"1.0.4"
|
||||
],
|
||||
[
|
||||
"follower-livedata",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"geojson-utils",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"handlebars",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"html-tools",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"htmljs",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"id-map",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"iron:controller",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"iron:core",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"iron:dynamic-template",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"iron:layout",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"iron:location",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"iron:middleware-stack",
|
||||
"1.0.0"
|
||||
],
|
||||
[
|
||||
"iron:router",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"iron:url",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"jquery",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"json",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"logging",
|
||||
"1.0.5"
|
||||
],
|
||||
[
|
||||
"meteor",
|
||||
"1.1.3"
|
||||
],
|
||||
[
|
||||
"minifiers",
|
||||
"1.1.2"
|
||||
],
|
||||
[
|
||||
"minimongo",
|
||||
"1.0.5"
|
||||
],
|
||||
[
|
||||
"mongo",
|
||||
"1.0.8"
|
||||
],
|
||||
[
|
||||
"observe-sequence",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"ordered-dict",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"random",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"reactive-dict",
|
||||
"1.0.4"
|
||||
],
|
||||
[
|
||||
"reactive-var",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"retry",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"routepolicy",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"session",
|
||||
"1.0.4"
|
||||
],
|
||||
[
|
||||
"spacebars",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"spacebars-compiler",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"tap:http-methods",
|
||||
"0.0.23"
|
||||
],
|
||||
[
|
||||
"tap:i18n",
|
||||
"1.2.1"
|
||||
],
|
||||
[
|
||||
"telescope-base",
|
||||
"0.0.0"
|
||||
],
|
||||
[
|
||||
"telescope-i18n",
|
||||
"0.0.0"
|
||||
],
|
||||
[
|
||||
"telescope-lib",
|
||||
"0.2.9"
|
||||
],
|
||||
[
|
||||
"templating",
|
||||
"1.0.9"
|
||||
],
|
||||
[
|
||||
"tracker",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"ui",
|
||||
"1.0.4"
|
||||
],
|
||||
[
|
||||
"underscore",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"webapp",
|
||||
"1.1.4"
|
||||
],
|
||||
[
|
||||
"webapp-hashing",
|
||||
"1.0.1"
|
||||
]
|
||||
],
|
||||
"pluginDependencies": [],
|
||||
"toolVersion": "meteor-tool@1.0.35",
|
||||
"format": "1.0"
|
||||
}
|
Loading…
Add table
Reference in a new issue