[RSSCloud] Update schema definition

This commit is contained in:
Alexei Sorokin 2020-08-11 18:23:45 +03:00
parent 15f7941daf
commit 2abe910ff5
3 changed files with 152 additions and 143 deletions

View File

@ -1,35 +1,37 @@
This plugin enables RSSCloud (http://rsscloud.org/) publishing and subscription This plugin enables RSSCloud (http://rsscloud.co/) publishing and subscription
handling for RSS 2.0 profile feeds (i.e: handling for RSS 2.0 profile feeds (i.e:
http://SITE/PATH/api/statuses/user_timeline/USERNAME.rss). When the plugin is http://SITE/PATH/api/statuses/user_timeline/USERNAME.rss). When the plugin is
enabled, StatusNet acts as both the publisher and hub ('writer' and 'cloud' in enabled, GNU social acts as both the publisher and hub ('writer' and 'cloud' in
RSSCloud parlance), but only for local StatusNet feeds. It's not possible to use RSSCloud parlance), but only for local GNU social feeds. It's not possible to use
it as a general purpose hub -- for instance you can't subscribe and get updates it as a general purpose hub -- for instance you can't subscribe and get updates
to a Wordpress feed from StatusNet using this plugin. to a Wordpress feed from GNU social using this plugin.
To use the plugin, add the following to your config.php: To use the plugin, add the following to your config.php:
addPlugin('RSSCloud'); ```php
addPlugin('RSSCloud');
```
Enabling the plugin will add a <cloud> element to your RSS 2.0 profile feeds Enabling the plugin will add a <cloud> element to your RSS 2.0 profile feeds
that looks like this: that looks like this:
<cloud domain="SITE" port="80" path="/main/rsscloud/request_notify" ```
registerProcedure="" protocol="http-post"/> <cloud domain="SITE" port="80" path="/main/rsscloud/request_notify"
registerProcedure="" protocol="http-post"/>
```
Aggregators may subscribe by sending a proper REST RSSCloud subscription request Aggregators may subscribe by sending a proper REST RSSCloud subscription request
(the optional 'domain' parameter with challenge is supported). Subscribing (the optional 'domain' parameter with challenge is supported). Subscribing
aggregators will be notified ('pinged') when users they have subscribed to post aggregators will be notified ('pinged') when users they have subscribed to post
new notices. Currently, REST is the only protocol supported for notifications. new notices. Currently, REST is the only protocol supported for notifications.
Deamon ## Daemon
------
There's also a daemon for offline processing of queued notices with RSSCloud There's also a daemon for offline processing of queued notices with RSSCloud
destinations, which will start automatically if/when you run destinations, which will start automatically if/when you run
scripts/startdaemons.sh. scripts/startdaemons.sh.
Notes ## Notes
-----
- Again, only RSS 2.0 profile feeds may be subscribed to, and they have to be - Again, only RSS 2.0 profile feeds may be subscribed to, and they have to be
the ones with user names in them, like: the ones with user names in them, like:
@ -39,8 +41,7 @@ Notes
- The plugin includes a dummy LoggingAggregator class that can be used for - The plugin includes a dummy LoggingAggregator class that can be used for
end-to-end testing. You probably don't want to mess with it. end-to-end testing. You probably don't want to mess with it.
TODO ## TODO
----
- Figure out why the RSSCloudSubcription can't ->delete() or ->update() - Figure out why the RSSCloudSubcription can't ->delete() or ->update()
- Support pinging via XML-RPC and SOAP - Support pinging via XML-RPC and SOAP

View File

@ -1,35 +1,30 @@
<?php <?php
// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
/** /**
* StatusNet, the distributed open-source microblogging tool
*
* Plugin to support RSSCloud * Plugin to support RSSCloud
* *
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin * @category Plugin
* @package StatusNet * @package GNUsocial
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
if (!defined('STATUSNET')) { defined('GNUSOCIAL') || die();
exit(1);
}
define('RSSCLOUDPLUGIN_VERSION', '0.1.0'); define('RSSCLOUDPLUGIN_VERSION', '0.1.0');
@ -39,8 +34,7 @@ define('RSSCLOUDPLUGIN_VERSION', '0.1.0');
* @category Plugin * @category Plugin
* @package StatusNet * @package StatusNet
* @author Zach Copley <zach@status.net> * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
* @link http://status.net/
*/ */
class RSSCloudPlugin extends Plugin class RSSCloudPlugin extends Plugin
{ {
@ -49,7 +43,7 @@ class RSSCloudPlugin extends Plugin
* *
* @return void * @return void
*/ */
function __construct() public function __construct()
{ {
parent::__construct(); parent::__construct();
} }
@ -60,7 +54,7 @@ class RSSCloudPlugin extends Plugin
* *
* @return void * @return void
*/ */
function onInitializePlugin() public function onInitializePlugin(): void
{ {
$this->domain = common_config('rsscloud', 'domain'); $this->domain = common_config('rsscloud', 'domain');
$this->port = common_config('rsscloud', 'port'); $this->port = common_config('rsscloud', 'port');
@ -98,19 +92,22 @@ class RSSCloudPlugin extends Plugin
* *
* Hook for RouterInitialized event. * Hook for RouterInitialized event.
* *
* @param Mapper $m URL parser and mapper * @param URLMapper $m URL parser and mapper
* * @return bool hook return
* @return boolean hook return
*/ */
function onRouterInitialized($m) public function onRouterInitialized(URLMapper $m): bool
{ {
$m->connect('/main/rsscloud/request_notify', $m->connect(
['action' => 'RSSCloudRequestNotify']); 'main/rsscloud/request_notify',
['action' => 'RSSCloudRequestNotify']
);
// XXX: This is just for end-to-end testing. Uncomment if you need to pretend // XXX: This is just for end-to-end testing. Uncomment if you need to pretend
// to be a cloud hub for some reason. // to be a cloud hub for some reason.
//$m->connect('/main/rsscloud/notify', //$m->connect(
// array('action' => 'LoggingAggregator')); // 'main/rsscloud/notify',
// ['action' => 'LoggingAggregator']
//);
return true; return true;
} }
@ -120,18 +117,18 @@ class RSSCloudPlugin extends Plugin
* element is started). * element is started).
* *
* @param Action $action the ApiAction * @param Action $action the ApiAction
*
* @return void * @return void
*/ */
function onStartApiRss($action) public function onStartApiRss(Action $action): void
{ {
if (get_class($action) == 'ApiTimelineUserAction') { if (get_class($action) == 'ApiTimelineUserAction') {
$attrs = [
$attrs = array('domain' => $this->domain, 'domain' => $this->domain,
'port' => $this->port, 'port' => $this->port,
'path' => $this->path, 'path' => $this->path,
'registerProcedure' => $this->funct, 'registerProcedure' => $this->funct,
'protocol' => $this->protocol); 'protocol' => $this->protocol,
];
// Dipping into XMLWriter to avoid a full end element (</cloud>). // Dipping into XMLWriter to avoid a full end element (</cloud>).
@ -149,12 +146,13 @@ class RSSCloudPlugin extends Plugin
* *
* @param Notice $notice the notice * @param Notice $notice the notice
* @param array &$transports the list of transports (queues) * @param array &$transports the list of transports (queues)
* * @return bool hook return
* @return boolean hook return
*/ */
function onStartEnqueueNotice($notice, &$transports) public function onStartEnqueueNotice(
{ Notice $notice,
array &$transports
): bool {
if ($notice->isLocal()) { if ($notice->isLocal()) {
array_push($transports, 'rsscloud'); array_push($transports, 'rsscloud');
} }
@ -165,50 +163,67 @@ class RSSCloudPlugin extends Plugin
* Create the rsscloud_subscription table if it's not * Create the rsscloud_subscription table if it's not
* already in the DB * already in the DB
* *
* @return boolean hook return * @return bool hook return
*/ */
function onCheckSchema() public function onCheckSchema(): bool
{ {
$schema = Schema::get(); $schema = Schema::get();
$schema->ensureTable('rsscloud_subscription', $schema->ensureTable(
array( 'rsscloud_subscription',
'fields' => array( RSSCloudSubscription::schemaDef()
'subscribed' => array('type' => 'int', 'not null' => true), );
'url' => array('type' => 'varchar', 'length' => '191', 'not null' => true), return true;
'failures' => array('type' => 'int', 'not null' => true, 'default' => 0),
'created' => array('type' => 'datetime', 'not null' => true),
'modified' => array('type' => 'timestamp', 'not null' => true),
),
'primary key' => array('subscribed', 'url'),
));
return true;
} }
/** /**
* Register RSSCloud notice queue handler * Register RSSCloud notice queue handler
* *
* @param QueueManager $manager * @param QueueManager $manager
* * @return bool hook return
* @return boolean hook return
*/ */
function onEndInitializeQueueManager($manager) public function onEndInitializeQueueManager(QueueManager $manager): bool
{ {
$manager->connect('rsscloud', 'RSSCloudQueueHandler'); $manager->connect('rsscloud', 'RSSCloudQueueHandler');
return true; return true;
} }
/**
* Ensure that subscriptions for a user are deleted
* when that user gets deleted.
*
* @param User $user
* @param array &$related list of related tables
*
* @return bool hook result
*/
public function onUserDeleteRelated(User $user, array &$related): bool
{
$sub = new RSSCloudSubscription();
$sub->subscribed = $user->id;
if ($sub->find()) {
while ($sub->fetch()) {
$sub->delete();
}
}
$sub->free();
return true;
}
public function onPluginVersion(array &$versions): bool public function onPluginVersion(array &$versions): bool
{ {
$versions[] = array('name' => 'RSSCloud', $versions[] = [
'version' => RSSCLOUDPLUGIN_VERSION, 'name' => 'RSSCloud',
'author' => 'Zach Copley', 'version' => RSSCLOUDPLUGIN_VERSION,
'homepage' => GNUSOCIAL_ENGINE_REPO_URL . 'tree/master/plugins/RSSCloud', 'author' => 'Zach Copley',
'rawdescription' => 'homepage' => GNUSOCIAL_ENGINE_REPO_URL . 'tree/master/plugins/RSSCloud',
// TRANS: Plugin description. 'rawdescription' =>
_m('The RSSCloud plugin enables your StatusNet instance to publish ' . // TRANS: Plugin description.
'real-time updates for profile RSS feeds using the ' . _m('The RSSCloud plugin enables your GNU social instance to '
'<a href="http://rsscloud.org/">RSSCloud protocol</a>.')); . 'publish real-time updates for profile RSS feeds using the '
. '<a href="http://rsscloud.co/">rssCloud protocol</a>.'),
];
return true; return true;
} }

View File

@ -1,71 +1,64 @@
<?php <?php
/* // This file is part of GNU social - https://www.gnu.org/software/social
* StatusNet - the distributed open-source microblogging tool //
* Copyright (C) 2008, 2009, StatusNet, Inc. // GNU social is free software: you can redistribute it and/or modify
* // it under the terms of the GNU Affero General Public License as published by
* This program is free software: you can redistribute it and/or modify // the Free Software Foundation, either version 3 of the License, or
* it under the terms of the GNU Affero General Public License as published by // (at your option) any later version.
* the Free Software Foundation, either version 3 of the License, or //
* (at your option) any later version. // GNU social is distributed in the hope that it will be useful,
* // but WITHOUT ANY WARRANTY; without even the implied warranty of
* This program is distributed in the hope that it will be useful, // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* but WITHOUT ANY WARRANTY; without even the implied warranty of // GNU Affero General Public License for more details.
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
* GNU Affero General Public License for more details. // You should have received a copy of the GNU Affero General Public License
* // along with GNU social. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
/** /**
* Table Definition for rsscloud_subscription * Table Definition for rsscloud_subscription
*
* @category Plugin
* @package GNUsocial
* @author Zach Copley <zach@status.net>
* @copyright 2008, 2009 StatusNet, Inc.
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; defined('GNUSOCIAL') || die();
class RSSCloudSubscription extends Memcached_DataObject { class RSSCloudSubscription extends Managed_DataObject
{
public $__table='rsscloud_subscription'; // table name
public $subscribed; // int primary key user id
public $url; // string primary key
public $failures; // int
public $created; // datestamp()
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
var $__table='rsscloud_subscription'; // table name public static function schemaDef(): array
var $subscribed; // int primary key user id
var $url; // string primary key
var $failures; // int
var $created; // datestamp()
var $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
static function getKV($k,$v=NULL) { return DB_DataObject::staticGet('DataObjects_Grp',$k,$v); }
function table()
{ {
return [
$db = $this->getDatabaseConnection(); 'fields' => [
$dbtype = $db->phptype; 'subscribed' => ['type' => 'int', 'not null' => true],
'url' => ['type' => 'varchar', 'length' => '191', 'not null' => true],
$cols = array('subscribed' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, 'failures' => ['type' => 'int', 'not null' => true, 'default' => 0],
'url' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL, 'created' => ['type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'],
'failures' => DB_DATAOBJECT_INT, 'modified' => ['type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'],
'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL, ],
'modified' => ($dbtype == 'mysql' || $dbtype == 'mysqli') ? 'primary key' => ['subscribed', 'url'],
DB_DATAOBJECT_MYSQLTIMESTAMP + DB_DATAOBJECT_NOTNULL : 'foreign keys' => [
DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME 'rsscloud_subscription_subscribed_fkey' => ['user', ['subscribed' => 'id']],
); ],
];
return $cols;
} }
function keys() public static function getSubscription(
{ int $subscribed,
return array('subscribed' => 'N', 'url' => 'N'); string $url
} ): ?self {
static function getSubscription($subscribed, $url)
{
$sub = new RSSCloudSubscription(); $sub = new RSSCloudSubscription();
$sub->whereAdd("subscribed = $subscribed"); $sub->whereAdd("subscribed = {$subscribed}");
$sub->whereAdd("url = '$url'"); $sub->whereAdd("url = '{$sub->escape($url)}'");
$sub->limit(1); $sub->limit(1);
if ($sub->find()) { if ($sub->find()) {
@ -73,6 +66,6 @@ class RSSCloudSubscription extends Memcached_DataObject {
return $sub; return $sub;
} }
return false; return null;
} }
} }