mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 01:51:40 -05:00
Auto post via RSS urls. Fixes #453
This commit is contained in:
parent
512cc7707d
commit
c5e813909a
19 changed files with 614 additions and 0 deletions
|
@ -78,4 +78,5 @@ telescope-invites
|
|||
useraccounts:unstyled
|
||||
telescope-datetimepicker
|
||||
tsega:bootstrap3-datetimepicker@3.1.3_1
|
||||
telescope-post-by-rss
|
||||
|
||||
|
|
|
@ -123,6 +123,7 @@ telescope-lib@0.2.9
|
|||
telescope-module-share@0.0.0
|
||||
telescope-newsletter@0.1.0
|
||||
telescope-notifications@0.1.0
|
||||
telescope-post-by-rss@0.0.1
|
||||
telescope-rss@0.0.0
|
||||
telescope-search@0.0.0
|
||||
telescope-singleday@0.1.0
|
||||
|
|
1
packages/telescope-post-by-rss/.gitignore
vendored
Normal file
1
packages/telescope-post-by-rss/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
.build*
|
1
packages/telescope-post-by-rss/.npm/package/.gitignore
vendored
Normal file
1
packages/telescope-post-by-rss/.npm/package/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
node_modules
|
7
packages/telescope-post-by-rss/.npm/package/README
Normal file
7
packages/telescope-post-by-rss/.npm/package/README
Normal file
|
@ -0,0 +1,7 @@
|
|||
This directory and the files immediately inside it are automatically generated
|
||||
when you change this package's NPM dependencies. Commit the files in this
|
||||
directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
|
||||
so that others run the same versions of sub-dependencies.
|
||||
|
||||
You should NOT check in the node_modules directory that Meteor automatically
|
||||
creates; if you are using git, the .gitignore file tells git to ignore it.
|
63
packages/telescope-post-by-rss/.npm/package/npm-shrinkwrap.json
generated
Normal file
63
packages/telescope-post-by-rss/.npm/package/npm-shrinkwrap.json
generated
Normal file
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"html-to-text": {
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"htmlparser": {
|
||||
"version": "1.7.7"
|
||||
},
|
||||
"underscore": {
|
||||
"version": "1.7.0"
|
||||
},
|
||||
"underscore.string": {
|
||||
"version": "2.4.0"
|
||||
},
|
||||
"optimist": {
|
||||
"version": "0.6.1",
|
||||
"dependencies": {
|
||||
"wordwrap": {
|
||||
"version": "0.0.2"
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.10"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.8.2",
|
||||
"dependencies": {
|
||||
"domhandler": {
|
||||
"version": "2.3.0"
|
||||
},
|
||||
"domutils": {
|
||||
"version": "1.5.0"
|
||||
},
|
||||
"domelementtype": {
|
||||
"version": "1.1.3"
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "1.1.13",
|
||||
"dependencies": {
|
||||
"core-util-is": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"isarray": {
|
||||
"version": "0.0.1"
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "0.10.31"
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"entities": {
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
packages/telescope-post-by-rss/i18n/en.i18n.json
Normal file
3
packages/telescope-post-by-rss/i18n/en.i18n.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"rss_url_is_already_exists": "Url is already exists."
|
||||
}
|
20
packages/telescope-post-by-rss/lib/client/routes.js
Normal file
20
packages/telescope-post-by-rss/lib/client/routes.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
adminNav.push({
|
||||
route: 'rssUrls',
|
||||
label: 'RSS Urls'
|
||||
});
|
||||
|
||||
Meteor.startup(function () {
|
||||
|
||||
Router.onBeforeAction(Router._filters.isAdmin, {only: ['rssUrls']});
|
||||
|
||||
// RSS Urls Admin
|
||||
|
||||
Router.route('/rss-urls', {
|
||||
name: 'rssUrls',
|
||||
waitOn: function() {
|
||||
return Meteor.subscribe('rssUrls');
|
||||
},
|
||||
template: getTemplate('rssUrls')
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
<template name="rssUrlItem">
|
||||
<li>
|
||||
<span>Url: {{url}}</span>
|
||||
<a class="delete-url" href="#">Delete</a>
|
||||
</li>
|
||||
</template>
|
|
@ -0,0 +1,10 @@
|
|||
Meteor.startup(function () {
|
||||
Template[getTemplate('rssUrlItem')].events({
|
||||
'click .delete-url': function(e, instance){
|
||||
e.preventDefault();
|
||||
|
||||
if (confirm(i18n.t('are_you_sure')))
|
||||
RssUrls.remove(instance.data._id);
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
<template name="rssUrls">
|
||||
<div class="grid-small grid-module dialog admin">
|
||||
<h2>RSS Urls</h2>
|
||||
|
||||
<form class="form-block">
|
||||
<h3>Add new RSS Url</h3>
|
||||
<div class="control-group">
|
||||
<label>Url</label>
|
||||
<div class="controls"><input id="url" type="text" value="" /></div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<input type="submit" class="button" value="Submit" />
|
||||
</div>
|
||||
</form>
|
||||
<ul>
|
||||
{{#each rssUrls}}
|
||||
{{> UI.dynamic template=rssUrlItem}}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,28 @@
|
|||
Meteor.startup(function () {
|
||||
Template[getTemplate('rssUrls')].helpers({
|
||||
rssUrls: function(){
|
||||
return RssUrls.find({}, {sort: {url: 1}});
|
||||
},
|
||||
rssUrlItem: function () {
|
||||
return getTemplate('rssUrlItem');
|
||||
}
|
||||
});
|
||||
|
||||
Template[getTemplate('rssUrls')].events({
|
||||
'click input[type=submit]': function(e){
|
||||
e.preventDefault();
|
||||
|
||||
var url = $('#url').val();
|
||||
|
||||
Meteor.call('insertRssUrl', {url: url}, function(error, result) {
|
||||
if(error){
|
||||
console.log(error);
|
||||
flashMessage(error.reason, "error");
|
||||
clearSeenMessages();
|
||||
}else{
|
||||
$('#url').val('');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
35
packages/telescope-post-by-rss/lib/rssUrls.js
Normal file
35
packages/telescope-post-by-rss/lib/rssUrls.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
// rssUrl schema
|
||||
rssUrlSchema = new SimpleSchema({
|
||||
_id: {
|
||||
type: String,
|
||||
optional: true
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Url
|
||||
},
|
||||
});
|
||||
|
||||
RssUrls = new Meteor.Collection("rss_urls", {
|
||||
schema: rssUrlSchema
|
||||
});
|
||||
|
||||
Meteor.startup(function () {
|
||||
RssUrls.allow({
|
||||
remove: isAdminById
|
||||
});
|
||||
|
||||
Meteor.methods({
|
||||
insertRssUrl: function(rssUrl){
|
||||
check(rssUrl, rssUrlSchema);
|
||||
|
||||
if (RssUrls.findOne({url: rssUrl.url}))
|
||||
throw new Meteor.Error('already-exists', i18n.t('rss_url_is_already_exists'));
|
||||
|
||||
if (!Meteor.user() || !isAdmin(Meteor.user()))
|
||||
throw new Meteor.Error('login-required', i18n.t('you_need_to_login_and_be_an_admin_to_add_a_new_rss_url'));
|
||||
|
||||
return RssUrls.insert(rssUrl);
|
||||
}
|
||||
});
|
||||
});
|
13
packages/telescope-post-by-rss/lib/server/cron.js
Normal file
13
packages/telescope-post-by-rss/lib/server/cron.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
SyncedCron.add({
|
||||
name: 'Post by RSS url',
|
||||
schedule: function(parser) {
|
||||
return parser.text('every 10 mins');
|
||||
},
|
||||
job: function() {
|
||||
fetchUrls();
|
||||
}
|
||||
});
|
||||
|
||||
Meteor.startup(function() {
|
||||
SyncedCron.start();
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
Meteor.publish('rssUrls', function() {
|
||||
if(isAdminById(this.userId)){
|
||||
return RssUrls.find();
|
||||
}
|
||||
return [];
|
||||
});
|
98
packages/telescope-post-by-rss/lib/server/utils.js
Normal file
98
packages/telescope-post-by-rss/lib/server/utils.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
var htmlParser = Npm.require('htmlparser2');
|
||||
var htmlToText = Npm.require('html-to-text');
|
||||
|
||||
var getFirstAdminUser = function() {
|
||||
return Meteor.users.findOne({isAdmin: true}, {sort: {createdAt: 1}});
|
||||
}
|
||||
|
||||
var insertPost = function(feedItem) {
|
||||
var post = {
|
||||
title: feedItem.title,
|
||||
body: htmlToText.fromString(feedItem.description),
|
||||
url: feedItem.link
|
||||
};
|
||||
|
||||
// check that there are no posts with the same URL
|
||||
if (!!post.url) {
|
||||
var sixMonthsAgo = moment().subtract(6, 'months').toDate();
|
||||
var postWithSameLink = Posts.findOne({url: post.url, postedAt: {$gte: sixMonthsAgo}});
|
||||
|
||||
if (typeof postWithSameLink !== 'undefined') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var title = cleanUp(post.title),
|
||||
body = post.body,
|
||||
user = getFirstAdminUser(),
|
||||
postId = '';
|
||||
|
||||
// ------------------------------ Checks ------------------------------ //
|
||||
|
||||
// check that user provided a title
|
||||
if(!post.title)
|
||||
post.title = 'Untitled';
|
||||
|
||||
// ------------------------------ Properties ------------------------------ //
|
||||
|
||||
// Basic Properties
|
||||
properties = {
|
||||
title: title,
|
||||
body: body,
|
||||
userId: user._id,
|
||||
author: getDisplayNameById(user._id),
|
||||
upvotes: 0,
|
||||
downvotes: 0,
|
||||
commentCount: 0,
|
||||
clickCount: 0,
|
||||
viewCount: 0,
|
||||
baseScore: 0,
|
||||
score: 0,
|
||||
status: 2,
|
||||
inactive: false,
|
||||
createdAt: new Date(),
|
||||
postedAt: new Date()
|
||||
};
|
||||
|
||||
post = _.extend(post, properties);
|
||||
|
||||
// ------------------------------ Insert ------------------------------ //
|
||||
|
||||
post._id = Posts.insert(post);
|
||||
|
||||
// ------------------------------ After Insert ------------------------------ //
|
||||
|
||||
// increment posts count
|
||||
Meteor.users.update({_id: user._id}, {$inc: {postCount: 1}});
|
||||
|
||||
Meteor.call('upvotePost', post, user);
|
||||
|
||||
return post;
|
||||
};
|
||||
|
||||
var handleFeed = function(error, feed) {
|
||||
if (error) return;
|
||||
|
||||
feed.items.forEach(function(item, index, array) {
|
||||
insertPost(item);
|
||||
});
|
||||
};
|
||||
|
||||
fetchUrls = function() {
|
||||
var content;
|
||||
|
||||
RssUrls.find().forEach(function(rssUrl) {
|
||||
try {
|
||||
content = HTTP.get(rssUrl.url).content;
|
||||
} catch (e) {
|
||||
// just go to next url
|
||||
return true;
|
||||
}
|
||||
|
||||
var feedHandler = new htmlParser.FeedHandler(handleFeed);
|
||||
|
||||
var parser = new htmlParser.Parser(feedHandler, {xmlMode: true});
|
||||
parser.write(content);
|
||||
parser.end()
|
||||
});
|
||||
}
|
5
packages/telescope-post-by-rss/package-tap.i18n
Normal file
5
packages/telescope-post-by-rss/package-tap.i18n
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"translation_function_name": "__",
|
||||
"helper_name": "_",
|
||||
"namespace": "project"
|
||||
}
|
56
packages/telescope-post-by-rss/package.js
Normal file
56
packages/telescope-post-by-rss/package.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
Package.describe({
|
||||
summary: 'Auto post via RSS to Telescope',
|
||||
version: '0.0.1',
|
||||
name: 'telescope-post-by-rss'
|
||||
});
|
||||
|
||||
Npm.depends({
|
||||
'htmlparser2': '3.8.2',
|
||||
'html-to-text': '0.1.0',
|
||||
});
|
||||
|
||||
Package.onUse(function(api) {
|
||||
|
||||
api.use([
|
||||
'telescope-base',
|
||||
'aldeed:simple-schema',
|
||||
'tap:i18n'
|
||||
], ['client', 'server']);
|
||||
|
||||
api.use([
|
||||
'iron:router',
|
||||
'templating'
|
||||
], 'client');
|
||||
|
||||
api.use([
|
||||
'http',
|
||||
'mrt:moment',
|
||||
'percolatestudio:synced-cron'
|
||||
], 'server');
|
||||
|
||||
api.add_files([
|
||||
'lib/rssUrls.js'
|
||||
], ['client', 'server']);
|
||||
|
||||
api.add_files([
|
||||
'lib/client/routes.js',
|
||||
'lib/client/templates/rss_urls.js',
|
||||
'lib/client/templates/rss_urls.html',
|
||||
'lib/client/templates/rss_url_item.js',
|
||||
'lib/client/templates/rss_url_item.html',
|
||||
], 'client');
|
||||
|
||||
api.add_files([
|
||||
'lib/server/utils.js',
|
||||
'lib/server/cron.js',
|
||||
'lib/server/publications.js'
|
||||
], ['server']);
|
||||
|
||||
api.add_files([
|
||||
"i18n/en.i18n.json"
|
||||
], ["client", "server"]);
|
||||
});
|
||||
|
||||
Package.onTest(function(api) {
|
||||
api.use('tinytest');
|
||||
});
|
239
packages/telescope-post-by-rss/versions.json
Normal file
239
packages/telescope-post-by-rss/versions.json
Normal file
|
@ -0,0 +1,239 @@
|
|||
{
|
||||
"dependencies": [
|
||||
[
|
||||
"aldeed:simple-schema",
|
||||
"1.1.0"
|
||||
],
|
||||
[
|
||||
"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"
|
||||
],
|
||||
[
|
||||
"coffeescript",
|
||||
"1.0.4"
|
||||
],
|
||||
[
|
||||
"ddp",
|
||||
"1.0.12"
|
||||
],
|
||||
[
|
||||
"deps",
|
||||
"1.0.5"
|
||||
],
|
||||
[
|
||||
"ejson",
|
||||
"1.0.4"
|
||||
],
|
||||
[
|
||||
"follower-livedata",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"geojson-utils",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"html-tools",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"htmljs",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"http",
|
||||
"1.0.8"
|
||||
],
|
||||
[
|
||||
"id-map",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"iron:controller",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"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.3"
|
||||
],
|
||||
[
|
||||
"iron:router",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"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.9"
|
||||
],
|
||||
[
|
||||
"mrt:moment",
|
||||
"2.8.1"
|
||||
],
|
||||
[
|
||||
"observe-sequence",
|
||||
"1.0.3"
|
||||
],
|
||||
[
|
||||
"ordered-dict",
|
||||
"1.0.1"
|
||||
],
|
||||
[
|
||||
"percolatestudio:synced-cron",
|
||||
"1.1.0"
|
||||
],
|
||||
[
|
||||
"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"
|
||||
],
|
||||
[
|
||||
"url",
|
||||
"1.0.2"
|
||||
],
|
||||
[
|
||||
"webapp",
|
||||
"1.1.4"
|
||||
],
|
||||
[
|
||||
"webapp-hashing",
|
||||
"1.0.1"
|
||||
]
|
||||
],
|
||||
"pluginDependencies": [],
|
||||
"toolVersion": "meteor-tool@1.0.36",
|
||||
"format": "1.0"
|
||||
}
|
Loading…
Add table
Reference in a new issue