3 * Action to let RSSCloud aggregators request update notification when
4 * user profile feeds change.
10 * @author Zach Copley <zach@status.net>
11 * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
12 * @link http://status.net/
14 * StatusNet - the distributed open-source microblogging tool
15 * Copyright (C) 2009, StatusNet, Inc.
17 * This program is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU Affero General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU Affero General Public License for more details.
27 * You should have received a copy of the GNU Affero General Public License
28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 if (!defined('STATUSNET')) {
35 class RSSCloudRequestNotifyAction extends Action
40 * @param array $args Web and URL arguments
42 * @return boolean false if user doesn't exist
44 function prepare($args)
46 parent::prepare($args);
48 $this->ip = $_SERVER['REMOTE_ADDR'];
49 $this->port = $this->arg('port');
50 $this->path = $this->arg('path');
52 if ($this->path[0] != '/') {
53 $this->path = '/' . $this->path;
56 $this->protocol = $this->arg('protocol');
57 $this->procedure = $this->arg('notifyProcedure');
58 $this->domain = $this->arg('domain');
60 $this->feeds = $this->getFeeds();
65 function handle($args)
67 parent::handle($args);
69 if ($_SERVER['REQUEST_METHOD'] != 'POST') {
70 $this->showResult(false, 'Request must be POST.');
76 if (empty($this->port)) {
80 if (empty($this->path)) {
84 if (empty($this->protocol)) {
85 $missing[] = 'protocol';
88 if (!isset($this->procedure)) {
89 $missing[] = 'notifyProcedure';
92 if (!empty($missing)) {
93 $msg = 'The following parameters were missing from the request body: ' .
94 implode(', ', $missing) . '.';
95 $this->showResult(false, $msg);
99 if (empty($this->feeds)) {
100 $this->showResult(false,
101 'You must provide at least one valid profile feed url (url1, url2, url3 ... urlN).');
105 // We have to validate everything before saving anything.
106 // We only return one success or failure no matter how
107 // many feeds the subscriber is trying to subscribe to
109 foreach ($this->feeds as $feed) {
111 if (!$this->validateFeed($feed)) {
112 $msg = 'Feed subscription failed - Not a valid feed.';
113 $this->showResult(false, $msg);
117 if (!$this->testNotificationHandler($feed)) {
118 $msg = 'Feed subscription failed - ' .
119 'notification handler doesn\'t respond correctly.';
120 $this->showResult(false, $msg);
126 foreach ($this->feeds as $feed) {
127 $this->saveSubscription($feed);
130 // XXX: What to do about deleting stale subscriptions?
131 // 25 hours seems harsh. WordPress doesn't ever remove
134 $msg = 'Thanks for the subscription. ' .
135 'When the feed(s) update(s) we\'ll notify you.';
137 $this->showResult(true, $msg);
140 function validateFeed($feed)
142 $user = $this->userFromFeed($feed);
155 while (list($key, $feed) = each ($this->args)) {
156 if (preg_match('/^url\d*$/', $key)) {
164 function testNotificationHandler($feed)
166 common_debug("RSSCloudPlugin - testNotificationHandler()");
168 $notifyUrl = $this->getNotifyUrl();
170 $notifier = new RSSCloudNotifier();
172 if (isset($this->domain)) {
174 // 'domain' param set, so we have to use GET and send a challenge
176 common_log(LOG_INFO, 'Testing notification handler with challenge: ' .
178 return $notifier->challenge($notifyUrl, $feed);
181 common_log(LOG_INFO, 'Testing notification handler: ' .
184 return $notifier->postUpdate($notifyUrl, $feed);
188 function getNotifyUrl()
190 if (isset($this->domain)) {
191 return 'http://' . $this->domain . ':' . $this->port . $this->path;
193 return 'http://' . $this->ip . ':' . $this->port . $this->path;
197 function userFromFeed($feed)
199 // We only do profile feeds
201 // XXX: Add cloud element to RSS 1.0 feeds?
203 $path = common_path('api/statuses/user_timeline/');
204 $valid = '%^' . $path . '(?<nickname>.*)\.rss$%';
206 if (preg_match($valid, $feed, $matches)) {
207 $user = User::staticGet('nickname', $matches['nickname']);
216 function saveSubscription($feed)
218 $user = $this->userFromFeed($feed);
220 $notifyUrl = $this->getNotifyUrl();
222 $sub = RSSCloudSubscription::getSubscription($user->id, $notifyUrl);
225 common_debug("Already subscribed to that!");
228 $sub = new RSSCloudSubscription();
230 $sub->subscribed = $user->id;
231 $sub->url = $notifyUrl;
232 $sub->created = common_sql_now();
234 if (!$sub->insert()) {
235 common_log_db_error($sub, 'INSERT', __FILE__);
244 function showResult($success, $msg)
247 $this->elementStart('notifyResult', array('success' => ($success) ? 'true' : 'false',