This commit is contained in:
Sacha Greif 2016-06-07 15:03:24 +09:00
parent 5ee570299a
commit 6152be381d
50 changed files with 0 additions and 904 deletions

View file

@ -1 +0,0 @@
.build*

View file

@ -1 +0,0 @@
node_modules

View file

@ -1,7 +0,0 @@
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.

View file

@ -1,44 +0,0 @@
{
"dependencies": {
"feedparser": {
"version": "1.0.0",
"dependencies": {
"sax": {
"version": "0.6.1"
},
"addressparser": {
"version": "0.1.3"
},
"array-indexofobject": {
"version": "0.0.1"
},
"readable-stream": {
"version": "1.0.33",
"dependencies": {
"core-util-is": {
"version": "1.0.1"
},
"isarray": {
"version": "0.0.1"
},
"string_decoder": {
"version": "0.10.31"
},
"inherits": {
"version": "2.0.1"
}
}
}
}
},
"he": {
"version": "0.5.0"
},
"iconv-lite": {
"version": "0.4.7"
},
"to-markdown": {
"version": "0.0.2"
}
}
}

View file

@ -1,65 +0,0 @@
aldeed:autoform@5.1.2
aldeed:http@0.2.2
aldeed:simple-schema@1.3.2
base64@1.0.3
binary-heap@1.0.3
blaze@2.1.2
blaze-tools@1.0.3
boilerplate-generator@1.0.3
callback-hook@1.0.3
cfs:http-methods@0.0.28
check@1.0.5
coffeescript@1.0.6
ddp@1.1.0
deps@1.0.7
ejson@1.0.6
fourseven:scss@2.1.1
geojson-utils@1.0.3
html-tools@1.0.4
htmljs@1.0.4
http@1.1.0
id-map@1.0.3
iron:controller@1.0.7
iron:core@1.0.7
iron:dynamic-template@1.0.7
iron:layout@1.0.7
iron:location@1.0.7
iron:middleware-stack@1.0.7
iron:router@1.0.7
iron:url@1.0.7
jquery@1.11.3_2
json@1.0.3
livedata@1.0.13
local-test:nova:post-by-feed@0.1.0
logging@1.0.7
matb33:collection-hooks@0.7.11
meteor@1.1.6
minifiers@1.1.5
minimongo@1.0.8
momentjs:moment@2.10.0
mongo@1.1.0
observe-sequence@1.0.6
ordered-dict@1.0.3
percolatestudio:synced-cron@1.1.0
random@1.0.3
reactive-dict@1.1.0
reactive-var@1.0.5
retry@1.0.3
routepolicy@1.0.5
session@1.1.0
spacebars@1.0.6
spacebars-compiler@1.0.6
tap:i18n@1.4.1
nova:lib@0.3.1
nova:messages@0.1.0
nova:post-by-feed@0.1.0
nova:posts@0.1.2
nova:tags@0.1.0
templating@1.1.1
tinytest@1.0.5
tracker@1.0.7
ui@1.0.6
underscore@1.0.3
url@1.0.4
webapp@1.2.0
webapp-hashing@1.0.3

View file

@ -1 +0,0 @@
Telescope post by feed package, used internally.

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,5 +0,0 @@
{
"feed_already_exists" : "Feed s toutu URL již existuje.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Pro přidání nového feedu musíte být přihlášený administrátor.",
"import_new_posts_from_feeds" : "Importovat nové příspěvky z feedů."
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,6 +0,0 @@
{
"feeds" : "Feeds",
"feed_already_exists" : "A feed with the same URL already exists.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "You need to log in and be an admin to add a new feed.",
"import_new_posts_from_feeds" : "Import new posts from feeds."
}

View file

@ -1,5 +0,0 @@
{
"feed_already_exists" : "Un feed con la misma URL ya existe.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Tienes que iniciar sesión y ser un administrador para agregar un nuevo feed.",
"import_new_posts_from_feeds" : "Importar nuevos posts desde los feeds."
}

View file

@ -1,6 +0,0 @@
{
"feeds" : "Feeds",
"feed_already_exists" : "Feed sama URLiga on juba olemas.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Sa pead sisse logima ja olema admin, et lisada uus feed.",
"import_new_posts_from_feeds" : "Import uusi postitusi feedist."
}

View file

@ -1,5 +0,0 @@
{
"feed_already_exists" : "یک فید با پیوند مشابه قبلا وجود داشته است.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "برای اضافه کردن فید جدید, شما نیاز به ورود به سامانه به صورت مدیر را دارید.",
"import_new_posts_from_feeds" : "پستهای جدید از فیدها وارد شوند."
}

View file

@ -1,6 +0,0 @@
{
"feeds" : "Feeds",
"feed_already_exists" : "Un flux avec la même URL existe déjà.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Vous devez vous connecter et être un administrateur pour ajouter un nouveau flux.",
"import_new_posts_from_feeds" : "Importez de nouveaux posts à partir de flux."
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,5 +0,0 @@
{
"feed_already_exists" : "Sebuah newsfeed dengan URL yang sama sudah ada.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Anda harus login dan menjadi admin untuk menambahkan newsfeed baru.",
"import_new_posts_from_feeds" : "Impor postingan baru dari newsfeed."
}

View file

@ -1,5 +0,0 @@
{
"feed_already_exists" : "Un feed con lo stesso URL esiste già.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Devi accedere ed essere un amministratore per aggiungere un nuovo feed.",
"import_new_posts_from_feeds" : "Importa nuovi post dai feed."
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,3 +0,0 @@
{
"feed_already_exists" : "같은 게시물(URL)이 존재합니다."
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,5 +0,0 @@
{
"feed_already_exists" : "Kanał z tym samym URL już istnieje.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Musisz się zalogować jako admin aby dodawać nowe kanały.",
"import_new_posts_from_feeds" : "Zaimportuj nowe posty z kanałów."
}

View file

@ -1,5 +0,0 @@
{
"feed_already_exists" : "Um feed com a mesma URL já existe.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Você precisa se logar e ser um admin para adicionar um novo feed.",
"import_new_posts_from_feeds" : "Importar novas postagens dos feeds."
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,5 +0,0 @@
{
"feed_already_exists" : "Pregled objav z istim URL že obstaja.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Morate se prijaviti in biti admin, da dodate nov pregled objav.",
"import_new_posts_from_feeds" : "Uvozi nove objave iz pregleda objav."
}

View file

@ -1,5 +0,0 @@
{
"feed_already_exists" : "Ett flöde med samma webbaddress finns redan.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Du måste logga in och vara en admin för att lägga till en ny ström.",
"import_new_posts_from_feeds" : "Importera nya inlägg från flöden."
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,6 +0,0 @@
{
"feeds" : "Beslemeler",
"feed_already_exists" : "Bu URL'i kullananan bir besleme zaten var.",
"you_need_to_login_and_be_an_admin_to_add_a_new_feed" : "Yeni bir besleme ekleyebilmek için yönetici olarak giri yapmış olmanız gerekir.",
"import_new_posts_from_feeds" : "Beslemeerden yeni gönderileri içeri al."
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,2 +0,0 @@
{
}

View file

@ -1,6 +0,0 @@
<template name="feed_item">
<div class="form-module">
{{> quickForm collection="Feeds" id=formId type="update" doc=this label-class="control-label" input-col-class="controls" template="bootstrap3-horizontal"}}
<a href="#" class="delete-link">Delete</a>
</div>
</template>

View file

@ -1,16 +0,0 @@
Meteor.startup(function () {
Template.feed_item.helpers({
formId: function () {
return 'updateFeed-'+ this._id;
}
});
Template.feed_item.events({
'click .delete-link': function(e, instance){
e.preventDefault();
if (confirm("Delete feed?")) {
Feeds.remove(instance.data._id);
}
}
});
});

View file

@ -1,11 +0,0 @@
<template name="feeds">
<div class="form-well add-feed">
<h3>Add new feed:</h3>
{{> quickForm collection="Feeds" id="insertFeedForm" type="insert" label-class="control-label" input-col-class="controls" template="bootstrap3-horizontal"}}
</div>
{{#loader ready=Template.subscriptionsReady}}
{{#each feeds}}
{{> feed_item}}
{{/each}}
{{/loader}}
</template>

View file

@ -1,11 +0,0 @@
Template.feeds.onCreated(function () {
var template = this;
template.subscribe('feeds');
template.subscribe('allUsersAdmin');
});
Template.feeds.helpers({
feeds: function(){
return Feeds.find({}, {sort: {url: 1}});
}
});

View file

@ -1,111 +0,0 @@
Feeds = new Mongo.Collection('feeds');
Feeds.schema = new SimpleSchema({
url: {
type: String,
regEx: SimpleSchema.RegEx.Url,
insertableIf: Users.is.admin,
editableIf: Users.is.admin
},
userId: {
type: String,
label: 'feedUser',
insertableIf: Users.is.admin,
editableIf: Users.is.admin,
autoform: {
instructions: 'Posts will be assigned to this user.',
options: function () {
var users = Meteor.users.find().map(function (user) {
return {
value: user._id,
label: Users.getDisplayName(user)
};
});
return users;
}
}
},
categories: {
type: [String],
label: 'categories',
optional: true,
insertableIf: Users.is.admin,
editableIf: Users.is.admin,
autoform: {
instructions: 'Posts will be assigned to this category.',
noselect: true,
editable: true,
options: function () {
var categories = Categories.find().map(function (category) {
return {
value: category._id,
label: category.name
};
});
return categories;
}
}
}
});
Meteor.startup(function(){
Feeds.internationalize();
});
Feeds.attachSchema(Feeds.schema);
// used to keep track of which feed a post was imported from
var feedIdProperty = {
fieldName: 'feedId',
fieldSchema: {
type: String,
label: 'feedId',
optional: true,
autoform: {
omit: true
}
}
};
Posts.addField(feedIdProperty);
// the RSS ID of the post in its original feed
var feedItemIdProperty = {
fieldName: 'feedItemId',
fieldSchema: {
type: String,
label: 'feedItemId',
optional: true,
autoform: {
omit: true
}
}
};
Posts.addField(feedItemIdProperty);
Meteor.startup(function () {
Feeds.allow({
insert: Users.is.adminById,
update: Users.is.adminById,
remove: Users.is.adminById
});
Meteor.methods({
insertFeed: function(feedUrl){
check(feedUrl, Feeds.schema);
if (Feeds.findOne({url: feedUrl.url}))
throw new Meteor.Error('already-exists', __('feed_already_exists'));
if (!Meteor.user() || !Users.is.admin(Meteor.user()))
throw new Meteor.Error('login-required', __('you_need_to_login_and_be_an_admin_to_add_a_new_feed'));
return Feeds.insert(feedUrl);
}
});
});
Telescope.menuItems.add("adminMenu", {
route: "adminFeeds",
label: "feeds",
description: "import_new_posts_from_feeds"
});

View file

@ -1,6 +0,0 @@
Telescope.adminRoutes.route('/feeds', {
name: "adminFeeds",
action: function(params, queryParams) {
BlazeLayout.render("layout", {main: "admin_wrapper", admin: "feeds"});
}
});

View file

@ -1,24 +0,0 @@
SyncedCron.options = {
log: false,
collectionName: 'cronHistory',
utc: false,
collectionTTL: 172800
}
var addJob = function () {
SyncedCron.add({
name: 'Post by RSS feed',
schedule: function(parser) {
return parser.text('every 30 minutes');
},
job: function() {
if (Feeds.find().count()) {
fetchFeeds();
}
}
});
}
Meteor.startup(function () {
addJob();
})

View file

@ -1,178 +0,0 @@
import moment from 'moment';
var toMarkdown = Npm.require('to-markdown').toMarkdown;
var he = Npm.require('he');
var FeedParser = Npm.require('feedparser');
var Readable = Npm.require('stream').Readable;
var iconv = Npm.require('iconv-lite');
var getFirstAdminUser = function() {
return Users.adminUsers({sort: {createdAt: 1}, limit: 1})[0];
};
var normalizeEncoding = function (contentBuffer) {
// got from https://github.com/szwacz/sputnik/
var encoding;
var content = contentBuffer.toString();
var xmlDeclaration = content.match(/^<\?xml .*\?>/);
if (xmlDeclaration) {
var encodingDeclaration = xmlDeclaration[0].match(/encoding=("|').*?("|')/);
if (encodingDeclaration) {
encoding = encodingDeclaration[0].substring(10, encodingDeclaration[0].length - 1);
}
}
if (encoding && encoding.toLowerCase() !== 'utf-8') {
try {
content = iconv.decode(contentBuffer, encoding);
} catch (err) {
// detected encoding is not supported, leave it as it is
}
}
return content;
};
var feedHandler = {
getStream: function(content) {
var stream = new Readable();
stream.push(content);
stream.push(null);
return stream;
},
getItemCategories: function(item, feedCategories) {
var itemCategories = [];
// loop over RSS categories for the current item if it has any
if (item.categories && item.categories.length > 0) {
item.categories.forEach(function(name) {
// if the RSS category corresponds to a Telescope cateogry, add it
var category = Categories.findOne({name: name}, {fields: {_id: 1}});
if (category) {
itemCategories.push(category._id);
}
});
}
// add predefined feed categories if there are any and remove any duplicates
if (!!feedCategories) {
itemCategories = _.uniq(itemCategories.concat(feedCategories));
}
return itemCategories;
},
handle: function(contentBuffer, userId, feedCategories, feedId) {
var content = normalizeEncoding(contentBuffer);
var stream = this.getStream(content),
feedParser = new FeedParser(),
newItemsCount = 0,
self = this;
stream.pipe(feedParser);
feedParser.on('meta', Meteor.bindEnvironment(function (meta) {
console.log('// Parsing RSS feed: '+ meta.title);
}));
feedParser.on('error', Meteor.bindEnvironment(function (error) {
console.log(error);
}));
feedParser.on('readable', Meteor.bindEnvironment(function () {
var s = this, item;
while (item = s.read()) {
// if item has no guid, use the URL to give it one
if (!item.guid) {
item.guid = item.link;
}
// check if post already exists
if (!!Posts.findOne({feedItemId: item.guid})) {
console.log('// Feed item already imported');
continue;
}
newItemsCount++;
var post = {
title: he.decode(item.title),
url: item.link,
feedId: feedId,
feedItemId: item.guid,
userId: userId,
categories: self.getItemCategories(item, feedCategories)
};
if (item.description)
post.body = toMarkdown(he.decode(item.description));
// console.log(item)
// if RSS item link is a 301 or 302 redirect, follow the redirect
var get = HTTP.get(item.link, {followRedirects: false});
if (!!get.statusCode && (get.statusCode === 301 || get.statusCode === 302) &&
!!get.headers && !!get.headers.location) {
post.url = get.headers.location;
}
// if RSS item has a date, use it
if (item.pubdate)
post.postedAt = moment(item.pubdate).toDate();
try {
Posts.submit(post);
} catch (error) {
// catch errors so they don't stop the loop
console.log(error);
}
}
// console.log('// Found ' + newItemsCount + ' new feed items');
}, function (error) {
console.log('// Failed to bind environment');
console.log(error.stack)
}, feedParser));
}
};
fetchFeeds = function() {
var contentBuffer;
Feeds.find().forEach(function(feed) {
// if feed doesn't specify a user, default to admin
var userId = !!feed.userId ? feed.userId : getFirstAdminUser()._id;
var feedCategories = feed.categories;
var feedId = feed._id;
try {
contentBuffer = HTTP.get(feed.url, {responseType: 'buffer'}).content;
feedHandler.handle(contentBuffer, userId, feedCategories, feedId);
} catch (error) {
console.log(error);
return true; // just go to next feed URL
}
});
};
Meteor.methods({
fetchFeeds: function () {
console.log("// fetching feeds…");
fetchFeeds();
},
testEntities: function (text) {
console.log(he.decode(text));
},
testToMarkdown: function (text) {
console.log(toMarkdown(text));
}
});

View file

@ -1,6 +0,0 @@
Meteor.publish('feeds', function() {
if(Users.is.adminById(this.userId)){
return Feeds.find();
}
return [];
});

View file

@ -1,5 +0,0 @@
{
"translation_function_name": "__",
"helper_name": "_",
"namespace": "project"
}

View file

@ -1,52 +0,0 @@
Package.describe({
name: "post-by-feed",
summary: "Auto post via RSS to Telescope",
version: "0.26.2-nova",
git: "https://github.com/TelescopeJS/telescope-post-by-feed.git"
});
Npm.depends({
'feedparser': '1.0.0',
'to-markdown': '0.0.2',
'he': '0.5.0',
'iconv-lite': '0.4.7'
});
Package.onUse(function(api) {
api.versionsFrom("METEOR@1.0");
api.use(['nova:core@0.26.2-nova']);
api.addFiles([
'lib/feeds.js',
'lib/routes.js'
], ['client', 'server']);
api.addFiles([
'lib/client/templates/feeds.html',
'lib/client/templates/feeds.js',
'lib/client/templates/feed_item.html',
'lib/client/templates/feed_item.js',
], 'client');
api.addFiles([
'lib/server/fetch_feeds.js',
'lib/server/cron.js',
'lib/server/publications.js'
], ['server']);
var languages = ["ar", "bg", "cs", "da", "de", "el", "en", "es", "et", "fr", "hu", "id", "it", "ja", "kk", "ko", "nl", "pl", "pt-BR", "ro", "ru", "sl", "sv", "th", "tr", "vi", "zh-CN"];
var languagesPaths = languages.map(function (language) {
return "i18n/"+language+".i18n.json";
});
api.addFiles(languagesPaths, ["client", "server"]);
api.export([
'Feeds'
]);
});
Package.onTest(function(api) {
api.use('tinytest');
});

View file

@ -1,251 +0,0 @@
{
"dependencies": [
[
"aldeed:autoform",
"4.2.0"
],
[
"aldeed:simple-schema",
"1.2.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"
],
[
"fourseven:scss",
"1.0.0"
],
[
"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.4"
],
[
"iron:dynamic-template",
"1.0.5"
],
[
"iron:layout",
"1.0.5"
],
[
"iron:location",
"1.0.4"
],
[
"iron:middleware-stack",
"1.0.3"
],
[
"iron:router",
"1.0.3"
],
[
"iron:url",
"1.0.4"
],
[
"jquery",
"1.0.1"
],
[
"json",
"1.0.1"
],
[
"livedata",
"1.0.11"
],
[
"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"
],
[
"nova: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"
}