return true;
}
+ /**
+ * Load related modules when needed
+ *
+ * Most non-trivial plugins will require extra modules to do their work. Typically
+ * these include data classes, action classes, widget classes, or external libraries.
+ *
+ * This method receives a class name and loads the PHP file related to that class. By
+ * tradition, action classes typically have files named for the action, all lower-case.
+ * Data classes are in files with the data class name, initial letter capitalized.
+ *
+ * Note that this method will be called for *all* overloaded classes, not just ones
+ * in this plugin! So, make sure to return true by default to let other plugins, and
+ * the core code, get a chance.
+ *
+ * @param string $cls Name of the class to be loaded
+ *
+ * @return boolean hook value; true means continue processing, false means stop.
+ */
+ public function onAutoload($cls) {
+ $cls = basename($cls);
+ $basedir = INSTALLDIR . '/plugins/' . mb_substr(get_called_class(), 0, -6);
+ $file = null;
+
+ if (preg_match('/^(\w+)(Action|Form)$/', $cls, $type)) {
+ $type = array_map('strtolower', $type);
+ $file = "$basedir/{$type[2]}s/{$type[1]}.php";
+ } else {
+ $file = "$basedir/classes/{$cls}.php";
+
+ if (!file_exists($file)) {
+ $type = strtolower($cls);
+ $file = "$basedir/lib/{$type}.php";
+ }
+ }
+
+ if (!is_null($file) && file_exists($file)) {
+ require_once($file);
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Checks if this plugin has localization that needs to be set up.
* Gettext localizations can be called via the _m() helper function.
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Implements the JSON Account Management endpoint
- *
- * 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 AccountManager
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Implements the JSON Account Management endpoint
- *
- * @category AccountManager
- * @package StatusNet
- * @author ECraig Andrews <candrews@integralblue.com>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class AccountManagementControlDocumentAction extends Action
-{
- /**
- * handle the action
- *
- * @param array $args unused.
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- header('Content-Type: application/json; charset=utf-8');
-
- $amcd = array();
-
- if(Event::handle('StartAccountManagementControlDocument', array(&$amcd))) {
-
- $amcd['version'] = 1;
- $amcd['sessionstatus'] = array(
- 'method' => 'GET',
- 'path' => common_local_url('AccountManagementSessionStatus')
- );
- $amcd['auth-methods'] = array(
- 'username-password-form' => array(
- 'connect' => array(
- 'method' => 'POST',
- 'path' => common_local_url('login'),
- 'params' => array(
- 'username' => 'nickname',
- 'password' => 'password'
- )
- ),
- 'disconnect' => array(
- 'method' => 'GET',
- 'path' => common_local_url('logout')
- )
- )
- );
-
- Event::handle('EndAccountManagementControlDocument', array(&$amcd));
- }
-
- print json_encode($amcd);
-
- return true;
- }
-
- function isReadOnly()
- {
- return true;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Implements the session status Account Management endpoint
- *
- * 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 AccountManager
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Implements the session status Account Management endpoint
- *
- * @category AccountManager
- * @package StatusNet
- * @author ECraig Andrews <candrews@integralblue.com>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class AccountManagementSessionStatusAction extends Action
-{
- /**
- * handle the action
- *
- * @param array $args unused.
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- $cur = common_current_user();
- if(empty($cur)) {
- print 'none';
- } else {
- //TODO it seems " should be escaped in the name and id, but the spec doesn't seem to indicate how to do that
- print 'active; name="' . $cur->nickname . '"; id="' . $cur->nickname . '"';
- }
-
- return true;
- }
-
- function isReadOnly()
- {
- return true;
- }
-}
parent::__construct();
}
- function onAutoload($cls)
- {
- switch ($cls)
- {
- case 'AccountManagementControlDocumentAction':
- require_once(INSTALLDIR.'/plugins/AccountManager/AccountManagementControlDocumentAction.php');
- return false;
- case 'AccountManagementSessionStatusAction':
- require_once(INSTALLDIR.'/plugins/AccountManager/AccountManagementSessionStatusAction.php');
- return false;
- }
- }
-
/**
* Hook for RouterInitialized event.
*
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Implements the JSON Account Management endpoint
+ *
+ * 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 AccountManager
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Implements the JSON Account Management endpoint
+ *
+ * @category AccountManager
+ * @package StatusNet
+ * @author ECraig Andrews <candrews@integralblue.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class AccountManagementControlDocumentAction extends Action
+{
+ /**
+ * handle the action
+ *
+ * @param array $args unused.
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ header('Content-Type: application/json; charset=utf-8');
+
+ $amcd = array();
+
+ if(Event::handle('StartAccountManagementControlDocument', array(&$amcd))) {
+
+ $amcd['version'] = 1;
+ $amcd['sessionstatus'] = array(
+ 'method' => 'GET',
+ 'path' => common_local_url('AccountManagementSessionStatus')
+ );
+ $amcd['auth-methods'] = array(
+ 'username-password-form' => array(
+ 'connect' => array(
+ 'method' => 'POST',
+ 'path' => common_local_url('login'),
+ 'params' => array(
+ 'username' => 'nickname',
+ 'password' => 'password'
+ )
+ ),
+ 'disconnect' => array(
+ 'method' => 'GET',
+ 'path' => common_local_url('logout')
+ )
+ )
+ );
+
+ Event::handle('EndAccountManagementControlDocument', array(&$amcd));
+ }
+
+ print json_encode($amcd);
+
+ return true;
+ }
+
+ function isReadOnly()
+ {
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Implements the session status Account Management endpoint
+ *
+ * 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 AccountManager
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Implements the session status Account Management endpoint
+ *
+ * @category AccountManager
+ * @package StatusNet
+ * @author ECraig Andrews <candrews@integralblue.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class AccountManagementSessionStatusAction extends Action
+{
+ /**
+ * handle the action
+ *
+ * @param array $args unused.
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ $cur = common_current_user();
+ if(empty($cur)) {
+ print 'none';
+ } else {
+ //TODO it seems " should be escaped in the name and id, but the spec doesn't seem to indicate how to do that
+ print 'active; name="' . $cur->nickname . '"; id="' . $cur->nickname . '"';
+ }
+
+ return true;
+ }
+
+ function isReadOnly()
+ {
+ return true;
+ }
+}
public $StartLike = false;
public $StopLike = false;
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'JoinListItem':
- case 'LeaveListItem':
- case 'FollowListItem':
- case 'UnfollowListItem':
- case 'SystemListItem':
- include_once $dir . '/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
- }
- }
-
function onEndSubscribe($subscriber, $other)
{
// Only do this if config is enabled
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Title of module
- *
- * PHP version 5
- *
- * 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 Cache
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * NoticeListItemAdapter for join activities
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class FollowListItem extends SystemListItem
-{
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * List item for when you join a group
- *
- * PHP version 5
- *
- * 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 Cache
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * NoticeListItemAdapter for join activities
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class JoinListItem extends SystemListItem
-{
- function showContent()
- {
- $notice = $this->nli->notice;
- $out = $this->nli->out;
-
- $mem = Group_member::getKV('uri', $notice->uri);
-
- if (!empty($mem)) {
- $out->elementStart('div', 'join-activity');
- $profile = $mem->getMember();
- $group = $mem->getGroup();
-
- // TRANS: Text for "joined list" item in activity plugin.
- // TRANS: %1$s is a profile URL, %2$s is a profile name,
- // TRANS: %3$s is a group home URL, %4$s is a group name.
- $out->raw(sprintf(_m('<a href="%1$s">%2$s</a> joined the group <a href="%3$s">%4$s</a>.'),
- $profile->profileurl,
- $profile->getBestName(),
- $group->homeUrl(),
- $group->getBestName()));
-
- $out->elementEnd('div');
- } else {
- parent::showContent();
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * List item for when you leave a group
- *
- * PHP version 5
- *
- * 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 Cache
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * NoticeListItemAdapter for leave activities
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class LeaveListItem extends SystemListItem
-{
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Title of module
+ *
+ * PHP version 5
+ *
+ * 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 Cache
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * NoticeListItemAdapter for join activities
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class FollowListItem extends SystemListItem
+{
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * List item for when you join a group
+ *
+ * PHP version 5
+ *
+ * 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 Cache
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * NoticeListItemAdapter for join activities
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class JoinListItem extends SystemListItem
+{
+ function showContent()
+ {
+ $notice = $this->nli->notice;
+ $out = $this->nli->out;
+
+ $mem = Group_member::getKV('uri', $notice->uri);
+
+ if (!empty($mem)) {
+ $out->elementStart('div', 'join-activity');
+ $profile = $mem->getMember();
+ $group = $mem->getGroup();
+
+ // TRANS: Text for "joined list" item in activity plugin.
+ // TRANS: %1$s is a profile URL, %2$s is a profile name,
+ // TRANS: %3$s is a group home URL, %4$s is a group name.
+ $out->raw(sprintf(_m('<a href="%1$s">%2$s</a> joined the group <a href="%3$s">%4$s</a>.'),
+ $profile->profileurl,
+ $profile->getBestName(),
+ $group->homeUrl(),
+ $group->getBestName()));
+
+ $out->elementEnd('div');
+ } else {
+ parent::showContent();
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * List item for when you leave a group
+ *
+ * PHP version 5
+ *
+ * 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 Cache
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * NoticeListItemAdapter for leave activities
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class LeaveListItem extends SystemListItem
+{
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Superclass for system event items
+ *
+ * PHP version 5
+ *
+ * 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 Activity
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * NoticeListItemAdapter for system activities
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class SystemListItem extends NoticeListItemAdapter
+{
+ /**
+ * Show the activity
+ *
+ * @return void
+ */
+ function showNotice()
+ {
+ $out = $this->nli->out;
+ $out->elementStart('div', 'entry-title');
+ $this->showContent();
+ $out->elementEnd('div');
+ }
+
+ function showContent()
+ {
+ $notice = $this->nli->notice;
+ $out = $this->nli->out;
+
+ // FIXME: get the actual data on the leave
+
+ $out->elementStart('div', 'system-activity');
+
+ $out->raw($notice->rendered);
+
+ $out->elementEnd('div');
+ }
+
+ function showNoticeOptions()
+ {
+ if (Event::handle('StartShowNoticeOptions', array($this))) {
+ $user = common_current_user();
+ if (!empty($user)) {
+ $this->nli->out->elementStart('div', 'notice-options');
+ $this->showFaveForm();
+ $this->showReplyLink();
+ $this->nli->out->elementEnd('div');
+ }
+ Event::handle('EndShowNoticeOptions', array($this));
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Unfollow list item
+ *
+ * PHP version 5
+ *
+ * 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 Activity
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * NoticeListItemAdapter for join activities
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class UnfollowListItem extends SystemListItem
+{
+ /**
+ * Show the join activity
+ *
+ * @return void
+ */
+ function showNotice()
+ {
+ $out = $this->nli->out;
+ $out->elementStart('div', 'entry-title');
+ $this->showContent();
+ $out->elementEnd('div');
+ }
+
+ function showContent()
+ {
+ $notice = $this->nli->notice;
+ $out = $this->nli->out;
+
+ // FIXME: get the actual data on the leave
+
+ $out->elementStart('div', 'unfollow-activity');
+
+ $out->raw($notice->rendered);
+
+ $out->elementEnd('div');
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Superclass for system event items
- *
- * PHP version 5
- *
- * 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 Activity
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * NoticeListItemAdapter for system activities
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class SystemListItem extends NoticeListItemAdapter
-{
- /**
- * Show the activity
- *
- * @return void
- */
- function showNotice()
- {
- $out = $this->nli->out;
- $out->elementStart('div', 'entry-title');
- $this->showContent();
- $out->elementEnd('div');
- }
-
- function showContent()
- {
- $notice = $this->nli->notice;
- $out = $this->nli->out;
-
- // FIXME: get the actual data on the leave
-
- $out->elementStart('div', 'system-activity');
-
- $out->raw($notice->rendered);
-
- $out->elementEnd('div');
- }
-
- function showNoticeOptions()
- {
- if (Event::handle('StartShowNoticeOptions', array($this))) {
- $user = common_current_user();
- if (!empty($user)) {
- $this->nli->out->elementStart('div', 'notice-options');
- $this->showFaveForm();
- $this->showReplyLink();
- $this->nli->out->elementEnd('div');
- }
- Event::handle('EndShowNoticeOptions', array($this));
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Unfollow list item
- *
- * PHP version 5
- *
- * 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 Activity
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * NoticeListItemAdapter for join activities
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class UnfollowListItem extends SystemListItem
-{
- /**
- * Show the join activity
- *
- * @return void
- */
- function showNotice()
- {
- $out = $this->nli->out;
- $out->elementStart('div', 'entry-title');
- $this->showContent();
- $out->elementEnd('div');
- }
-
- function showContent()
- {
- $notice = $this->nli->notice;
- $out = $this->nli->out;
-
- // FIXME: get the actual data on the leave
-
- $out->elementStart('div', 'unfollow-activity');
-
- $out->raw($notice->rendered);
-
- $out->elementEnd('div');
- }
-}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
-
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'TrainAction':
- case 'SpamAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'Spam_score':
- include_once $dir . '/'.$cls.'.php';
- return false;
- case 'SpamFilter':
- case 'SpamNoticeStream':
- case 'TrainSpamForm':
- case 'TrainHamForm':
- include_once $dir . '/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* When a notice is saved, check its spam score
*
+++ /dev/null
-<?php
- /**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Score of a notice by activity spam service
- *
- * PHP version 5
- *
- * 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 Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Score of a notice per the activity spam service
- *
- * @category Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-
-class Spam_score extends Managed_DataObject
-{
- const MAX_SCALE = 10000;
- public $__table = 'spam_score'; // table name
-
- public $notice_id; // int
- public $score; // float
- public $created; // datetime
-
- function saveNew($notice, $result) {
-
- $score = new Spam_score();
-
- $score->notice_id = $notice->id;
- $score->score = $result->probability;
- $score->is_spam = $result->isSpam;
- $score->scaled = Spam_score::scale($score->score);
- $score->created = common_sql_now();
- $score->notice_created = $notice->created;
-
- $score->insert();
-
- self::blow('spam_score:notice_ids');
-
- return $score;
- }
-
- function save($notice, $result) {
-
- $orig = null;
- $score = Spam_score::getKV('notice_id', $notice->id);
-
- if (empty($score)) {
- $score = new Spam_score();
- } else {
- $orig = clone($score);
- }
-
- $score->notice_id = $notice->id;
- $score->score = $result->probability;
- $score->is_spam = $result->isSpam;
- $score->scaled = Spam_score::scale($score->score);
- $score->created = common_sql_now();
- $score->notice_created = $notice->created;
-
- if (empty($orig)) {
- $score->insert();
- } else {
- $score->update($orig);
- }
-
- self::blow('spam_score:notice_ids');
-
- return $score;
- }
-
- function delete()
- {
- self::blow('spam_score:notice_ids');
- self::blow('spam_score:notice_ids;last');
- parent::delete();
- }
-
- /**
- * The One True Thingy that must be defined and declared.
- */
- public static function schemaDef()
- {
- return array(
- 'description' => 'score of the notice per activityspam',
- 'fields' => array(
- 'notice_id' => array('type' => 'int',
- 'not null' => true,
- 'description' => 'notice getting scored'),
- 'score' => array('type' => 'double',
- 'not null' => true,
- 'description' => 'score for the notice (0.0, 1.0)'),
- 'scaled' => array('type' => 'int',
- 'description' => 'scaled score for the notice (0, 10000)'),
- 'is_spam' => array('type' => 'tinyint',
- 'description' => 'flag for spamosity'),
- 'created' => array('type' => 'datetime',
- 'not null' => true,
- 'description' => 'date this record was created'),
- 'notice_created' => array('type' => 'datetime',
- 'description' => 'date the notice was created'),
- ),
- 'primary key' => array('notice_id'),
- 'foreign keys' => array(
- 'spam_score_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
- ),
- 'indexes' => array(
- 'spam_score_created_idx' => array('created'),
- 'spam_score_scaled_idx' => array('scaled'),
- ),
- );
- }
-
- public static function upgrade()
- {
- Spam_score::upgradeScaled();
- Spam_score::upgradeIsSpam();
- Spam_score::upgradeNoticeCreated();
- }
-
- protected static function upgradeScaled()
- {
- $score = new Spam_score();
- $score->whereAdd('scaled IS NULL');
-
- if ($score->find()) {
- while ($score->fetch()) {
- $orig = clone($score);
- $score->scaled = Spam_score::scale($score->score);
- $score->update($orig);
- }
- }
- }
-
- protected static function upgradeIsSpam()
- {
- $score = new Spam_score();
- $score->whereAdd('is_spam IS NULL');
-
- if ($score->find()) {
- while ($score->fetch()) {
- $orig = clone($score);
- $score->is_spam = ($score->score >= 0.90) ? 1 : 0;
- $score->update($orig);
- }
- }
- }
-
- protected static function upgradeNoticeCreated()
- {
- $score = new Spam_score();
- $score->whereAdd('notice_created IS NULL');
-
- if ($score->find()) {
- while ($score->fetch()) {
- $notice = Notice::getKV('id', $score->notice_id);
- if (!empty($notice)) {
- $orig = clone($score);
- $score->notice_created = $notice->created;
- $score->update($orig);
- }
- }
- }
- }
-
- public static function scale($score)
- {
- $raw = round($score * Spam_score::MAX_SCALE);
- return max(0, min(Spam_score::MAX_SCALE, $raw));
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * Stream of latest spam messages
+ *
+ * PHP version 5
+ *
+ * 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 Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/noticelist.php';
+
+/**
+ * SpamAction
+ *
+ * Shows the latest spam on the service
+ *
+ * @category Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class SpamAction extends Action
+{
+ var $page = null;
+ var $notices = null;
+
+ function title() {
+ return _("Latest Spam");
+ }
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+
+ // User must be logged in.
+
+ $user = common_current_user();
+
+ if (empty($user)) {
+ throw new ClientException(_("You must be logged in to review."), 403);
+ }
+
+ // User must have the right to review spam
+
+ if (!$user->hasRight(ActivitySpamPlugin::REVIEWSPAM)) {
+ throw new ClientException(_('You cannot review spam on this site.'), 403);
+ }
+
+ $stream = new SpamNoticeStream($user->getProfile());
+
+ $this->notices = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
+ NOTICES_PER_PAGE + 1);
+
+ if($this->page > 1 && $this->notices->N == 0) {
+ throw new ClientException(_('No such page.'), 404);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+
+ function handle($argarray=null)
+ {
+ parent::handle($args);
+
+ $this->showPage();
+ }
+
+ /**
+ * Fill the content area
+ *
+ * Shows a list of the notices in the public stream, with some pagination
+ * controls.
+ *
+ * @return void
+ */
+
+ function showContent()
+ {
+ $nl = new NoticeList($this->notices, $this);
+
+ $cnt = $nl->show();
+
+ if ($cnt == 0) {
+ $this->showEmptyList();
+ }
+
+ $this->pagination($this->page > 1,
+ $cnt > NOTICES_PER_PAGE,
+ $this->page,
+ 'spam');
+ }
+
+ function showEmptyList()
+ {
+ // TRANS: Text displayed for public feed when there are no public notices.
+ $message = _('This is the timeline of spam messages for %%site.name%% but none have been detected yet.');
+
+ $this->elementStart('div', 'guide');
+ $this->raw(common_markup_to_html($message));
+ $this->elementEnd('div');
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * Train a notice as spam
+ *
+ * PHP version 5
+ *
+ * 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 Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Train a notice as spam
+ *
+ * @category Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class TrainAction extends Action
+{
+ protected $notice = null;
+ protected $filter = null;
+ protected $category = null;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ // User must be logged in.
+
+ $user = common_current_user();
+
+ if (empty($user)) {
+ throw new ClientException(_("You must be logged in to train spam."), 403);
+ }
+
+ // User must have the right to review spam
+
+ if (!$user->hasRight(ActivitySpamPlugin::TRAINSPAM)) {
+ throw new ClientException(_('You cannot review spam on this site.'), 403);
+ }
+
+ $id = $this->trimmed('notice');
+
+ $this->notice = Notice::getKV('id', $id);
+
+ if (empty($this->notice)) {
+ throw new ClientException(_("No such notice."));
+ }
+
+ $this->checkSessionToken();
+
+ $filter = null;
+
+ Event::handle('GetSpamFilter', array(&$filter));
+
+ if (empty($filter)) {
+ throw new ServerException(_("No spam filter configured."));
+ }
+
+ $this->filter = $filter;
+
+ $this->category = $this->trimmed('category');
+
+ if ($this->category !== SpamFilter::SPAM &&
+ $this->category !== SpamFilter::HAM)
+ {
+ throw new ClientException(_("No such category."));
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+
+ function handle($argarray=null)
+ {
+ // Train
+
+ $this->filter->trainOnError($this->notice, $this->category);
+
+ // Re-test
+
+ $result = $this->filter->test($this->notice);
+
+ // Update or insert
+
+ $score = Spam_score::save($this->notice, $result);
+
+ // Show new toggle form
+
+ if ($this->category === SpamFilter::SPAM) {
+ $form = new TrainHamForm($this, $this->notice);
+ } else {
+ $form = new TrainSpamForm($this, $this->notice);
+ }
+
+ if ($this->boolean('ajax')) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Page title for page on which favorite notices can be unfavourited.
+ $this->element('title', null, _('Disfavor favorite.'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $form->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect(common_local_url('spam'), 303);
+ }
+ }
+}
--- /dev/null
+<?php
+ /**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Score of a notice by activity spam service
+ *
+ * PHP version 5
+ *
+ * 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 Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Score of a notice per the activity spam service
+ *
+ * @category Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+
+class Spam_score extends Managed_DataObject
+{
+ const MAX_SCALE = 10000;
+ public $__table = 'spam_score'; // table name
+
+ public $notice_id; // int
+ public $score; // float
+ public $created; // datetime
+
+ function saveNew($notice, $result) {
+
+ $score = new Spam_score();
+
+ $score->notice_id = $notice->id;
+ $score->score = $result->probability;
+ $score->is_spam = $result->isSpam;
+ $score->scaled = Spam_score::scale($score->score);
+ $score->created = common_sql_now();
+ $score->notice_created = $notice->created;
+
+ $score->insert();
+
+ self::blow('spam_score:notice_ids');
+
+ return $score;
+ }
+
+ function save($notice, $result) {
+
+ $orig = null;
+ $score = Spam_score::getKV('notice_id', $notice->id);
+
+ if (empty($score)) {
+ $score = new Spam_score();
+ } else {
+ $orig = clone($score);
+ }
+
+ $score->notice_id = $notice->id;
+ $score->score = $result->probability;
+ $score->is_spam = $result->isSpam;
+ $score->scaled = Spam_score::scale($score->score);
+ $score->created = common_sql_now();
+ $score->notice_created = $notice->created;
+
+ if (empty($orig)) {
+ $score->insert();
+ } else {
+ $score->update($orig);
+ }
+
+ self::blow('spam_score:notice_ids');
+
+ return $score;
+ }
+
+ function delete()
+ {
+ self::blow('spam_score:notice_ids');
+ self::blow('spam_score:notice_ids;last');
+ parent::delete();
+ }
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'score of the notice per activityspam',
+ 'fields' => array(
+ 'notice_id' => array('type' => 'int',
+ 'not null' => true,
+ 'description' => 'notice getting scored'),
+ 'score' => array('type' => 'double',
+ 'not null' => true,
+ 'description' => 'score for the notice (0.0, 1.0)'),
+ 'scaled' => array('type' => 'int',
+ 'description' => 'scaled score for the notice (0, 10000)'),
+ 'is_spam' => array('type' => 'tinyint',
+ 'description' => 'flag for spamosity'),
+ 'created' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was created'),
+ 'notice_created' => array('type' => 'datetime',
+ 'description' => 'date the notice was created'),
+ ),
+ 'primary key' => array('notice_id'),
+ 'foreign keys' => array(
+ 'spam_score_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
+ ),
+ 'indexes' => array(
+ 'spam_score_created_idx' => array('created'),
+ 'spam_score_scaled_idx' => array('scaled'),
+ ),
+ );
+ }
+
+ public static function upgrade()
+ {
+ Spam_score::upgradeScaled();
+ Spam_score::upgradeIsSpam();
+ Spam_score::upgradeNoticeCreated();
+ }
+
+ protected static function upgradeScaled()
+ {
+ $score = new Spam_score();
+ $score->whereAdd('scaled IS NULL');
+
+ if ($score->find()) {
+ while ($score->fetch()) {
+ $orig = clone($score);
+ $score->scaled = Spam_score::scale($score->score);
+ $score->update($orig);
+ }
+ }
+ }
+
+ protected static function upgradeIsSpam()
+ {
+ $score = new Spam_score();
+ $score->whereAdd('is_spam IS NULL');
+
+ if ($score->find()) {
+ while ($score->fetch()) {
+ $orig = clone($score);
+ $score->is_spam = ($score->score >= 0.90) ? 1 : 0;
+ $score->update($orig);
+ }
+ }
+ }
+
+ protected static function upgradeNoticeCreated()
+ {
+ $score = new Spam_score();
+ $score->whereAdd('notice_created IS NULL');
+
+ if ($score->find()) {
+ while ($score->fetch()) {
+ $notice = Notice::getKV('id', $score->notice_id);
+ if (!empty($notice)) {
+ $orig = clone($score);
+ $score->notice_created = $notice->created;
+ $score->update($orig);
+ }
+ }
+ }
+ }
+
+ public static function scale($score)
+ {
+ $raw = round($score * Spam_score::MAX_SCALE);
+ return max(0, min(Spam_score::MAX_SCALE, $raw));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Toggle indicating spam, click to train as ham
+ *
+ * PHP version 5
+ *
+ * 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 Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form
+ *
+ * @category Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class TrainHamForm extends Form {
+
+ var $notice = null;
+
+ function __construct($out, $notice) {
+ parent::__construct($out);
+ $this->notice = $notice;
+ }
+
+ /**
+ * Name of the form
+ *
+ * Sub-classes should overload this with the name of their form.
+ *
+ * @return void
+ */
+
+ function formLegend()
+ {
+ return _("Train ham");
+ }
+
+ /**
+ * Visible or invisible data elements
+ *
+ * Display the form fields that make up the data of the form.
+ * Sub-classes should overload this to show their data.
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->hidden('notice', $this->notice->id);
+ }
+
+ /**
+ * Buttons for form actions
+ *
+ * Submit and cancel buttons (or whatever)
+ * Sub-classes should overload this to show their own buttons.
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->submit('train-ham-submit-' . $this->notice->id,
+ _('Clear spam'),
+ 'submit',
+ null,
+ _("Clear spam"));
+ }
+
+ /**
+ * ID of the form
+ *
+ * Should be unique on the page. Sub-classes should overload this
+ * to show their own IDs.
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'train-ham-' . $this->notice->id;
+ }
+
+ /**
+ * Action of the form.
+ *
+ * URL to post to. Should be overloaded by subclasses to give
+ * somewhere to post to.
+ *
+ * @return string URL to post to
+ */
+
+ function action()
+ {
+ return common_local_url('train', array('category' => 'ham'));
+ }
+
+ /**
+ * Class of the form. May include space-separated list of multiple classes.
+ *
+ * If 'ajax' is included, the form will automatically be submitted with
+ * an 'ajax=1' parameter added, and the resulting form or error message
+ * will replace the form after submission.
+ *
+ * It's up to you to make sure that the target action supports this!
+ *
+ * @return string the form's class
+ */
+
+ function formClass()
+ {
+ return 'form-train-ham ajax';
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Toggle indicating ham, click to train as spam
+ *
+ * PHP version 5
+ *
+ * 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 Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form
+ *
+ * @category Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class TrainSpamForm extends Form {
+
+ var $notice = null;
+
+ function __construct($out, $notice) {
+ parent::__construct($out);
+ $this->notice = $notice;
+ }
+
+ /**
+ * Name of the form
+ *
+ * Sub-classes should overload this with the name of their form.
+ *
+ * @return void
+ */
+
+ function formLegend()
+ {
+ return _("Train spam");
+ }
+
+ /**
+ * Visible or invisible data elements
+ *
+ * Display the form fields that make up the data of the form.
+ * Sub-classes should overload this to show their data.
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->hidden('notice', $this->notice->id);
+ }
+
+ /**
+ * Buttons for form actions
+ *
+ * Submit and cancel buttons (or whatever)
+ * Sub-classes should overload this to show their own buttons.
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->submit('train-spam-submit-' . $this->notice->id,
+ _('Train spam'),
+ 'submit',
+ null,
+ _("Mark as spam"));
+ }
+
+ /**
+ * ID of the form
+ *
+ * Should be unique on the page. Sub-classes should overload this
+ * to show their own IDs.
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'train-spam-' . $this->notice->id;
+ }
+
+ /**
+ * Action of the form.
+ *
+ * URL to post to. Should be overloaded by subclasses to give
+ * somewhere to post to.
+ *
+ * @return string URL to post to
+ */
+
+ function action()
+ {
+ return common_local_url('train', array('category' => 'spam'));
+ }
+
+ /**
+ * Class of the form. May include space-separated list of multiple classes.
+ *
+ * If 'ajax' is included, the form will automatically be submitted with
+ * an 'ajax=1' parameter added, and the resulting form or error message
+ * will replace the form after submission.
+ *
+ * It's up to you to make sure that the target action supports this!
+ *
+ * @return string the form's class
+ */
+
+ function formClass()
+ {
+ return 'form-train-spam ajax';
+ }
+}
--- /dev/null
+<?php
+ /**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * Spam filter class
+ *
+ * PHP version 5
+ *
+ * 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 Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Spam filter class
+ *
+ * Local proxy for remote filter
+ *
+ * @category Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class SpamFilter extends OAuthClient {
+
+ const HAM = 'ham';
+ const SPAM = 'spam';
+
+ public $server;
+
+ function __construct($server, $consumerKey, $secret) {
+ parent::__construct($consumerKey, $secret);
+ $this->server = $server;
+ }
+
+ protected function toActivity($notice) {
+ // FIXME: need this to autoload ActivityStreamsMediaLink
+ $doc = new ActivityStreamJSONDocument();
+
+ $activity = $notice->asActivity(null);
+
+ return $activity;
+ }
+
+ public function test($notice) {
+
+ $activity = $this->toActivity($notice);
+ return $this->testActivity($activity);
+ }
+
+ public function testActivity($activity) {
+
+ $response = $this->postJSON($this->server . "/is-this-spam", $activity->asArray());
+
+ $result = json_decode($response->getBody());
+
+ return $result;
+ }
+
+ public function train($notice, $category) {
+
+ $activity = $this->toActivity($notice);
+ return $this->trainActivity($activity, $category);
+
+ }
+
+ public function trainActivity($activity, $category) {
+
+ switch ($category) {
+ case self::HAM:
+ $endpoint = '/this-is-ham';
+ break;
+ case self::SPAM:
+ $endpoint = '/this-is-spam';
+ break;
+ default:
+ throw new Exception("Unknown category: " + $category);
+ }
+
+ $response = $this->postJSON($this->server . $endpoint, $activity->asArray());
+
+ // We don't do much with the results
+ return true;
+ }
+
+ public function trainOnError($notice, $category) {
+
+ $activity = $this->toActivity($notice);
+
+ return $this->trainActivityOnError($activity, $category);
+ }
+
+ public function trainActivityOnError($activity, $category) {
+
+ $result = $this->testActivity($activity);
+
+ if (($category === self::SPAM && $result->isSpam) ||
+ ($category === self::HAM && !$result->isSpam)) {
+ return true;
+ } else {
+ return $this->trainActivity($activity, $category);
+ }
+ }
+
+ function postJSON($url, $body)
+ {
+ $request = OAuthRequest::from_consumer_and_token($this->consumer,
+ $this->token,
+ 'POST',
+ $url);
+
+ $request->sign_request($this->sha1_method,
+ $this->consumer,
+ $this->token);
+
+ $hclient = new HTTPClient($url);
+
+ $hclient->setConfig(array('connect_timeout' => 120,
+ 'timeout' => 120,
+ 'follow_redirects' => true,
+ 'ssl_verify_peer' => false,
+ 'ssl_verify_host' => false));
+
+ $hclient->setMethod(HTTP_Request2::METHOD_POST);
+ $hclient->setBody(json_encode($body));
+ $hclient->setHeader('Content-Type', 'application/json');
+ $hclient->setHeader($request->to_header());
+
+ // Twitter is strict about accepting invalid "Expect" headers
+ // No reason not to clear it still here -ESP
+
+ $hclient->setHeader('Expect', '');
+
+ try {
+ $response = $hclient->send();
+ $code = $response->getStatus();
+ if (!$response->isOK()) {
+ throw new OAuthClientException($response->getBody(), $code);
+ }
+ return $response;
+ } catch (Exception $e) {
+ throw new OAuthClientException($e->getMessage(), $e->getCode());
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * Spam notice stream
+ *
+ * PHP version 5
+ *
+ * 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 Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Spam notice stream
+ *
+ * @category Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class SpamNoticeStream extends ScopingNoticeStream
+{
+ function __construct($tag, $profile = -1)
+ {
+ if (is_int($profile) && $profile == -1) {
+ $profile = Profile::current();
+ }
+ parent::__construct(new CachingNoticeStream(new RawSpamNoticeStream(),
+ 'spam_score:notice_ids'));
+ }
+}
+
+/**
+ * Raw stream of spammy notices
+ *
+ * @category Stream
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class RawSpamNoticeStream extends NoticeStream
+{
+ function getNoticeIds($offset, $limit, $since_id, $max_id)
+ {
+ $ss = new Spam_score();
+
+ $ss->is_spam = 1;
+
+ $ss->selectAdd();
+ $ss->selectAdd('notice_id');
+
+ Notice::addWhereSinceId($ss, $since_id, 'notice_id');
+ Notice::addWhereMaxId($ss, $max_id, 'notice_id');
+
+ $ss->orderBy('notice_created DESC, notice_id DESC');
+
+ if (!is_null($offset)) {
+ $ss->limit($offset, $limit);
+ }
+
+ $ids = array();
+
+ if ($ss->find()) {
+ while ($ss->fetch()) {
+ $ids[] = $ss->notice_id;
+ }
+ }
+
+ return $ids;
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2012, StatusNet, Inc.
- *
- * Stream of latest spam messages
- *
- * PHP version 5
- *
- * 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 Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/noticelist.php';
-
-/**
- * SpamAction
- *
- * Shows the latest spam on the service
- *
- * @category Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class SpamAction extends Action
-{
- var $page = null;
- var $notices = null;
-
- function title() {
- return _("Latest Spam");
- }
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
-
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
-
- // User must be logged in.
-
- $user = common_current_user();
-
- if (empty($user)) {
- throw new ClientException(_("You must be logged in to review."), 403);
- }
-
- // User must have the right to review spam
-
- if (!$user->hasRight(ActivitySpamPlugin::REVIEWSPAM)) {
- throw new ClientException(_('You cannot review spam on this site.'), 403);
- }
-
- $stream = new SpamNoticeStream($user->getProfile());
-
- $this->notices = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
- NOTICES_PER_PAGE + 1);
-
- if($this->page > 1 && $this->notices->N == 0) {
- throw new ClientException(_('No such page.'), 404);
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
-
- function handle($argarray=null)
- {
- parent::handle($args);
-
- $this->showPage();
- }
-
- /**
- * Fill the content area
- *
- * Shows a list of the notices in the public stream, with some pagination
- * controls.
- *
- * @return void
- */
-
- function showContent()
- {
- $nl = new NoticeList($this->notices, $this);
-
- $cnt = $nl->show();
-
- if ($cnt == 0) {
- $this->showEmptyList();
- }
-
- $this->pagination($this->page > 1,
- $cnt > NOTICES_PER_PAGE,
- $this->page,
- 'spam');
- }
-
- function showEmptyList()
- {
- // TRANS: Text displayed for public feed when there are no public notices.
- $message = _('This is the timeline of spam messages for %%site.name%% but none have been detected yet.');
-
- $this->elementStart('div', 'guide');
- $this->raw(common_markup_to_html($message));
- $this->elementEnd('div');
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
-
- function isReadOnly($args)
- {
- return true;
- }
-}
+++ /dev/null
-<?php
- /**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2012, StatusNet, Inc.
- *
- * Spam filter class
- *
- * PHP version 5
- *
- * 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 Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Spam filter class
- *
- * Local proxy for remote filter
- *
- * @category Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class SpamFilter extends OAuthClient {
-
- const HAM = 'ham';
- const SPAM = 'spam';
-
- public $server;
-
- function __construct($server, $consumerKey, $secret) {
- parent::__construct($consumerKey, $secret);
- $this->server = $server;
- }
-
- protected function toActivity($notice) {
- // FIXME: need this to autoload ActivityStreamsMediaLink
- $doc = new ActivityStreamJSONDocument();
-
- $activity = $notice->asActivity(null);
-
- return $activity;
- }
-
- public function test($notice) {
-
- $activity = $this->toActivity($notice);
- return $this->testActivity($activity);
- }
-
- public function testActivity($activity) {
-
- $response = $this->postJSON($this->server . "/is-this-spam", $activity->asArray());
-
- $result = json_decode($response->getBody());
-
- return $result;
- }
-
- public function train($notice, $category) {
-
- $activity = $this->toActivity($notice);
- return $this->trainActivity($activity, $category);
-
- }
-
- public function trainActivity($activity, $category) {
-
- switch ($category) {
- case self::HAM:
- $endpoint = '/this-is-ham';
- break;
- case self::SPAM:
- $endpoint = '/this-is-spam';
- break;
- default:
- throw new Exception("Unknown category: " + $category);
- }
-
- $response = $this->postJSON($this->server . $endpoint, $activity->asArray());
-
- // We don't do much with the results
- return true;
- }
-
- public function trainOnError($notice, $category) {
-
- $activity = $this->toActivity($notice);
-
- return $this->trainActivityOnError($activity, $category);
- }
-
- public function trainActivityOnError($activity, $category) {
-
- $result = $this->testActivity($activity);
-
- if (($category === self::SPAM && $result->isSpam) ||
- ($category === self::HAM && !$result->isSpam)) {
- return true;
- } else {
- return $this->trainActivity($activity, $category);
- }
- }
-
- function postJSON($url, $body)
- {
- $request = OAuthRequest::from_consumer_and_token($this->consumer,
- $this->token,
- 'POST',
- $url);
-
- $request->sign_request($this->sha1_method,
- $this->consumer,
- $this->token);
-
- $hclient = new HTTPClient($url);
-
- $hclient->setConfig(array('connect_timeout' => 120,
- 'timeout' => 120,
- 'follow_redirects' => true,
- 'ssl_verify_peer' => false,
- 'ssl_verify_host' => false));
-
- $hclient->setMethod(HTTP_Request2::METHOD_POST);
- $hclient->setBody(json_encode($body));
- $hclient->setHeader('Content-Type', 'application/json');
- $hclient->setHeader($request->to_header());
-
- // Twitter is strict about accepting invalid "Expect" headers
- // No reason not to clear it still here -ESP
-
- $hclient->setHeader('Expect', '');
-
- try {
- $response = $hclient->send();
- $code = $response->getStatus();
- if (!$response->isOK()) {
- throw new OAuthClientException($response->getBody(), $code);
- }
- return $response;
- } catch (Exception $e) {
- throw new OAuthClientException($e->getMessage(), $e->getCode());
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2012, StatusNet, Inc.
- *
- * Spam notice stream
- *
- * PHP version 5
- *
- * 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 Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Spam notice stream
- *
- * @category Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class SpamNoticeStream extends ScopingNoticeStream
-{
- function __construct($tag, $profile = -1)
- {
- if (is_int($profile) && $profile == -1) {
- $profile = Profile::current();
- }
- parent::__construct(new CachingNoticeStream(new RawSpamNoticeStream(),
- 'spam_score:notice_ids'));
- }
-}
-
-/**
- * Raw stream of spammy notices
- *
- * @category Stream
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class RawSpamNoticeStream extends NoticeStream
-{
- function getNoticeIds($offset, $limit, $since_id, $max_id)
- {
- $ss = new Spam_score();
-
- $ss->is_spam = 1;
-
- $ss->selectAdd();
- $ss->selectAdd('notice_id');
-
- Notice::addWhereSinceId($ss, $since_id, 'notice_id');
- Notice::addWhereMaxId($ss, $max_id, 'notice_id');
-
- $ss->orderBy('notice_created DESC, notice_id DESC');
-
- if (!is_null($offset)) {
- $ss->limit($offset, $limit);
- }
-
- $ids = array();
-
- if ($ss->find()) {
- while ($ss->fetch()) {
- $ids[] = $ss->notice_id;
- }
- }
-
- return $ids;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2012, StatusNet, Inc.
- *
- * Train a notice as spam
- *
- * PHP version 5
- *
- * 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 Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Train a notice as spam
- *
- * @category Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class TrainAction extends Action
-{
- protected $notice = null;
- protected $filter = null;
- protected $category = null;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
-
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- // User must be logged in.
-
- $user = common_current_user();
-
- if (empty($user)) {
- throw new ClientException(_("You must be logged in to train spam."), 403);
- }
-
- // User must have the right to review spam
-
- if (!$user->hasRight(ActivitySpamPlugin::TRAINSPAM)) {
- throw new ClientException(_('You cannot review spam on this site.'), 403);
- }
-
- $id = $this->trimmed('notice');
-
- $this->notice = Notice::getKV('id', $id);
-
- if (empty($this->notice)) {
- throw new ClientException(_("No such notice."));
- }
-
- $this->checkSessionToken();
-
- $filter = null;
-
- Event::handle('GetSpamFilter', array(&$filter));
-
- if (empty($filter)) {
- throw new ServerException(_("No spam filter configured."));
- }
-
- $this->filter = $filter;
-
- $this->category = $this->trimmed('category');
-
- if ($this->category !== SpamFilter::SPAM &&
- $this->category !== SpamFilter::HAM)
- {
- throw new ClientException(_("No such category."));
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
-
- function handle($argarray=null)
- {
- // Train
-
- $this->filter->trainOnError($this->notice, $this->category);
-
- // Re-test
-
- $result = $this->filter->test($this->notice);
-
- // Update or insert
-
- $score = Spam_score::save($this->notice, $result);
-
- // Show new toggle form
-
- if ($this->category === SpamFilter::SPAM) {
- $form = new TrainHamForm($this, $this->notice);
- } else {
- $form = new TrainSpamForm($this, $this->notice);
- }
-
- if ($this->boolean('ajax')) {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- // TRANS: Page title for page on which favorite notices can be unfavourited.
- $this->element('title', null, _('Disfavor favorite.'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $form->show();
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- common_redirect(common_local_url('spam'), 303);
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Toggle indicating spam, click to train as ham
- *
- * PHP version 5
- *
- * 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 Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form
- *
- * @category Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class TrainHamForm extends Form {
-
- var $notice = null;
-
- function __construct($out, $notice) {
- parent::__construct($out);
- $this->notice = $notice;
- }
-
- /**
- * Name of the form
- *
- * Sub-classes should overload this with the name of their form.
- *
- * @return void
- */
-
- function formLegend()
- {
- return _("Train ham");
- }
-
- /**
- * Visible or invisible data elements
- *
- * Display the form fields that make up the data of the form.
- * Sub-classes should overload this to show their data.
- *
- * @return void
- */
-
- function formData()
- {
- $this->hidden('notice', $this->notice->id);
- }
-
- /**
- * Buttons for form actions
- *
- * Submit and cancel buttons (or whatever)
- * Sub-classes should overload this to show their own buttons.
- *
- * @return void
- */
-
- function formActions()
- {
- $this->submit('train-ham-submit-' . $this->notice->id,
- _('Clear spam'),
- 'submit',
- null,
- _("Clear spam"));
- }
-
- /**
- * ID of the form
- *
- * Should be unique on the page. Sub-classes should overload this
- * to show their own IDs.
- *
- * @return int ID of the form
- */
-
- function id()
- {
- return 'train-ham-' . $this->notice->id;
- }
-
- /**
- * Action of the form.
- *
- * URL to post to. Should be overloaded by subclasses to give
- * somewhere to post to.
- *
- * @return string URL to post to
- */
-
- function action()
- {
- return common_local_url('train', array('category' => 'ham'));
- }
-
- /**
- * Class of the form. May include space-separated list of multiple classes.
- *
- * If 'ajax' is included, the form will automatically be submitted with
- * an 'ajax=1' parameter added, and the resulting form or error message
- * will replace the form after submission.
- *
- * It's up to you to make sure that the target action supports this!
- *
- * @return string the form's class
- */
-
- function formClass()
- {
- return 'form-train-ham ajax';
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Toggle indicating ham, click to train as spam
- *
- * PHP version 5
- *
- * 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 Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form
- *
- * @category Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class TrainSpamForm extends Form {
-
- var $notice = null;
-
- function __construct($out, $notice) {
- parent::__construct($out);
- $this->notice = $notice;
- }
-
- /**
- * Name of the form
- *
- * Sub-classes should overload this with the name of their form.
- *
- * @return void
- */
-
- function formLegend()
- {
- return _("Train spam");
- }
-
- /**
- * Visible or invisible data elements
- *
- * Display the form fields that make up the data of the form.
- * Sub-classes should overload this to show their data.
- *
- * @return void
- */
-
- function formData()
- {
- $this->hidden('notice', $this->notice->id);
- }
-
- /**
- * Buttons for form actions
- *
- * Submit and cancel buttons (or whatever)
- * Sub-classes should overload this to show their own buttons.
- *
- * @return void
- */
-
- function formActions()
- {
- $this->submit('train-spam-submit-' . $this->notice->id,
- _('Train spam'),
- 'submit',
- null,
- _("Mark as spam"));
- }
-
- /**
- * ID of the form
- *
- * Should be unique on the page. Sub-classes should overload this
- * to show their own IDs.
- *
- * @return int ID of the form
- */
-
- function id()
- {
- return 'train-spam-' . $this->notice->id;
- }
-
- /**
- * Action of the form.
- *
- * URL to post to. Should be overloaded by subclasses to give
- * somewhere to post to.
- *
- * @return string URL to post to
- */
-
- function action()
- {
- return common_local_url('train', array('category' => 'spam'));
- }
-
- /**
- * Class of the form. May include space-separated list of multiple classes.
- *
- * If 'ajax' is included, the form will automatically be submitted with
- * an 'ajax=1' parameter added, and the resulting form or error message
- * will replace the form after submission.
- *
- * It's up to you to make sure that the target action supports this!
- *
- * @return string the form's class
- */
-
- function formClass()
- {
- return 'form-train-spam ajax';
- }
-}
return true;
}
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'AdsenseadminpanelAction':
- require_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- default:
- return true;
- }
- }
-
function onEndAdminPanelNav($menu) {
if (AdminPanelAction::canAdmin('adsense')) {
// TRANS: Menu item title/tooltip
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Adsense administration panel
+ *
+ * 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 Adsense
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Administer adsense settings
+ *
+ * @category Adsense
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class AdsenseadminpanelAction extends AdminPanelAction
+{
+ /**
+ * Returns the page title
+ *
+ * @return string page title
+ */
+ function title()
+ {
+ // TRANS: Title of AdSense administrator panel.
+ return _m('TITLE', 'AdSense');
+ }
+
+ /**
+ * Instructions for using this form.
+ *
+ * @return string instructions
+ */
+ function getInstructions()
+ {
+ // TRANS: Instructions for AdSense administrator panel.
+ return _m('AdSense settings for this StatusNet site');
+ }
+
+ /**
+ * Show the site admin panel form
+ *
+ * @return void
+ */
+ function showForm()
+ {
+ $form = new AdsenseAdminPanelForm($this);
+ $form->show();
+ return;
+ }
+
+ /**
+ * Save settings from the form
+ *
+ * @return void
+ */
+ function saveSettings()
+ {
+ static $settings = array('adsense' => array('adScript', 'client', 'mediumRectangle', 'rectangle', 'leaderboard', 'wideSkyscraper'));
+
+ $values = array();
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ $values[$section][$setting] = $this->trimmed($setting);
+ }
+ }
+
+ // This throws an exception on validation errors
+ $this->validate($values);
+
+ // assert(all values are valid);
+ $config = new Config();
+
+ $config->query('BEGIN');
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ Config::save($section, $setting, $values[$section][$setting]);
+ }
+ }
+
+ $config->query('COMMIT');
+
+ return;
+ }
+
+ function validate(&$values)
+ {
+ }
+}
+
+/**
+ * Form for the adsense admin panel
+ */
+class AdsenseAdminPanelForm extends AdminForm
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'form_adsense_admin_panel';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_adsense';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('adsenseadminpanel');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'adsense_admin'));
+ $this->out->elementStart('ul', 'form_data');
+ $this->li();
+ $this->input('client',
+ // TRANS: Field label in AdSense administration panel.
+ _m('Client ID'),
+ // TRANS: Field title in AdSense administration panel.
+ _m('Google client ID.'),
+ 'adsense');
+ $this->unli();
+ $this->li();
+ $this->input('adScript',
+ // TRANS: Field label in AdSense administration panel.
+ _m('Ad script URL'),
+ // TRANS: Field title in AdSense administration panel.
+ _m('Script URL (advanced).'),
+ 'adsense');
+ $this->unli();
+ $this->li();
+ $this->input('mediumRectangle',
+ // TRANS: Field label in AdSense administration panel.
+ _m('Medium rectangle'),
+ // TRANS: Field title in AdSense administration panel.
+ _m('Medium rectangle slot code.'),
+ 'adsense');
+ $this->unli();
+ $this->li();
+ $this->input('rectangle',
+ // TRANS: Field label in AdSense administration panel.
+ _m('Rectangle'),
+ // TRANS: Field title in AdSense administration panel.
+ _m('Rectangle slot code.'),
+ 'adsense');
+ $this->unli();
+ $this->li();
+ $this->input('leaderboard',
+ // TRANS: Field label in AdSense administration panel.
+ _m('Leaderboard'),
+ // TRANS: Field title in AdSense administration panel.
+ _m('Leaderboard slot code.'),
+ 'adsense');
+ $this->unli();
+ $this->li();
+ $this->input('wideSkyscraper',
+ // TRANS: Field label in AdSense administration panel.
+ _m('Skyscraper'),
+ // TRANS: Field title in AdSense administration panel.
+ _m('Wide skyscraper slot code.'),
+ 'adsense');
+ $this->unli();
+ $this->out->elementEnd('ul');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text to save settings in AdSense administration panel.
+ $this->out->submit('submit', _m('BUTTON','Save'),
+ // TRANS: Button title to save settings in AdSense administration panel.
+ 'submit', null, _m('Save AdSense settings.'));
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Adsense administration panel
- *
- * 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 Adsense
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Administer adsense settings
- *
- * @category Adsense
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class AdsenseadminpanelAction extends AdminPanelAction
-{
- /**
- * Returns the page title
- *
- * @return string page title
- */
- function title()
- {
- // TRANS: Title of AdSense administrator panel.
- return _m('TITLE', 'AdSense');
- }
-
- /**
- * Instructions for using this form.
- *
- * @return string instructions
- */
- function getInstructions()
- {
- // TRANS: Instructions for AdSense administrator panel.
- return _m('AdSense settings for this StatusNet site');
- }
-
- /**
- * Show the site admin panel form
- *
- * @return void
- */
- function showForm()
- {
- $form = new AdsenseAdminPanelForm($this);
- $form->show();
- return;
- }
-
- /**
- * Save settings from the form
- *
- * @return void
- */
- function saveSettings()
- {
- static $settings = array('adsense' => array('adScript', 'client', 'mediumRectangle', 'rectangle', 'leaderboard', 'wideSkyscraper'));
-
- $values = array();
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- $values[$section][$setting] = $this->trimmed($setting);
- }
- }
-
- // This throws an exception on validation errors
- $this->validate($values);
-
- // assert(all values are valid);
- $config = new Config();
-
- $config->query('BEGIN');
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- Config::save($section, $setting, $values[$section][$setting]);
- }
- }
-
- $config->query('COMMIT');
-
- return;
- }
-
- function validate(&$values)
- {
- }
-}
-
-/**
- * Form for the adsense admin panel
- */
-class AdsenseAdminPanelForm extends AdminForm
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'form_adsense_admin_panel';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_adsense';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('adsenseadminpanel');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'adsense_admin'));
- $this->out->elementStart('ul', 'form_data');
- $this->li();
- $this->input('client',
- // TRANS: Field label in AdSense administration panel.
- _m('Client ID'),
- // TRANS: Field title in AdSense administration panel.
- _m('Google client ID.'),
- 'adsense');
- $this->unli();
- $this->li();
- $this->input('adScript',
- // TRANS: Field label in AdSense administration panel.
- _m('Ad script URL'),
- // TRANS: Field title in AdSense administration panel.
- _m('Script URL (advanced).'),
- 'adsense');
- $this->unli();
- $this->li();
- $this->input('mediumRectangle',
- // TRANS: Field label in AdSense administration panel.
- _m('Medium rectangle'),
- // TRANS: Field title in AdSense administration panel.
- _m('Medium rectangle slot code.'),
- 'adsense');
- $this->unli();
- $this->li();
- $this->input('rectangle',
- // TRANS: Field label in AdSense administration panel.
- _m('Rectangle'),
- // TRANS: Field title in AdSense administration panel.
- _m('Rectangle slot code.'),
- 'adsense');
- $this->unli();
- $this->li();
- $this->input('leaderboard',
- // TRANS: Field label in AdSense administration panel.
- _m('Leaderboard'),
- // TRANS: Field title in AdSense administration panel.
- _m('Leaderboard slot code.'),
- 'adsense');
- $this->unli();
- $this->li();
- $this->input('wideSkyscraper',
- // TRANS: Field label in AdSense administration panel.
- _m('Skyscraper'),
- // TRANS: Field title in AdSense administration panel.
- _m('Wide skyscraper slot code.'),
- 'adsense');
- $this->unli();
- $this->out->elementEnd('ul');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text to save settings in AdSense administration panel.
- $this->out->submit('submit', _m('BUTTON','Save'),
- // TRANS: Button title to save settings in AdSense administration panel.
- 'submit', null, _m('Save AdSense settings.'));
- }
-}
case 'Aim':
require_once(INSTALLDIR.'/plugins/Aim/extlib/phptoclib/aimclassw.php');
return false;
- case 'AimManager':
- include_once $dir . '/'.strtolower($cls).'.php';
- return false;
- case 'Fake_Aim':
- include_once $dir . '/'. $cls .'.php';
- return false;
- default:
- return true;
}
+
+ return parent::onAutoload($cls);
}
function onStartImDaemonIoManagers(&$classes)
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Instead of sending AIM messages, retrieve the raw data that would be sent
- *
- * 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 Network
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-class Fake_Aim extends Aim
-{
- public $would_be_sent = null;
-
- function sflapSend($sflap_type, $sflap_data, $no_null, $formatted)
- {
- $this->would_be_sent = array($sflap_type, $sflap_data, $no_null, $formatted);
- }
-}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-/**
- * AIM background connection manager for AIM-using queue handlers,
- * allowing them to send outgoing messages on the right connection.
- *
- * Input is handled during socket select loop, keepalive pings during idle.
- * Any incoming messages will be handled.
- *
- * In a multi-site queuedaemon.php run, one connection will be instantiated
- * for each site being handled by the current process that has XMPP enabled.
- */
-class AimManager extends ImManager
-{
- public $conn = null;
- /**
- * Initialize connection to server.
- * @return boolean true on success
- */
- public function start($master)
- {
- if(parent::start($master))
- {
- $this->connect();
- return true;
- }else{
- return false;
- }
- }
-
- public function getSockets()
- {
- $this->connect();
- if($this->conn){
- return array($this->conn->myConnection);
- }else{
- return array();
- }
- }
-
- /**
- * Process AIM events that have come in over the wire.
- * @param resource $socket
- */
- public function handleInput($socket)
- {
- common_log(LOG_DEBUG, "Servicing the AIM queue.");
- $this->stats('aim_process');
- $this->conn->receive();
- }
-
- function connect()
- {
- if (!$this->conn) {
- $this->conn=new Aim($this->plugin->user,$this->plugin->password,4);
- $this->conn->registerHandler("IMIn",array($this,"handle_aim_message"));
- $this->conn->myServer="toc.oscar.aol.com";
- $this->conn->signon();
- // @todo i18n FIXME: Update translator documentation, please.
- // TRANS: No idea what the use case for this message is.
- $this->conn->setProfile(_m('Send me a message to post a notice'),false);
- }
- return $this->conn;
- }
-
- function handle_aim_message($data)
- {
- $this->plugin->enqueueIncomingRaw($data);
- return true;
- }
-
- function send_raw_message($data)
- {
- $this->connect();
- if (!$this->conn) {
- return false;
- }
- $this->conn->sflapSend($data[0],$data[1],$data[2],$data[3]);
- return true;
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Instead of sending AIM messages, retrieve the raw data that would be sent
+ *
+ * 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 Network
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class Fake_Aim extends Aim
+{
+ public $would_be_sent = null;
+
+ function sflapSend($sflap_type, $sflap_data, $no_null, $formatted)
+ {
+ $this->would_be_sent = array($sflap_type, $sflap_data, $no_null, $formatted);
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+/**
+ * AIM background connection manager for AIM-using queue handlers,
+ * allowing them to send outgoing messages on the right connection.
+ *
+ * Input is handled during socket select loop, keepalive pings during idle.
+ * Any incoming messages will be handled.
+ *
+ * In a multi-site queuedaemon.php run, one connection will be instantiated
+ * for each site being handled by the current process that has XMPP enabled.
+ */
+class AimManager extends ImManager
+{
+ public $conn = null;
+ /**
+ * Initialize connection to server.
+ * @return boolean true on success
+ */
+ public function start($master)
+ {
+ if(parent::start($master))
+ {
+ $this->connect();
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+ public function getSockets()
+ {
+ $this->connect();
+ if($this->conn){
+ return array($this->conn->myConnection);
+ }else{
+ return array();
+ }
+ }
+
+ /**
+ * Process AIM events that have come in over the wire.
+ * @param resource $socket
+ */
+ public function handleInput($socket)
+ {
+ common_log(LOG_DEBUG, "Servicing the AIM queue.");
+ $this->stats('aim_process');
+ $this->conn->receive();
+ }
+
+ function connect()
+ {
+ if (!$this->conn) {
+ $this->conn=new Aim($this->plugin->user,$this->plugin->password,4);
+ $this->conn->registerHandler("IMIn",array($this,"handle_aim_message"));
+ $this->conn->myServer="toc.oscar.aol.com";
+ $this->conn->signon();
+ // @todo i18n FIXME: Update translator documentation, please.
+ // TRANS: No idea what the use case for this message is.
+ $this->conn->setProfile(_m('Send me a message to post a notice'),false);
+ }
+ return $this->conn;
+ }
+
+ function handle_aim_message($data)
+ {
+ $this->plugin->enqueueIncomingRaw($data);
+ return true;
+ }
+
+ function send_raw_message($data)
+ {
+ $this->connect();
+ if (!$this->conn) {
+ return false;
+ }
+ $this->conn->sflapSend($data[0],$data[1],$data[2],$data[3]);
+ return true;
+ }
+}
$action->inlineScript('SN.U.NoticeFavor();');
}
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls) {
- case 'Fave_tally':
- include_once $dir . '/' . $cls . '.php';
- return false;
- case 'AnonFavorAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'AnonDisFavorAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'AnonFavorForm':
- include_once $dir . '/anonfavorform.php';
- return false;
- case 'AnonDisFavorForm':
- include_once $dir . '/anondisfavorform.php';
- return false;
- default:
- return true;
- }
- }
-
function onStartInitializeRouter($m)
{
$m->connect('main/anonfavor', array('action' => 'AnonFavor'));
+++ /dev/null
-<?php
-/**
- * Data class for favorites talley
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for favorites tally
- *
- * A class representing a total number of times a notice has been favored
- *
- * @category Action
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class Fave_tally extends Managed_DataObject
-{
- ###START_AUTOCODE
- /* the code below is auto generated do not remove the above tag */
-
- public $__table = 'fave_tally'; // table name
- public $notice_id; // int(4) primary_key not_null
- public $count; // int(4) not_null
- public $created; // datetime() not_null
- public $modified; // datetime not_null default_0000-00-00%2000%3A00%3A00
-
- /* the code above is auto generated do not remove the tag below */
- ###END_AUTOCODE
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice id'),
- 'count' => array('type' => 'int', 'not null' => true, 'description' => 'the fave tally count'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('notice_id'),
- 'foreign keys' => array(
- 'fave_tally_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
- ),
- );
- }
-
- /**
- * Increment a notice's tally
- *
- * @param integer $noticeID ID of notice we're tallying
- *
- * @return Fave_tally $tally the tally data object
- */
- static function increment($noticeID)
- {
- $tally = Fave_tally::ensureTally($noticeID);
-
- $orig = clone($tally);
- $tally->count++;
- $result = $tally->update($orig);
-
- if (!$result) {
- $msg = sprintf(
- // TRANS: Server exception.
- // TRANS: %d is the notice ID (number).
- _m("Could not update favorite tally for notice ID %d."),
- $noticeID
- );
- throw new ServerException($msg);
- }
-
- return $tally;
- }
-
- /**
- * Decrement a notice's tally
- *
- * @param integer $noticeID ID of notice we're tallying
- *
- * @return Fave_tally $tally the tally data object
- */
- static function decrement($noticeID)
- {
- $tally = Fave_tally::ensureTally($noticeID);
-
- if ($tally->count > 0) {
- $orig = clone($tally);
- $tally->count--;
- $result = $tally->update($orig);
-
- if (!$result) {
- $msg = sprintf(
- // TRANS: Server exception.
- // TRANS: %d is the notice ID (number).
- _m("Could not update favorite tally for notice ID %d."),
- $noticeID
- );
- throw new ServerException($msg);
- }
- }
-
- return $tally;
- }
-
- /**
- * Ensure a tally exists for a given notice. If we can't find
- * one create one with the total number of existing faves
- *
- * @param integer $noticeID
- *
- * @return Fave_tally the tally data object
- */
- static function ensureTally($noticeID)
- {
- $tally = Fave_tally::getKV('notice_id', $noticeID);
-
- if (!$tally) {
- $tally = new Fave_tally();
- $tally->notice_id = $noticeID;
- $tally->count = Fave_tally::countExistingFaves($noticeID);
- $result = $tally->insert();
- if (!$result) {
- $msg = sprintf(
- // TRANS: Server exception.
- // TRANS: %d is the notice ID (number).
- _m("Could not create favorite tally for notice ID %d."),
- $noticeID
- );
- throw new ServerException($msg);
- }
- }
-
- return $tally;
- }
-
- /**
- * Count the number of faves a notice already has. Used to initalize
- * a tally for a notice.
- *
- * @param integer $noticeID ID of the notice to count faves for
- *
- * @return integer $total total number of time the notice has been favored
- */
- static function countExistingFaves($noticeID)
- {
- $fave = new Fave();
- $fave->notice_id = $noticeID;
- $total = $fave->count();
- return $total;
- }
-}
--- /dev/null
+<?php
+/**
+ * Anonymous disfavor action
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Anonymous disfavor class
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class AnonDisfavorAction extends RedirectingAction
+{
+ /**
+ * Class handler.
+ *
+ * @param array $args query arguments
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ $profile = AnonymousFavePlugin::getAnonProfile();
+
+ if (empty($profile) || $_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ // TRANS: Client error.
+ _m('Could not disfavor notice! Please make sure your browser has cookies enabled.')
+ );
+ return;
+ }
+
+ $id = $this->trimmed('notice');
+ $notice = Notice::getKV($id);
+ $token = $this->trimmed('token-' . $notice->id);
+
+ if (!$token || $token != common_session_token()) {
+ // TRANS: Client error.
+ $this->clientError(_m('There was a problem with your session token. Try again, please.'));
+ return;
+ }
+
+ $fave = new Fave();
+ $fave->user_id = $profile->id;
+ $fave->notice_id = $notice->id;
+
+ if (!$fave->find(true)) {
+ // TRANS: Client error.
+ $this->clientError(_m('This notice is not a favorite!'));
+ return;
+ }
+
+ $result = $fave->delete();
+
+ if (!$result) {
+ common_log_db_error($fave, 'DELETE', __FILE__);
+ // TRANS: Server error.
+ $this->serverError(_m('Could not delete favorite.'));
+ return;
+ }
+
+ $profile->blowFavesCache();
+
+ if ($this->boolean('ajax')) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Title.
+ $this->element('title', null, _m('Add to favorites'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $favor = new AnonFavorForm($this, $notice);
+ $favor->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ $this->returnToPrevious();
+ }
+ }
+
+ /**
+ * If returnto not set, return to the public stream.
+ *
+ * @return string URL
+ */
+ function defaultReturnTo()
+ {
+ $returnto = common_get_returnto();
+ if (empty($returnto)) {
+ return common_local_url('public');
+ } else {
+ return $returnto;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Anonyous favor action
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Anonymous favor class
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class AnonFavorAction extends RedirectingAction
+{
+ /**
+ * Class handler.
+ *
+ * @param array $args query arguments
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ $profile = AnonymousFavePlugin::getAnonProfile();
+
+ if (empty($profile) || $_SERVER['REQUEST_METHOD'] != 'POST') {
+ // TRANS: Client error.
+ $this->clientError(_m('Could not favor notice! Please make sure your browser has cookies enabled.')
+ );
+ return;
+ }
+
+ $id = $this->trimmed('notice');
+ $notice = Notice::getKV($id);
+ $token = $this->trimmed('token-' . $notice->id);
+
+ if (empty($token) || $token != common_session_token()) {
+ // TRANS: Client error.
+ $this->clientError(_m('There was a problem with your session token. Try again, please.'));
+ return;
+ }
+
+
+ if ($profile->hasFave($notice)) {
+ // TRANS: Client error.
+ $this->clientError(_m('This notice is already a favorite!'));
+ return;
+ }
+ $fave = Fave::addNew($profile, $notice);
+
+ if (!$fave) {
+ // TRANS: Server error.
+ $this->serverError(_m('Could not create favorite.'));
+ return;
+ }
+
+ $profile->blowFavesCache();
+
+ if ($this->boolean('ajax')) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Title.
+ $this->element('title', null, _m('Disfavor favorite'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $disfavor = new AnonDisFavorForm($this, $notice);
+ $disfavor->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ $this->returnToPrevious();
+ }
+ }
+
+ /**
+ * If returnto not set, return to the public stream.
+ *
+ * @return string URL
+ */
+ function defaultReturnTo()
+ {
+ $returnto = common_get_returnto();
+ if (empty($returnto)) {
+ return common_local_url('public');
+ } else {
+ return $returnto;
+ }
+ }
+}
+++ /dev/null
-<?php
-/**
- * Anonymous disfavor action
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Anonymous disfavor class
- *
- * @category Action
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class AnonDisfavorAction extends RedirectingAction
-{
- /**
- * Class handler.
- *
- * @param array $args query arguments
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- $profile = AnonymousFavePlugin::getAnonProfile();
-
- if (empty($profile) || $_SERVER['REQUEST_METHOD'] != 'POST') {
- $this->clientError(
- // TRANS: Client error.
- _m('Could not disfavor notice! Please make sure your browser has cookies enabled.')
- );
- return;
- }
-
- $id = $this->trimmed('notice');
- $notice = Notice::getKV($id);
- $token = $this->trimmed('token-' . $notice->id);
-
- if (!$token || $token != common_session_token()) {
- // TRANS: Client error.
- $this->clientError(_m('There was a problem with your session token. Try again, please.'));
- return;
- }
-
- $fave = new Fave();
- $fave->user_id = $profile->id;
- $fave->notice_id = $notice->id;
-
- if (!$fave->find(true)) {
- // TRANS: Client error.
- $this->clientError(_m('This notice is not a favorite!'));
- return;
- }
-
- $result = $fave->delete();
-
- if (!$result) {
- common_log_db_error($fave, 'DELETE', __FILE__);
- // TRANS: Server error.
- $this->serverError(_m('Could not delete favorite.'));
- return;
- }
-
- $profile->blowFavesCache();
-
- if ($this->boolean('ajax')) {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- // TRANS: Title.
- $this->element('title', null, _m('Add to favorites'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $favor = new AnonFavorForm($this, $notice);
- $favor->show();
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- $this->returnToPrevious();
- }
- }
-
- /**
- * If returnto not set, return to the public stream.
- *
- * @return string URL
- */
- function defaultReturnTo()
- {
- $returnto = common_get_returnto();
- if (empty($returnto)) {
- return common_local_url('public');
- } else {
- return $returnto;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for disfavoring a notice anonymously
- *
- * 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 Form
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/form.php';
-
-/**
- * Form for disfavoring a notice anonymously
- *
- * @category Form
- * @package StatusNet
- * @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
- * @link http://status.net/
- *
- * @see DisFavorForm
- */
-class AnonDisfavorForm extends DisFavorForm
-{
- /**
- * Constructor
- *
- * @param HTMLOutputter $out output channel
- * @param Notice $notice notice to disfavor
- */
- function __construct($out=null, $notice=null)
- {
- parent::__construct($out, $notice);
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('AnonDisFavor');
- }
-}
+++ /dev/null
-<?php
-/**
- * Anonyous favor action
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Anonymous favor class
- *
- * @category Action
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class AnonFavorAction extends RedirectingAction
-{
- /**
- * Class handler.
- *
- * @param array $args query arguments
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- $profile = AnonymousFavePlugin::getAnonProfile();
-
- if (empty($profile) || $_SERVER['REQUEST_METHOD'] != 'POST') {
- // TRANS: Client error.
- $this->clientError(_m('Could not favor notice! Please make sure your browser has cookies enabled.')
- );
- return;
- }
-
- $id = $this->trimmed('notice');
- $notice = Notice::getKV($id);
- $token = $this->trimmed('token-' . $notice->id);
-
- if (empty($token) || $token != common_session_token()) {
- // TRANS: Client error.
- $this->clientError(_m('There was a problem with your session token. Try again, please.'));
- return;
- }
-
-
- if ($profile->hasFave($notice)) {
- // TRANS: Client error.
- $this->clientError(_m('This notice is already a favorite!'));
- return;
- }
- $fave = Fave::addNew($profile, $notice);
-
- if (!$fave) {
- // TRANS: Server error.
- $this->serverError(_m('Could not create favorite.'));
- return;
- }
-
- $profile->blowFavesCache();
-
- if ($this->boolean('ajax')) {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- // TRANS: Title.
- $this->element('title', null, _m('Disfavor favorite'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $disfavor = new AnonDisFavorForm($this, $notice);
- $disfavor->show();
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- $this->returnToPrevious();
- }
- }
-
- /**
- * If returnto not set, return to the public stream.
- *
- * @return string URL
- */
- function defaultReturnTo()
- {
- $returnto = common_get_returnto();
- if (empty($returnto)) {
- return common_local_url('public');
- } else {
- return $returnto;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for favoring a notice anonymously
- *
- * 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 Form
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 20010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/form.php';
-
-/**
- * Form for favoring a notice anonymously
- *
- * @category Form
- * @package StatusNet
- * @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
- * @link http://status.net/
- *
- * @see AnonDisfavorForm
- */
-class AnonFavorForm extends FavorForm
-{
- /**
- * Constructor
- *
- * @param HTMLOutputter $out output channel
- * @param Notice $notice notice to favor
- */
- function __construct($out=null, $notice=null)
- {
- parent::__construct($out, $notice);
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('AnonFavor');
- }
-}
--- /dev/null
+<?php
+/**
+ * Data class for favorites talley
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for favorites tally
+ *
+ * A class representing a total number of times a notice has been favored
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class Fave_tally extends Managed_DataObject
+{
+ ###START_AUTOCODE
+ /* the code below is auto generated do not remove the above tag */
+
+ public $__table = 'fave_tally'; // table name
+ public $notice_id; // int(4) primary_key not_null
+ public $count; // int(4) not_null
+ public $created; // datetime() not_null
+ public $modified; // datetime not_null default_0000-00-00%2000%3A00%3A00
+
+ /* the code above is auto generated do not remove the tag below */
+ ###END_AUTOCODE
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice id'),
+ 'count' => array('type' => 'int', 'not null' => true, 'description' => 'the fave tally count'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('notice_id'),
+ 'foreign keys' => array(
+ 'fave_tally_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
+ ),
+ );
+ }
+
+ /**
+ * Increment a notice's tally
+ *
+ * @param integer $noticeID ID of notice we're tallying
+ *
+ * @return Fave_tally $tally the tally data object
+ */
+ static function increment($noticeID)
+ {
+ $tally = Fave_tally::ensureTally($noticeID);
+
+ $orig = clone($tally);
+ $tally->count++;
+ $result = $tally->update($orig);
+
+ if (!$result) {
+ $msg = sprintf(
+ // TRANS: Server exception.
+ // TRANS: %d is the notice ID (number).
+ _m("Could not update favorite tally for notice ID %d."),
+ $noticeID
+ );
+ throw new ServerException($msg);
+ }
+
+ return $tally;
+ }
+
+ /**
+ * Decrement a notice's tally
+ *
+ * @param integer $noticeID ID of notice we're tallying
+ *
+ * @return Fave_tally $tally the tally data object
+ */
+ static function decrement($noticeID)
+ {
+ $tally = Fave_tally::ensureTally($noticeID);
+
+ if ($tally->count > 0) {
+ $orig = clone($tally);
+ $tally->count--;
+ $result = $tally->update($orig);
+
+ if (!$result) {
+ $msg = sprintf(
+ // TRANS: Server exception.
+ // TRANS: %d is the notice ID (number).
+ _m("Could not update favorite tally for notice ID %d."),
+ $noticeID
+ );
+ throw new ServerException($msg);
+ }
+ }
+
+ return $tally;
+ }
+
+ /**
+ * Ensure a tally exists for a given notice. If we can't find
+ * one create one with the total number of existing faves
+ *
+ * @param integer $noticeID
+ *
+ * @return Fave_tally the tally data object
+ */
+ static function ensureTally($noticeID)
+ {
+ $tally = Fave_tally::getKV('notice_id', $noticeID);
+
+ if (!$tally) {
+ $tally = new Fave_tally();
+ $tally->notice_id = $noticeID;
+ $tally->count = Fave_tally::countExistingFaves($noticeID);
+ $result = $tally->insert();
+ if (!$result) {
+ $msg = sprintf(
+ // TRANS: Server exception.
+ // TRANS: %d is the notice ID (number).
+ _m("Could not create favorite tally for notice ID %d."),
+ $noticeID
+ );
+ throw new ServerException($msg);
+ }
+ }
+
+ return $tally;
+ }
+
+ /**
+ * Count the number of faves a notice already has. Used to initalize
+ * a tally for a notice.
+ *
+ * @param integer $noticeID ID of the notice to count faves for
+ *
+ * @return integer $total total number of time the notice has been favored
+ */
+ static function countExistingFaves($noticeID)
+ {
+ $fave = new Fave();
+ $fave->notice_id = $noticeID;
+ $total = $fave->count();
+ return $total;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for disfavoring a notice anonymously
+ *
+ * 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 Form
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/form.php';
+
+/**
+ * Form for disfavoring a notice anonymously
+ *
+ * @category Form
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ *
+ * @see DisFavorForm
+ */
+class AnonDisfavorForm extends DisFavorForm
+{
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Notice $notice notice to disfavor
+ */
+ function __construct($out=null, $notice=null)
+ {
+ parent::__construct($out, $notice);
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('AnonDisFavor');
+ }
+}
+
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for favoring a notice anonymously
+ *
+ * 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 Form
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 20010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/form.php';
+
+/**
+ * Form for favoring a notice anonymously
+ *
+ * @category Form
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ *
+ * @see AnonDisfavorForm
+ */
+class AnonFavorForm extends FavorForm
+{
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param Notice $notice notice to favor
+ */
+ function __construct($out=null, $notice=null)
+ {
+ parent::__construct($out, $notice);
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('AnonFavor');
+ }
+}
+
parent::__construct();
}
- function onAutoload($cls)
- {
- switch ($cls)
- {
- case 'AutocompleteAction':
- require_once(INSTALLDIR.'/plugins/Autocomplete/autocomplete.php');
- return false;
- }
- }
-
function onEndShowScripts($action){
if (common_logged_in()) {
$action->element('span', array('id' => 'autocomplete-api',
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List users for autocompletion
+ *
+ * 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
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * List users for autocompletion
+ *
+ * This is the form for adding a new g
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class AutocompleteAction extends Action
+{
+ private $result;
+
+ /**
+ * Last-modified date for page
+ *
+ * When was the content of this page last modified? Based on notice,
+ * profile, avatar.
+ *
+ * @return int last-modified date as unix timestamp
+ */
+ function lastModified()
+ {
+ $max=0;
+ foreach($this->users as $user){
+ $max = max($max,strtotime($user->modified),strtotime($user->getProfile()->modified));
+ }
+ foreach($this->groups as $group){
+ $max = max($max,strtotime($group->modified));
+ }
+ return $max;
+ }
+
+ /**
+ * An entity tag for this page
+ *
+ * Shows the ETag for the page, based on the notice ID and timestamps
+ * for the notice, profile, and avatar. It's weak, since we change
+ * the date text "one hour ago", etc.
+ *
+ * @return string etag
+ */
+ function etag()
+ {
+ return '"' . implode(':', array($this->arg('action'),
+ common_user_cache_hash(),
+ crc32($this->arg('q')), //the actual string can have funny characters in we don't want showing up in the etag
+ $this->arg('limit'),
+ $this->lastModified())) . '"';
+ }
+
+ function prepare($args)
+ {
+ // If we die, show short error messages.
+ StatusNet::setApi(true);
+
+ parent::prepare($args);
+
+ $cur = common_current_user();
+ if (!$cur) {
+ // TRANS: Client exception in autocomplete plugin.
+ throw new ClientException(_m('Access forbidden.'), true);
+ }
+ $this->groups=array();
+ $this->users=array();
+ $q = $this->arg('q');
+ $limit = $this->arg('limit');
+ if($limit > 200) $limit=200; //prevent DOS attacks
+ if(substr($q,0,1)=='@'){
+ //user search
+ $q=substr($q,1);
+ $user = new User();
+ $user->limit($limit);
+ $user->whereAdd('nickname like \'' . trim($user->escape($q), '\'') . '%\'');
+ if($user->find()){
+ while($user->fetch()) {
+ $this->users[]=clone($user);
+ }
+ }
+ }
+ if(substr($q,0,1)=='!'){
+ //group search
+ $q=substr($q,1);
+ $group = new User_group();
+ $group->limit($limit);
+ $group->whereAdd('nickname like \'' . trim($group->escape($q), '\'') . '%\'');
+ if($group->find()){
+ while($group->fetch()) {
+ $this->groups[]=clone($group);
+ }
+ }
+ }
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $results = array();
+ foreach($this->users as $user){
+ $profile = $user->getProfile();
+ $avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
+ // sigh.... encapsulate this upstream!
+ if ($avatar) {
+ $avatar = $avatar->displayUrl();
+ } else {
+ $avatar = Avatar::defaultImage(AVATAR_MINI_SIZE);
+ }
+ $results[] = array(
+ 'nickname' => $user->nickname,
+ 'fullname'=> $profile->fullname,
+ 'avatar' => $avatar,
+ 'type' => 'user'
+ );
+ }
+ foreach($this->groups as $group){
+ // sigh.... encapsulate this upstream!
+ if ($group->mini_logo) {
+ $avatar = $group->mini_logo;
+ } else {
+ $avatar = User_group::defaultLogo(AVATAR_MINI_SIZE);
+ }
+ $results[] = array(
+ 'nickname' => $group->nickname,
+ 'fullname'=> $group->fullname,
+ 'avatar' => $avatar,
+ 'type' => 'group');
+ }
+ foreach($results as $result) {
+ print json_encode($result) . "\n";
+ }
+ }
+
+ /**
+ * Is this action read-only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return true;
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * List users for autocompletion
- *
- * 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
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2008-2009 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * List users for autocompletion
- *
- * This is the form for adding a new g
- *
- * @category Plugin
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class AutocompleteAction extends Action
-{
- private $result;
-
- /**
- * Last-modified date for page
- *
- * When was the content of this page last modified? Based on notice,
- * profile, avatar.
- *
- * @return int last-modified date as unix timestamp
- */
- function lastModified()
- {
- $max=0;
- foreach($this->users as $user){
- $max = max($max,strtotime($user->modified),strtotime($user->getProfile()->modified));
- }
- foreach($this->groups as $group){
- $max = max($max,strtotime($group->modified));
- }
- return $max;
- }
-
- /**
- * An entity tag for this page
- *
- * Shows the ETag for the page, based on the notice ID and timestamps
- * for the notice, profile, and avatar. It's weak, since we change
- * the date text "one hour ago", etc.
- *
- * @return string etag
- */
- function etag()
- {
- return '"' . implode(':', array($this->arg('action'),
- common_user_cache_hash(),
- crc32($this->arg('q')), //the actual string can have funny characters in we don't want showing up in the etag
- $this->arg('limit'),
- $this->lastModified())) . '"';
- }
-
- function prepare($args)
- {
- // If we die, show short error messages.
- StatusNet::setApi(true);
-
- parent::prepare($args);
-
- $cur = common_current_user();
- if (!$cur) {
- // TRANS: Client exception in autocomplete plugin.
- throw new ClientException(_m('Access forbidden.'), true);
- }
- $this->groups=array();
- $this->users=array();
- $q = $this->arg('q');
- $limit = $this->arg('limit');
- if($limit > 200) $limit=200; //prevent DOS attacks
- if(substr($q,0,1)=='@'){
- //user search
- $q=substr($q,1);
- $user = new User();
- $user->limit($limit);
- $user->whereAdd('nickname like \'' . trim($user->escape($q), '\'') . '%\'');
- if($user->find()){
- while($user->fetch()) {
- $this->users[]=clone($user);
- }
- }
- }
- if(substr($q,0,1)=='!'){
- //group search
- $q=substr($q,1);
- $group = new User_group();
- $group->limit($limit);
- $group->whereAdd('nickname like \'' . trim($group->escape($q), '\'') . '%\'');
- if($group->find()){
- while($group->fetch()) {
- $this->groups[]=clone($group);
- }
- }
- }
- return true;
- }
-
- function handle($args)
- {
- parent::handle($args);
- $results = array();
- foreach($this->users as $user){
- $profile = $user->getProfile();
- $avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
- // sigh.... encapsulate this upstream!
- if ($avatar) {
- $avatar = $avatar->displayUrl();
- } else {
- $avatar = Avatar::defaultImage(AVATAR_MINI_SIZE);
- }
- $results[] = array(
- 'nickname' => $user->nickname,
- 'fullname'=> $profile->fullname,
- 'avatar' => $avatar,
- 'type' => 'user'
- );
- }
- foreach($this->groups as $group){
- // sigh.... encapsulate this upstream!
- if ($group->mini_logo) {
- $avatar = $group->mini_logo;
- } else {
- $avatar = User_group::defaultLogo(AVATAR_MINI_SIZE);
- }
- $results[] = array(
- 'nickname' => $group->nickname,
- 'fullname'=> $group->fullname,
- 'avatar' => $avatar,
- 'type' => 'group');
- }
- foreach($results as $result) {
- print json_encode($result) . "\n";
- }
- }
-
- /**
- * Is this action read-only?
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return true;
- }
-}
return true;
}
- /**
- * Automatically load the actions and libraries used by the plugin
- *
- * @param Class $cls the class
- *
- * @return boolean hook return
- *
- */
- function onAutoload($cls)
- {
- $base = dirname(__FILE__);
- $lower = strtolower($cls);
- switch ($lower) {
- case 'bitlyadminpanelaction':
- require_once "$base/$lower.php";
- return false;
- default:
- return true;
- }
- }
-
/**
* Internal hook point to check the default global credentials so
* the admin form knows if we have a fallback or not.
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Admin panel for plugin to use bit.ly URL shortening services.
+ *
+ * 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 Settings
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Administer global bit.ly URL shortener settings
+ *
+ * @category Admin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class BitlyadminpanelAction extends AdminPanelAction
+{
+ /**
+ * Returns the page title
+ *
+ * @return string page title
+ */
+ function title()
+ {
+ // TRANS: Title of administration panel.
+ return _m('bit.ly URL shortening');
+ }
+
+ /**
+ * Instructions for using this form.
+ *
+ * @return string instructions
+ */
+ function getInstructions()
+ {
+ // TRANS: Instructions for administration panel.
+ // TRANS: This message contains Markdown links in the form [decsription](link).
+ return _m('URL shortening with bit.ly requires ' .
+ '[a bit.ly account and API key](http://bit.ly/a/your_api_key). ' .
+ 'This verifies that this is an authorized account, and ' .
+ 'allow you to use bit.ly\'s tracking features and custom domains.');
+ }
+
+ /**
+ * Show the bit.ly admin panel form
+ *
+ * @return void
+ */
+ function showForm()
+ {
+ $form = new BitlyAdminPanelForm($this);
+ $form->show();
+ return;
+ }
+
+ /**
+ * Save settings from the form
+ *
+ * @return void
+ */
+ function saveSettings()
+ {
+ static $settings = array(
+ 'bitly' => array('default_login', 'default_apikey')
+ );
+
+ $values = array();
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ $values[$section][$setting]
+ = $this->trimmed($setting);
+ }
+ }
+
+ // This throws an exception on validation errors
+
+ $this->validate($values);
+
+ // assert(all values are valid);
+
+ $config = new Config();
+
+ $config->query('BEGIN');
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ Config::save($section, $setting, $values[$section][$setting]);
+ }
+ }
+
+ $config->query('COMMIT');
+
+ return;
+ }
+
+ function validate(&$values)
+ {
+ // Validate consumer key and secret (can't be too long)
+
+ if (mb_strlen($values['bitly']['default_apikey']) > 255) {
+ $this->clientError(
+ // TRANS: Client error displayed when using too long a key.
+ _m('Invalid login. Maximum length is 255 characters.')
+ );
+ }
+
+ if (mb_strlen($values['bitly']['default_apikey']) > 255) {
+ $this->clientError(
+ // TRANS: Client error displayed when using too long a key.
+ _m('Invalid API key. Maximum length is 255 characters.')
+ );
+ }
+ }
+}
+
+class BitlyAdminPanelForm extends AdminForm
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'bitlyadminpanel';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('bitlyadminpanel');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart(
+ 'fieldset',
+ array('id' => 'settings_bitly')
+ );
+ // TRANS: Fieldset legend in administration panel for bit.ly username and API key.
+ $this->out->element('legend', null, _m('LEGEND','Credentials'));
+
+ // Do we have global defaults to fall back on?
+ $login = $apiKey = false;
+ Event::handle('BitlyDefaultCredentials', array(&$login, &$apiKey));
+ $haveGlobalDefaults = ($login && $apiKey);
+ if ($login && $apiKey) {
+ $this->out->element('p', 'form_guide',
+ // TRANS: Form guide in administration panel for bit.ly URL shortening.
+ _m('Leave these empty to use global default credentials.'));
+ } else {
+ $this->out->element('p', 'form_guide',
+ // TRANS: Form guide in administration panel for bit.ly URL shortening.
+ _m('If you leave these empty, bit.ly will be unavailable to users.'));
+ }
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->input(
+ 'default_login',
+ // TRANS: Field label in administration panel for bit.ly URL shortening.
+ _m('Login name'),
+ null,
+ 'bitly'
+ );
+ $this->unli();
+
+ $this->li();
+ $this->input(
+ 'default_apikey',
+ // TRANS: Field label in administration panel for bit.ly URL shortening.
+ _m('API key'),
+ null,
+ 'bitly'
+ );
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $this->out->submit('submit',
+ // TRANS: Button text to save setting in administration panel for bit.ly URL shortening.
+ _m('BUTTON','Save'),
+ 'submit',
+ null,
+ // TRANS: Button title to save setting in administration panel for bit.ly URL shortening.
+ _m('Save bit.ly settings'));
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Admin panel for plugin to use bit.ly URL shortening services.
- *
- * 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 Settings
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Administer global bit.ly URL shortener settings
- *
- * @category Admin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class BitlyadminpanelAction extends AdminPanelAction
-{
- /**
- * Returns the page title
- *
- * @return string page title
- */
- function title()
- {
- // TRANS: Title of administration panel.
- return _m('bit.ly URL shortening');
- }
-
- /**
- * Instructions for using this form.
- *
- * @return string instructions
- */
- function getInstructions()
- {
- // TRANS: Instructions for administration panel.
- // TRANS: This message contains Markdown links in the form [decsription](link).
- return _m('URL shortening with bit.ly requires ' .
- '[a bit.ly account and API key](http://bit.ly/a/your_api_key). ' .
- 'This verifies that this is an authorized account, and ' .
- 'allow you to use bit.ly\'s tracking features and custom domains.');
- }
-
- /**
- * Show the bit.ly admin panel form
- *
- * @return void
- */
- function showForm()
- {
- $form = new BitlyAdminPanelForm($this);
- $form->show();
- return;
- }
-
- /**
- * Save settings from the form
- *
- * @return void
- */
- function saveSettings()
- {
- static $settings = array(
- 'bitly' => array('default_login', 'default_apikey')
- );
-
- $values = array();
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- $values[$section][$setting]
- = $this->trimmed($setting);
- }
- }
-
- // This throws an exception on validation errors
-
- $this->validate($values);
-
- // assert(all values are valid);
-
- $config = new Config();
-
- $config->query('BEGIN');
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- Config::save($section, $setting, $values[$section][$setting]);
- }
- }
-
- $config->query('COMMIT');
-
- return;
- }
-
- function validate(&$values)
- {
- // Validate consumer key and secret (can't be too long)
-
- if (mb_strlen($values['bitly']['default_apikey']) > 255) {
- $this->clientError(
- // TRANS: Client error displayed when using too long a key.
- _m('Invalid login. Maximum length is 255 characters.')
- );
- }
-
- if (mb_strlen($values['bitly']['default_apikey']) > 255) {
- $this->clientError(
- // TRANS: Client error displayed when using too long a key.
- _m('Invalid API key. Maximum length is 255 characters.')
- );
- }
- }
-}
-
-class BitlyAdminPanelForm extends AdminForm
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'bitlyadminpanel';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('bitlyadminpanel');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart(
- 'fieldset',
- array('id' => 'settings_bitly')
- );
- // TRANS: Fieldset legend in administration panel for bit.ly username and API key.
- $this->out->element('legend', null, _m('LEGEND','Credentials'));
-
- // Do we have global defaults to fall back on?
- $login = $apiKey = false;
- Event::handle('BitlyDefaultCredentials', array(&$login, &$apiKey));
- $haveGlobalDefaults = ($login && $apiKey);
- if ($login && $apiKey) {
- $this->out->element('p', 'form_guide',
- // TRANS: Form guide in administration panel for bit.ly URL shortening.
- _m('Leave these empty to use global default credentials.'));
- } else {
- $this->out->element('p', 'form_guide',
- // TRANS: Form guide in administration panel for bit.ly URL shortening.
- _m('If you leave these empty, bit.ly will be unavailable to users.'));
- }
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->input(
- 'default_login',
- // TRANS: Field label in administration panel for bit.ly URL shortening.
- _m('Login name'),
- null,
- 'bitly'
- );
- $this->unli();
-
- $this->li();
- $this->input(
- 'default_apikey',
- // TRANS: Field label in administration panel for bit.ly URL shortening.
- _m('API key'),
- null,
- 'bitly'
- );
- $this->unli();
-
- $this->out->elementEnd('ul');
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $this->out->submit('submit',
- // TRANS: Button text to save setting in administration panel for bit.ly URL shortening.
- _m('BUTTON','Save'),
- 'submit',
- null,
- // TRANS: Button title to save setting in administration panel for bit.ly URL shortening.
- _m('Save bit.ly settings'));
- }
-}
return true;
}
- /**
- * Auto-load our classes if called
- *
- * @param string $cls Class to load
- *
- * @return boolean hook return
- */
- function onAutoload($cls)
- {
- switch (strtolower($cls))
- {
- case 'nickname_blacklist':
- case 'homepage_blacklist':
- include_once INSTALLDIR.'/plugins/Blacklist/'.ucfirst($cls).'.php';
- return false;
- case 'blacklistadminpanelaction':
- $base = strtolower(mb_substr($cls, 0, -6));
- include_once INSTALLDIR.'/plugins/Blacklist/'.$base.'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Plugin version data
*
+++ /dev/null
-<?php
-/**
- * Data class for homepage blacklisting
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for Homepage blacklist
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Homepage_blacklist extends Managed_DataObject
-{
- public $__table = 'homepage_blacklist'; // table name
- public $pattern; // varchar(255) pattern
- public $created; // datetime not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'blacklist pattern'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('pattern'),
- );
- }
-
- /**
- * Return a list of patterns to check
- *
- * @return array string patterns to check
- */
- static function getPatterns()
- {
- $patterns = self::cacheGet('homepage_blacklist:patterns');
-
- if ($patterns === false) {
-
- $patterns = array();
-
- $nb = new Homepage_blacklist();
-
- $nb->find();
-
- while ($nb->fetch()) {
- $patterns[] = $nb->pattern;
- }
-
- self::cacheSet('homepage_blacklist:patterns', $patterns);
- }
-
- return $patterns;
- }
-
- /**
- * Save new list of patterns
- *
- * @return array of patterns to check
- */
- static function saveNew($newPatterns)
- {
- $oldPatterns = self::getPatterns();
-
- // Delete stuff that's old that not in new
- $toDelete = array_diff($oldPatterns, $newPatterns);
-
- // Insert stuff that's in new and not in old
- $toInsert = array_diff($newPatterns, $oldPatterns);
-
- foreach ($toDelete as $pattern) {
- $nb = Homepage_blacklist::getKV('pattern', $pattern);
- if (!empty($nb)) {
- $nb->delete();
- }
- }
-
- foreach ($toInsert as $pattern) {
- $nb = new Homepage_blacklist();
- $nb->pattern = $pattern;
- $nb->created = common_sql_now();
- $nb->insert();
- }
-
- self::blow('homepage_blacklist:patterns');
- }
-
- static function ensurePattern($pattern)
- {
- $hb = Homepage_blacklist::getKV('pattern', $pattern);
-
- if (empty($nb)) {
- $hb = new Homepage_blacklist();
- $hb->pattern = $pattern;
- $hb->created = common_sql_now();
- $hb->insert();
- self::blow('homepage_blacklist:patterns');
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * Data class for nickname blacklisting
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for Nickname blacklist
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Nickname_blacklist extends Managed_DataObject
-{
- public $__table = 'nickname_blacklist'; // table name
- public $pattern; // varchar(255) pattern
- public $created; // datetime not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'blacklist pattern'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('pattern'),
- );
- }
-
- /**
- * Return a list of patterns to check
- *
- * @return array string patterns to check
- */
- static function getPatterns()
- {
- $patterns = self::cacheGet('nickname_blacklist:patterns');
-
- if ($patterns === false) {
-
- $patterns = array();
-
- $nb = new Nickname_blacklist();
-
- $nb->find();
-
- while ($nb->fetch()) {
- $patterns[] = $nb->pattern;
- }
-
- self::cacheSet('nickname_blacklist:patterns', $patterns);
- }
-
- return $patterns;
- }
-
- /**
- * Save new list of patterns
- *
- * @return array of patterns to check
- */
- static function saveNew($newPatterns)
- {
- $oldPatterns = self::getPatterns();
-
- // Delete stuff that's old that not in new
- $toDelete = array_diff($oldPatterns, $newPatterns);
-
- // Insert stuff that's in new and not in old
- $toInsert = array_diff($newPatterns, $oldPatterns);
-
- foreach ($toDelete as $pattern) {
- $nb = Nickname_blacklist::getKV('pattern', $pattern);
- if (!empty($nb)) {
- $nb->delete();
- }
- }
-
- foreach ($toInsert as $pattern) {
- $nb = new Nickname_blacklist();
- $nb->pattern = $pattern;
- $nb->created = common_sql_now();
- $nb->insert();
- }
-
- self::blow('nickname_blacklist:patterns');
- }
-
- static function ensurePattern($pattern)
- {
- $nb = Nickname_blacklist::getKV('pattern', $pattern);
-
- if (empty($nb)) {
- $nb = new Nickname_blacklist();
- $nb->pattern = $pattern;
- $nb->created = common_sql_now();
- $nb->insert();
- self::blow('nickname_blacklist:patterns');
- }
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Blacklist administration panel
+ *
+ * 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 Settings
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Administer blacklist
+ *
+ * @category Admin
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+class BlacklistadminpanelAction extends AdminPanelAction
+{
+ /**
+ * title of the admin panel
+ *
+ * @return string title
+ */
+ function title()
+ {
+ // TRANS: Title of blacklist plugin administration panel.
+ return _m('TITLE','Blacklist');
+ }
+
+ /**
+ * Panel instructions
+ *
+ * @return string instructions
+ */
+ function getInstructions()
+ {
+ // TRANS: Instructions for blacklist plugin administration panel.
+ return _m('Blacklisted URLs and nicknames');
+ }
+
+ /**
+ * Show the actual form
+ *
+ * @return void
+ *
+ * @see BlacklistAdminPanelForm
+ */
+ function showForm()
+ {
+ $form = new BlacklistAdminPanelForm($this);
+ $form->show();
+ return;
+ }
+
+ /**
+ * Save the form settings
+ *
+ * @return void
+ */
+ function saveSettings()
+ {
+ $nickPatterns = $this->splitPatterns($this->trimmed('blacklist-nicknames'));
+ Nickname_blacklist::saveNew($nickPatterns);
+
+ $urlPatterns = $this->splitPatterns($this->trimmed('blacklist-urls'));
+ Homepage_blacklist::saveNew($urlPatterns);
+
+ return;
+ }
+
+ protected function splitPatterns($text)
+ {
+ $patterns = array();
+ foreach (explode("\n", $text) as $raw) {
+ $trimmed = trim($raw);
+ if ($trimmed != '') {
+ $patterns[] = $trimmed;
+ }
+ }
+ return $patterns;
+ }
+
+ /**
+ * Validate the values
+ *
+ * @param array &$values 2d array of values to check
+ *
+ * @return boolean success flag
+ */
+ function validate(&$values)
+ {
+ return true;
+ }
+}
+
+/**
+ * Admin panel form for blacklist panel
+ *
+ * @category Admin
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+class BlacklistAdminPanelForm extends Form
+{
+ /**
+ * ID of the form
+ *
+ * @return string ID
+ */
+ function id()
+ {
+ return 'blacklistadminpanel';
+ }
+
+ /**
+ * Class of the form
+ *
+ * @return string class
+ */
+ function formClass()
+ {
+ return 'form_settings';
+ }
+
+ /**
+ * Action we post to
+ *
+ * @return string action URL
+ */
+ function action()
+ {
+ return common_local_url('blacklistadminpanel');
+ }
+
+ /**
+ * Show the form controls
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->out->elementStart('li');
+
+ $nickPatterns = Nickname_blacklist::getPatterns();
+
+ // TRANS: Field label in blacklist plugin administration panel.
+ $this->out->textarea('blacklist-nicknames', _m('Nicknames'),
+ implode("\r\n", $nickPatterns),
+ // TRANS: Field title in blacklist plugin administration panel.
+ _m('Patterns of nicknames to block, one per line.'));
+ $this->out->elementEnd('li');
+
+ $urlPatterns = Homepage_blacklist::getPatterns();
+
+ $this->out->elementStart('li');
+ // TRANS: Field label in blacklist plugin administration panel.
+ $this->out->textarea('blacklist-urls', _m('URLs'),
+ implode("\r\n", $urlPatterns),
+ // TRANS: Field title in blacklist plugin administration panel.
+ _m('Patterns of URLs to block, one per line.'));
+ $this->out->elementEnd('li');
+
+ $this->out->elementEnd('ul');
+ }
+
+ /**
+ * Buttons for submitting
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $this->out->submit('submit',
+ // TRANS: Button text in blacklist plugin administration panel to save settings.
+ _m('BUTTON','Save'),
+ 'submit',
+ null,
+ // TRANS: Button title in blacklist plugin administration panel to save settings.
+ _m('Save site settings.'));
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Blacklist administration panel
- *
- * 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 Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Administer blacklist
- *
- * @category Admin
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-class BlacklistadminpanelAction extends AdminPanelAction
-{
- /**
- * title of the admin panel
- *
- * @return string title
- */
- function title()
- {
- // TRANS: Title of blacklist plugin administration panel.
- return _m('TITLE','Blacklist');
- }
-
- /**
- * Panel instructions
- *
- * @return string instructions
- */
- function getInstructions()
- {
- // TRANS: Instructions for blacklist plugin administration panel.
- return _m('Blacklisted URLs and nicknames');
- }
-
- /**
- * Show the actual form
- *
- * @return void
- *
- * @see BlacklistAdminPanelForm
- */
- function showForm()
- {
- $form = new BlacklistAdminPanelForm($this);
- $form->show();
- return;
- }
-
- /**
- * Save the form settings
- *
- * @return void
- */
- function saveSettings()
- {
- $nickPatterns = $this->splitPatterns($this->trimmed('blacklist-nicknames'));
- Nickname_blacklist::saveNew($nickPatterns);
-
- $urlPatterns = $this->splitPatterns($this->trimmed('blacklist-urls'));
- Homepage_blacklist::saveNew($urlPatterns);
-
- return;
- }
-
- protected function splitPatterns($text)
- {
- $patterns = array();
- foreach (explode("\n", $text) as $raw) {
- $trimmed = trim($raw);
- if ($trimmed != '') {
- $patterns[] = $trimmed;
- }
- }
- return $patterns;
- }
-
- /**
- * Validate the values
- *
- * @param array &$values 2d array of values to check
- *
- * @return boolean success flag
- */
- function validate(&$values)
- {
- return true;
- }
-}
-
-/**
- * Admin panel form for blacklist panel
- *
- * @category Admin
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-class BlacklistAdminPanelForm extends Form
-{
- /**
- * ID of the form
- *
- * @return string ID
- */
- function id()
- {
- return 'blacklistadminpanel';
- }
-
- /**
- * Class of the form
- *
- * @return string class
- */
- function formClass()
- {
- return 'form_settings';
- }
-
- /**
- * Action we post to
- *
- * @return string action URL
- */
- function action()
- {
- return common_local_url('blacklistadminpanel');
- }
-
- /**
- * Show the form controls
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('ul', 'form_data');
-
- $this->out->elementStart('li');
-
- $nickPatterns = Nickname_blacklist::getPatterns();
-
- // TRANS: Field label in blacklist plugin administration panel.
- $this->out->textarea('blacklist-nicknames', _m('Nicknames'),
- implode("\r\n", $nickPatterns),
- // TRANS: Field title in blacklist plugin administration panel.
- _m('Patterns of nicknames to block, one per line.'));
- $this->out->elementEnd('li');
-
- $urlPatterns = Homepage_blacklist::getPatterns();
-
- $this->out->elementStart('li');
- // TRANS: Field label in blacklist plugin administration panel.
- $this->out->textarea('blacklist-urls', _m('URLs'),
- implode("\r\n", $urlPatterns),
- // TRANS: Field title in blacklist plugin administration panel.
- _m('Patterns of URLs to block, one per line.'));
- $this->out->elementEnd('li');
-
- $this->out->elementEnd('ul');
- }
-
- /**
- * Buttons for submitting
- *
- * @return void
- */
- function formActions()
- {
- $this->out->submit('submit',
- // TRANS: Button text in blacklist plugin administration panel to save settings.
- _m('BUTTON','Save'),
- 'submit',
- null,
- // TRANS: Button title in blacklist plugin administration panel to save settings.
- _m('Save site settings.'));
- }
-}
--- /dev/null
+<?php
+/**
+ * Data class for homepage blacklisting
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for Homepage blacklist
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Homepage_blacklist extends Managed_DataObject
+{
+ public $__table = 'homepage_blacklist'; // table name
+ public $pattern; // varchar(255) pattern
+ public $created; // datetime not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'blacklist pattern'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('pattern'),
+ );
+ }
+
+ /**
+ * Return a list of patterns to check
+ *
+ * @return array string patterns to check
+ */
+ static function getPatterns()
+ {
+ $patterns = self::cacheGet('homepage_blacklist:patterns');
+
+ if ($patterns === false) {
+
+ $patterns = array();
+
+ $nb = new Homepage_blacklist();
+
+ $nb->find();
+
+ while ($nb->fetch()) {
+ $patterns[] = $nb->pattern;
+ }
+
+ self::cacheSet('homepage_blacklist:patterns', $patterns);
+ }
+
+ return $patterns;
+ }
+
+ /**
+ * Save new list of patterns
+ *
+ * @return array of patterns to check
+ */
+ static function saveNew($newPatterns)
+ {
+ $oldPatterns = self::getPatterns();
+
+ // Delete stuff that's old that not in new
+ $toDelete = array_diff($oldPatterns, $newPatterns);
+
+ // Insert stuff that's in new and not in old
+ $toInsert = array_diff($newPatterns, $oldPatterns);
+
+ foreach ($toDelete as $pattern) {
+ $nb = Homepage_blacklist::getKV('pattern', $pattern);
+ if (!empty($nb)) {
+ $nb->delete();
+ }
+ }
+
+ foreach ($toInsert as $pattern) {
+ $nb = new Homepage_blacklist();
+ $nb->pattern = $pattern;
+ $nb->created = common_sql_now();
+ $nb->insert();
+ }
+
+ self::blow('homepage_blacklist:patterns');
+ }
+
+ static function ensurePattern($pattern)
+ {
+ $hb = Homepage_blacklist::getKV('pattern', $pattern);
+
+ if (empty($nb)) {
+ $hb = new Homepage_blacklist();
+ $hb->pattern = $pattern;
+ $hb->created = common_sql_now();
+ $hb->insert();
+ self::blow('homepage_blacklist:patterns');
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class for nickname blacklisting
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for Nickname blacklist
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Nickname_blacklist extends Managed_DataObject
+{
+ public $__table = 'nickname_blacklist'; // table name
+ public $pattern; // varchar(255) pattern
+ public $created; // datetime not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'pattern' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'blacklist pattern'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('pattern'),
+ );
+ }
+
+ /**
+ * Return a list of patterns to check
+ *
+ * @return array string patterns to check
+ */
+ static function getPatterns()
+ {
+ $patterns = self::cacheGet('nickname_blacklist:patterns');
+
+ if ($patterns === false) {
+
+ $patterns = array();
+
+ $nb = new Nickname_blacklist();
+
+ $nb->find();
+
+ while ($nb->fetch()) {
+ $patterns[] = $nb->pattern;
+ }
+
+ self::cacheSet('nickname_blacklist:patterns', $patterns);
+ }
+
+ return $patterns;
+ }
+
+ /**
+ * Save new list of patterns
+ *
+ * @return array of patterns to check
+ */
+ static function saveNew($newPatterns)
+ {
+ $oldPatterns = self::getPatterns();
+
+ // Delete stuff that's old that not in new
+ $toDelete = array_diff($oldPatterns, $newPatterns);
+
+ // Insert stuff that's in new and not in old
+ $toInsert = array_diff($newPatterns, $oldPatterns);
+
+ foreach ($toDelete as $pattern) {
+ $nb = Nickname_blacklist::getKV('pattern', $pattern);
+ if (!empty($nb)) {
+ $nb->delete();
+ }
+ }
+
+ foreach ($toInsert as $pattern) {
+ $nb = new Nickname_blacklist();
+ $nb->pattern = $pattern;
+ $nb->created = common_sql_now();
+ $nb->insert();
+ }
+
+ self::blow('nickname_blacklist:patterns');
+ }
+
+ static function ensurePattern($pattern)
+ {
+ $nb = Nickname_blacklist::getKV('pattern', $pattern);
+
+ if (empty($nb)) {
+ $nb = new Nickname_blacklist();
+ $nb->pattern = $pattern;
+ $nb->created = common_sql_now();
+ $nb->insert();
+ self::blow('nickname_blacklist:patterns');
+ }
+ }
+}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'NewblogentryAction':
- case 'ShowblogentryAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'BlogEntryForm':
- case 'BlogEntryListItem':
- include_once $dir . '/'.strtolower($cls).'.php';
- return false;
- case 'Blog_entry':
- include_once $dir . '/'.$cls.'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Map URLs to actions
*
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Data structure for blog entries
- *
- * PHP version 5
- *
- * 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 Blog
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Data structure for blog entries
- *
- * @category Blog
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class Blog_entry extends Managed_DataObject
-{
- public $__table = 'blog_entry';
-
- public $id; // UUID
- public $profile_id; // int
- public $title; // varchar(255)
- public $summary; // text
- public $content; // text
- public $uri; // text
- public $url; // text
- public $created; // datetime
- public $modified; // datetime
-
- const TYPE = ActivityObject::ARTICLE;
-
- static function schemaDef()
- {
- return array(
- 'description' => 'lite blog entry',
- 'fields' => array(
- 'id' => array('type' => 'char',
- 'length' => 36,
- 'not null' => true,
- 'description' => 'Unique ID (UUID)'),
- 'profile_id' => array('type' => 'int',
- 'not null' => true,
- 'description' => 'Author profile ID'),
- 'title' => array('type' => 'varchar',
- 'length' => 255,
- 'description' => 'title of the entry'),
- 'summary' => array('type' => 'text',
- 'description' => 'initial summary'),
- 'content' => array('type' => 'text',
- 'description' => 'HTML content of the entry'),
- 'uri' => array('type' => 'varchar',
- 'length' => 255,
- 'description' => 'URI (probably http://) for this entry'),
- 'url' => array('type' => 'varchar',
- 'length' => 255,
- 'description' => 'URL (probably http://) for this entry'),
- 'created' => array('type' => 'datetime',
- 'not null' => true,
- 'description' => 'date this record was created'),
- 'modified' => array('type' => 'datetime',
- 'not null' => true,
- 'description' => 'date this record was created'),
- ),
- 'primary key' => array('id'),
- 'unique keys' => array(
- 'blog_entry_uri_key' => array('uri'),
- ),
- 'foreign keys' => array(
- 'blog_entry_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
- ),
- 'indexes' => array(
- 'blog_entry_created_idx' => array('created')
- ),
- );
- }
-
- static function saveNew($profile, $title, $content, $options=null)
- {
- if (is_null($options)) {
- $options = array();
- }
-
- $be = new Blog_entry();
- $be->id = (string) new UUID();
- $be->profile_id = $profile->id;
- $be->title = $title; // Note: not HTML-protected
- $be->content = self::purify($content);
-
- if (array_key_exists('summary', $options)) {
- $be->summary = self::purify($options['summary']);
- } else {
- // Already purified
- $be->summary = self::summarize($be->content);
- }
-
- // Don't save an identical summary
-
- if ($be->summary == $be->content) {
- $be->summary = null;
- }
-
- $url = common_local_url('showblogentry', array('id' => $be->id));
-
- if (!array_key_exists('uri', $options)) {
- $options['uri'] = $url;
- }
-
- $be->uri = $options['uri'];
-
- if (!array_key_exists('url', $options)) {
- $options['url'] = $url;
- }
-
- $be->url = $options['url'];
-
- if (!array_key_exists('created', $options)) {
- $be->created = common_sql_now();
- }
-
- $be->created = $options['created'];
-
- $be->modified = common_sql_now();
-
- $be->insert();
-
- // Use user's preferences for short URLs, if possible
-
- try {
- $user = $profile->getUser();
- $shortUrl = File_redirection::makeShort($url,
- empty($user) ? null : $user);
- } catch (Exception $e) {
- // Don't let this stop us.
- $shortUrl = $url;
- }
-
- // XXX: this might be too long.
-
- if (!empty($be->summary)) {
- $options['rendered'] = $be->summary . ' ' .
- XMLStringer::estring('a', array('href' => $url,
- 'class' => 'blog-entry'),
- _('More...'));
- $text = html_entity_decode(strip_tags($be->summary), ENT_QUOTES, 'UTF-8');
- } else {
- $options['rendered'] = $be->content;
- $text = html_entity_decode(strip_tags($be->content), ENT_QUOTES, 'UTF-8');
- }
-
-
- if (Notice::contentTooLong($text)) {
- $text = substr($text, 0, Notice::maxContent() - mb_strlen($shortUrl) - 2) .
- '… ' . $shortUrl;
- }
-
- // Override this no matter what.
-
- $options['object_type'] = self::TYPE;
-
- $source = array_key_exists('source', $options) ?
- $options['source'] : 'web';
-
- $saved = Notice::saveNew($profile->id, $text, $source, $options);
-
- return $saved;
- }
-
- /**
- * Summarize the contents of a blog post
- *
- * We take the first div or paragraph of the blog post if there's a hit;
- * Otherwise we take the whole thing.
- *
- * @param string $html HTML of full content
- */
- static function summarize($html)
- {
- if (preg_match('#<p>.*?</p>#s', $html, $matches)) {
- return $matches[0];
- } else if (preg_match('#<div>.*?</div>#s', $html, $matches)) {
- return $matches[0];
- } else {
- return $html;
- }
- }
-
- static function fromNotice($notice)
- {
- return Blog_entry::getKV('uri', $notice->uri);
- }
-
- function getNotice()
- {
- return Notice::getKV('uri', $this->uri);
- }
-
- function asActivityObject()
- {
- $obj = new ActivityObject();
-
- $obj->id = $this->uri;
- $obj->type = self::TYPE;
- $obj->title = $this->title;
- $obj->summary = $this->summary;
- $obj->content = $this->content;
- $obj->link = $this->url;
-
- return $obj;
- }
-
- /**
- * Clean up input HTML
- */
- static function purify($html)
- {
- require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
-
- $config = array('safe' => 1,
- 'deny_attribute' => 'id,style,on*');
- $pure = htmLawed($html, $config);
-
- return $pure;
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Save a new blog entry
+ *
+ * PHP version 5
+ *
+ * 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 Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Save a new blog entry
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class NewblogentryAction extends Action
+{
+ protected $user;
+ protected $title;
+ protected $content;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ if (!$this->isPost()) {
+ throw new ClientException(_('Must be a POST.'), 405);
+ }
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown when trying to post a blog entry while not logged in.
+ throw new ClientException(_m('Must be logged in to post a blog entry.'),
+ 403);
+ }
+
+ $this->checkSessionToken();
+
+ $this->title = $this->trimmed('title');
+
+ if (empty($this->title)) {
+ // TRANS: Client exception thrown when trying to post a blog entry without providing a title.
+ throw new ClientException(_m('Title required.'));
+ }
+
+ $this->content = $this->trimmed('content');
+
+ if (empty($this->content)) {
+ // TRANS: Client exception thrown when trying to post a blog entry without providing content.
+ throw new ClientException(_m('Content required.'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+
+ function handle($argarray=null)
+ {
+ $options = array();
+
+ // Does the heavy-lifting for getting "To:" information
+
+ ToSelector::fillOptions($this, $options);
+
+ $options['source'] = 'web';
+
+ $profile = $this->user->getProfile();
+
+ $saved = Blog_entry::saveNew($profile,
+ $this->title,
+ $this->content,
+ $options);
+
+ if ($this->boolean('ajax')) {
+ header('Content-Type: text/xml; charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Page title after sending a notice.
+ $this->element('title', null, _m('Blog entry saved'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $nli = new NoticeListItem($saved, $this);
+ $nli->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect($saved->bestUrl(), 303);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Show a blog entry
+ *
+ * PHP version 5
+ *
+ * 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 Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Show a blog entry
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ShowblogentryAction extends ShownoticeAction
+{
+ protected $id;
+ protected $entry;
+
+ function getNotice()
+ {
+ $this->id = $this->trimmed('id');
+
+ $this->entry = Blog_entry::getKV('id', $this->id);
+
+ if (empty($this->entry)) {
+ // TRANS: Client exception thrown when referring to a non-existing blog entry.
+ throw new ClientException(_m('No such entry.'), 404);
+ }
+
+ $notice = $this->entry->getNotice();
+
+ if (empty($notice)) {
+ // TRANS: Client exception thrown when referring to a non-existing blog entry.
+ throw new ClientException(_m('No such entry.'), 404);
+ }
+
+ return $notice;
+ }
+
+ /**
+ * Title of the page
+ *
+ * Used by Action class for layout.
+ *
+ * @return string page tile
+ */
+ function title()
+ {
+ // XXX: check for double-encoding
+ // TRANS: Title for a blog entry without a title.
+ return (empty($this->entry->title)) ? _m('Untitled') : $this->entry->title;
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form for creating a blog entry
- *
- * PHP version 5
- *
- * 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 Blog
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form for creating a blog entry
- *
- * @category Blog
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class BlogEntryForm extends Form
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'form_new_blog_entry';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings ajax-notice';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('newblogentry');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'new_blog_entry_data'));
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->out->input('blog-entry-title',
- // TRANS: Field label on blog entry form.
- _m('LABEL','Title'),
- null,
- // TRANS: Field title on blog entry form.
- _m('Title of the blog entry.'),
- 'title');
- $this->unli();
-
- $this->li();
- $this->out->textarea('blog-entry-content',
- // TRANS: Field label on blog entry form.
- _m('LABEL','Text'),
- null,
- // TRANS: Field title on blog entry form.
- _m('Text of the blog entry.'),
- 'content');
- $this->unli();
-
- $this->out->elementEnd('ul');
-
- $toWidget = new ToSelector($this->out,
- common_current_user(),
- null);
- $toWidget->show();
-
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $this->out->submit('blog-entry-submit',
- // TRANS: Button text to save a blog entry.
- _m('BUTTON', 'Save'),
- 'submit',
- 'submit');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * NoticeListItem adapter for blog entries
- *
- * PHP version 5
- *
- * 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 Blog
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * NoticeListItem adapter for blog entries
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class BlogEntryListItem extends NoticeListItemAdapter
-{
- function showNotice()
- {
- $out = $this->nli->out;
- $out->elementStart('div', 'entry-title');
- $this->showAuthor();
- $this->showContent();
- $out->elementEnd('div');
- }
-
- function showContent()
- {
- $notice = $this->nli->notice;
- $out = $this->nli->out;
-
- $entry = Blog_entry::fromNotice($notice);
-
- if (empty($entry)) {
- throw new Exception('BlogEntryListItem used for non-blog notice.');
- }
-
- $out->elementStart('h4', array('class' => 'blog-entry-title'));
- $out->element('a', array('href' => $notice->bestUrl()), $entry->title);
- $out->elementEnd('h4');
-
- // XXX: kind of a hack
-
- $actionName = $out->trimmed('action');
-
- if ($actionName == 'shownotice' ||
- $actionName == 'showblogentry' ||
- $actionName == 'conversation') {
-
- $out->elementStart('div', 'blog-entry-content');
- $out->raw($entry->content);
- $out->elementEnd('div');
-
- } else {
-
- if (!empty($entry->summary)) {
- $out->elementStart('div', 'blog-entry-summary');
- $out->raw($entry->summary);
- $out->elementEnd('div');
- }
-
- $url = ($entry->url) ? $entry->url : $notice->bestUrl();
- $out->element('a',
- array('href' => $url,
- 'class' => 'blog-entry-link'),
- _('More...'));
- }
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Data structure for blog entries
+ *
+ * PHP version 5
+ *
+ * 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 Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Data structure for blog entries
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class Blog_entry extends Managed_DataObject
+{
+ public $__table = 'blog_entry';
+
+ public $id; // UUID
+ public $profile_id; // int
+ public $title; // varchar(255)
+ public $summary; // text
+ public $content; // text
+ public $uri; // text
+ public $url; // text
+ public $created; // datetime
+ public $modified; // datetime
+
+ const TYPE = ActivityObject::ARTICLE;
+
+ static function schemaDef()
+ {
+ return array(
+ 'description' => 'lite blog entry',
+ 'fields' => array(
+ 'id' => array('type' => 'char',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'Unique ID (UUID)'),
+ 'profile_id' => array('type' => 'int',
+ 'not null' => true,
+ 'description' => 'Author profile ID'),
+ 'title' => array('type' => 'varchar',
+ 'length' => 255,
+ 'description' => 'title of the entry'),
+ 'summary' => array('type' => 'text',
+ 'description' => 'initial summary'),
+ 'content' => array('type' => 'text',
+ 'description' => 'HTML content of the entry'),
+ 'uri' => array('type' => 'varchar',
+ 'length' => 255,
+ 'description' => 'URI (probably http://) for this entry'),
+ 'url' => array('type' => 'varchar',
+ 'length' => 255,
+ 'description' => 'URL (probably http://) for this entry'),
+ 'created' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was created'),
+ ),
+ 'primary key' => array('id'),
+ 'unique keys' => array(
+ 'blog_entry_uri_key' => array('uri'),
+ ),
+ 'foreign keys' => array(
+ 'blog_entry_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
+ ),
+ 'indexes' => array(
+ 'blog_entry_created_idx' => array('created')
+ ),
+ );
+ }
+
+ static function saveNew($profile, $title, $content, $options=null)
+ {
+ if (is_null($options)) {
+ $options = array();
+ }
+
+ $be = new Blog_entry();
+ $be->id = (string) new UUID();
+ $be->profile_id = $profile->id;
+ $be->title = $title; // Note: not HTML-protected
+ $be->content = self::purify($content);
+
+ if (array_key_exists('summary', $options)) {
+ $be->summary = self::purify($options['summary']);
+ } else {
+ // Already purified
+ $be->summary = self::summarize($be->content);
+ }
+
+ // Don't save an identical summary
+
+ if ($be->summary == $be->content) {
+ $be->summary = null;
+ }
+
+ $url = common_local_url('showblogentry', array('id' => $be->id));
+
+ if (!array_key_exists('uri', $options)) {
+ $options['uri'] = $url;
+ }
+
+ $be->uri = $options['uri'];
+
+ if (!array_key_exists('url', $options)) {
+ $options['url'] = $url;
+ }
+
+ $be->url = $options['url'];
+
+ if (!array_key_exists('created', $options)) {
+ $be->created = common_sql_now();
+ }
+
+ $be->created = $options['created'];
+
+ $be->modified = common_sql_now();
+
+ $be->insert();
+
+ // Use user's preferences for short URLs, if possible
+
+ try {
+ $user = $profile->getUser();
+ $shortUrl = File_redirection::makeShort($url,
+ empty($user) ? null : $user);
+ } catch (Exception $e) {
+ // Don't let this stop us.
+ $shortUrl = $url;
+ }
+
+ // XXX: this might be too long.
+
+ if (!empty($be->summary)) {
+ $options['rendered'] = $be->summary . ' ' .
+ XMLStringer::estring('a', array('href' => $url,
+ 'class' => 'blog-entry'),
+ _('More...'));
+ $text = html_entity_decode(strip_tags($be->summary), ENT_QUOTES, 'UTF-8');
+ } else {
+ $options['rendered'] = $be->content;
+ $text = html_entity_decode(strip_tags($be->content), ENT_QUOTES, 'UTF-8');
+ }
+
+
+ if (Notice::contentTooLong($text)) {
+ $text = substr($text, 0, Notice::maxContent() - mb_strlen($shortUrl) - 2) .
+ '… ' . $shortUrl;
+ }
+
+ // Override this no matter what.
+
+ $options['object_type'] = self::TYPE;
+
+ $source = array_key_exists('source', $options) ?
+ $options['source'] : 'web';
+
+ $saved = Notice::saveNew($profile->id, $text, $source, $options);
+
+ return $saved;
+ }
+
+ /**
+ * Summarize the contents of a blog post
+ *
+ * We take the first div or paragraph of the blog post if there's a hit;
+ * Otherwise we take the whole thing.
+ *
+ * @param string $html HTML of full content
+ */
+ static function summarize($html)
+ {
+ if (preg_match('#<p>.*?</p>#s', $html, $matches)) {
+ return $matches[0];
+ } else if (preg_match('#<div>.*?</div>#s', $html, $matches)) {
+ return $matches[0];
+ } else {
+ return $html;
+ }
+ }
+
+ static function fromNotice($notice)
+ {
+ return Blog_entry::getKV('uri', $notice->uri);
+ }
+
+ function getNotice()
+ {
+ return Notice::getKV('uri', $this->uri);
+ }
+
+ function asActivityObject()
+ {
+ $obj = new ActivityObject();
+
+ $obj->id = $this->uri;
+ $obj->type = self::TYPE;
+ $obj->title = $this->title;
+ $obj->summary = $this->summary;
+ $obj->content = $this->content;
+ $obj->link = $this->url;
+
+ return $obj;
+ }
+
+ /**
+ * Clean up input HTML
+ */
+ static function purify($html)
+ {
+ require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
+
+ $config = array('safe' => 1,
+ 'deny_attribute' => 'id,style,on*');
+ $pure = htmLawed($html, $config);
+
+ return $pure;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for creating a blog entry
+ *
+ * PHP version 5
+ *
+ * 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 Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form for creating a blog entry
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class BlogEntryForm extends Form
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'form_new_blog_entry';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings ajax-notice';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('newblogentry');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'new_blog_entry_data'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('blog-entry-title',
+ // TRANS: Field label on blog entry form.
+ _m('LABEL','Title'),
+ null,
+ // TRANS: Field title on blog entry form.
+ _m('Title of the blog entry.'),
+ 'title');
+ $this->unli();
+
+ $this->li();
+ $this->out->textarea('blog-entry-content',
+ // TRANS: Field label on blog entry form.
+ _m('LABEL','Text'),
+ null,
+ // TRANS: Field title on blog entry form.
+ _m('Text of the blog entry.'),
+ 'content');
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+
+ $toWidget = new ToSelector($this->out,
+ common_current_user(),
+ null);
+ $toWidget->show();
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $this->out->submit('blog-entry-submit',
+ // TRANS: Button text to save a blog entry.
+ _m('BUTTON', 'Save'),
+ 'submit',
+ 'submit');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * NoticeListItem adapter for blog entries
+ *
+ * PHP version 5
+ *
+ * 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 Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * NoticeListItem adapter for blog entries
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class BlogEntryListItem extends NoticeListItemAdapter
+{
+ function showNotice()
+ {
+ $out = $this->nli->out;
+ $out->elementStart('div', 'entry-title');
+ $this->showAuthor();
+ $this->showContent();
+ $out->elementEnd('div');
+ }
+
+ function showContent()
+ {
+ $notice = $this->nli->notice;
+ $out = $this->nli->out;
+
+ $entry = Blog_entry::fromNotice($notice);
+
+ if (empty($entry)) {
+ throw new Exception('BlogEntryListItem used for non-blog notice.');
+ }
+
+ $out->elementStart('h4', array('class' => 'blog-entry-title'));
+ $out->element('a', array('href' => $notice->bestUrl()), $entry->title);
+ $out->elementEnd('h4');
+
+ // XXX: kind of a hack
+
+ $actionName = $out->trimmed('action');
+
+ if ($actionName == 'shownotice' ||
+ $actionName == 'showblogentry' ||
+ $actionName == 'conversation') {
+
+ $out->elementStart('div', 'blog-entry-content');
+ $out->raw($entry->content);
+ $out->elementEnd('div');
+
+ } else {
+
+ if (!empty($entry->summary)) {
+ $out->elementStart('div', 'blog-entry-summary');
+ $out->raw($entry->summary);
+ $out->elementEnd('div');
+ }
+
+ $url = ($entry->url) ? $entry->url : $notice->bestUrl();
+ $out->element('a',
+ array('href' => $url,
+ 'class' => 'blog-entry-link'),
+ _('More...'));
+ }
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Save a new blog entry
- *
- * PHP version 5
- *
- * 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 Blog
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Save a new blog entry
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class NewblogentryAction extends Action
-{
- protected $user;
- protected $title;
- protected $content;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
-
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- if (!$this->isPost()) {
- throw new ClientException(_('Must be a POST.'), 405);
- }
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Client exception thrown when trying to post a blog entry while not logged in.
- throw new ClientException(_m('Must be logged in to post a blog entry.'),
- 403);
- }
-
- $this->checkSessionToken();
-
- $this->title = $this->trimmed('title');
-
- if (empty($this->title)) {
- // TRANS: Client exception thrown when trying to post a blog entry without providing a title.
- throw new ClientException(_m('Title required.'));
- }
-
- $this->content = $this->trimmed('content');
-
- if (empty($this->content)) {
- // TRANS: Client exception thrown when trying to post a blog entry without providing content.
- throw new ClientException(_m('Content required.'));
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
-
- function handle($argarray=null)
- {
- $options = array();
-
- // Does the heavy-lifting for getting "To:" information
-
- ToSelector::fillOptions($this, $options);
-
- $options['source'] = 'web';
-
- $profile = $this->user->getProfile();
-
- $saved = Blog_entry::saveNew($profile,
- $this->title,
- $this->content,
- $options);
-
- if ($this->boolean('ajax')) {
- header('Content-Type: text/xml; charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: Page title after sending a notice.
- $this->element('title', null, _m('Blog entry saved'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $nli = new NoticeListItem($saved, $this);
- $nli->show();
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- common_redirect($saved->bestUrl(), 303);
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Show a blog entry
- *
- * PHP version 5
- *
- * 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 Blog
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Show a blog entry
- *
- * @category Blog
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ShowblogentryAction extends ShownoticeAction
-{
- protected $id;
- protected $entry;
-
- function getNotice()
- {
- $this->id = $this->trimmed('id');
-
- $this->entry = Blog_entry::getKV('id', $this->id);
-
- if (empty($this->entry)) {
- // TRANS: Client exception thrown when referring to a non-existing blog entry.
- throw new ClientException(_m('No such entry.'), 404);
- }
-
- $notice = $this->entry->getNotice();
-
- if (empty($notice)) {
- // TRANS: Client exception thrown when referring to a non-existing blog entry.
- throw new ClientException(_m('No such entry.'), 404);
- }
-
- return $notice;
- }
-
- /**
- * Title of the page
- *
- * Used by Action class for layout.
- *
- * @return string page tile
- */
- function title()
- {
- // XXX: check for double-encoding
- // TRANS: Title for a blog entry without a title.
- return (empty($this->entry->title)) ? _m('Untitled') : $this->entry->title;
- }
-}
+++ /dev/null
-<?php
-/**
- * Data class to mark notices as bookmarks
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * For storing the fact that a notice is a bookmark
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Bookmark extends Managed_DataObject
-{
- public $__table = 'bookmark'; // table name
- public $id; // char(36) primary_key not_null
- public $profile_id; // int(4) not_null
- public $url; // varchar(255) not_null
- public $title; // varchar(255)
- public $description; // text
- public $uri; // varchar(255)
- public $created; // datetime
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'id' => array('type' => 'char',
- 'length' => 36,
- 'not null' => true),
- 'profile_id' => array('type' => 'int', 'not null' => true),
- 'uri' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true),
- 'url' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true),
- 'title' => array('type' => 'varchar', 'length' => 255),
- 'description' => array('type' => 'text'),
- 'created' => array('type' => 'datetime', 'not null' => true),
- ),
- 'primary key' => array('id'),
- 'unique keys' => array(
- 'bookmark_uri_key' => array('uri'),
- ),
- 'foreign keys' => array(
- 'bookmark_profile_id_fkey' => array('profile', array('profile_id' => 'id'))
- ),
- 'indexes' => array('bookmark_created_idx' => array('created'),
- 'bookmark_url_idx' => array('url'),
- 'bookmark_profile_id_idx' => array('profile_id'),
- ),
- );
- }
-
- /**
- * Get a bookmark based on a notice
- *
- * @param Notice $notice Notice to check for
- *
- * @return Bookmark found bookmark or null
- */
- static function getByNotice($notice)
- {
- return self::getKV('uri', $notice->uri);
- }
-
- /**
- * Get the bookmark that a user made for an URL
- *
- * @param Profile $profile Profile to check for
- * @param string $url URL to check for
- *
- * @return Bookmark bookmark found or null
- */
- static function getByURL($profile, $url)
- {
- $nb = new Bookmark();
-
- $nb->profile_id = $profile->id;
- $nb->url = $url;
-
- if ($nb->find(true)) {
- return $nb;
- } else {
- return null;
- }
- }
-
- /**
- * Save a new notice bookmark
- *
- * @param Profile $profile To save the bookmark for
- * @param string $title Title of the bookmark
- * @param string $url URL of the bookmark
- * @param mixed $rawtags array of tags or string
- * @param string $description Description of the bookmark
- * @param array $options Options for the Notice::saveNew()
- *
- * @return Notice saved notice
- */
- static function saveNew($profile, $title, $url, $rawtags, $description,
- $options=null)
- {
- $nb = self::getByURL($profile, $url);
-
- if (!empty($nb)) {
- // TRANS: Client exception thrown when trying to save a new bookmark that already exists.
- throw new ClientException(_m('Bookmark already exists.'));
- }
-
- if (empty($options)) {
- $options = array();
- }
-
- if (array_key_exists('uri', $options)) {
- $other = Bookmark::getKV('uri', $options['uri']);
- if (!empty($other)) {
- // TRANS: Client exception thrown when trying to save a new bookmark that already exists.
- throw new ClientException(_m('Bookmark already exists.'));
- }
- }
-
- if (is_string($rawtags)) {
- if (empty($rawtags)) {
- $rawtags = array();
- } else {
- $rawtags = preg_split('/[\s,]+/', $rawtags);
- }
- }
-
- $nb = new Bookmark();
-
- $nb->id = UUID::gen();
- $nb->profile_id = $profile->id;
- $nb->url = $url;
- $nb->title = $title;
- $nb->description = $description;
-
- if (array_key_exists('created', $options)) {
- $nb->created = $options['created'];
- } else {
- $nb->created = common_sql_now();
- }
-
- if (array_key_exists('uri', $options)) {
- $nb->uri = $options['uri'];
- } else {
- // FIXME: hacks to work around router bugs in
- // queue daemons
-
- $r = Router::get();
-
- $path = $r->build('showbookmark',
- array('id' => $nb->id));
-
- if (empty($path)) {
- $nb->uri = common_path('bookmark/'.$nb->id, false, false);
- } else {
- $nb->uri = common_local_url('showbookmark',
- array('id' => $nb->id),
- null,
- null,
- false);
- }
- }
-
- $nb->insert();
-
- $tags = array();
- $replies = array();
-
- // filter "for:nickname" tags
-
- foreach ($rawtags as $tag) {
- if (strtolower(mb_substr($tag, 0, 4)) == 'for:') {
- // skip if done by caller
- if (!array_key_exists('replies', $options)) {
- $nickname = mb_substr($tag, 4);
- $other = common_relative_profile($profile,
- $nickname);
- if (!empty($other)) {
- $replies[] = $other->getUri();
- }
- }
- } else {
- $tags[] = common_canonical_tag($tag);
- }
- }
-
- $hashtags = array();
- $taglinks = array();
-
- foreach ($tags as $tag) {
- $hashtags[] = '#'.$tag;
- $attrs = array('href' => Notice_tag::url($tag),
- 'rel' => $tag,
- 'class' => 'tag');
- $taglinks[] = XMLStringer::estring('a', $attrs, $tag);
- }
-
- // Use user's preferences for short URLs, if possible
-
- try {
- $user = User::getKV('id', $profile->id);
-
- $shortUrl = File_redirection::makeShort($url,
- empty($user) ? null : $user);
- } catch (Exception $e) {
- // Don't let this stop us.
- $shortUrl = $url;
- }
-
- // TRANS: Bookmark content.
- // TRANS: %1$s is a title, %2$s is a short URL, %3$s is the bookmark description,
- // TRANS: %4$s is space separated list of hash tags.
- $content = sprintf(_m('"%1$s" %2$s %3$s %4$s'),
- $title,
- $shortUrl,
- $description,
- implode(' ', $hashtags));
-
- // TRANS: Rendered bookmark content.
- // TRANS: %1$s is a URL, %2$s the bookmark title, %3$s is the bookmark description,
- // TRANS: %4$s is space separated list of hash tags.
- $rendered = sprintf(_m('<span class="xfolkentry">'.
- '<a class="taggedlink" href="%1$s">%2$s</a> '.
- '<span class="description">%3$s</span> '.
- '<span class="meta">%4$s</span>'.
- '</span>'),
- htmlspecialchars($url),
- htmlspecialchars($title),
- htmlspecialchars($description),
- implode(' ', $taglinks));
-
- $options = array_merge(array('urls' => array($url),
- 'rendered' => $rendered,
- 'tags' => $tags,
- 'replies' => $replies,
- 'object_type' => ActivityObject::BOOKMARK),
- $options);
-
- if (!array_key_exists('uri', $options)) {
- $options['uri'] = $nb->uri;
- }
-
- try {
- $saved = Notice::saveNew($profile->id,
- $content,
- array_key_exists('source', $options) ?
- $options['source'] : 'web',
- $options);
- } catch (Exception $e) {
- $nb->delete();
- throw $e;
- }
-
- if (empty($saved)) {
- $nb->delete();
- }
-
- return $saved;
- }
-}
$action->script($this->path('js/bookmark.js'));
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'BookmarksAction':
- case 'BookmarksrssAction':
- case 'ApiTimelineBookmarksAction':
- case 'ShowbookmarkAction':
- case 'NewbookmarkAction':
- case 'BookmarkpopupAction':
- case 'NoticebyurlAction':
- case 'BookmarkforurlAction':
- case 'ImportdeliciousAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'Bookmark':
- include_once $dir.'/'.$cls.'.php';
- return false;
- case 'BookmarkListItem':
- case 'BookmarkForm':
- case 'InitialBookmarkForm':
- case 'DeliciousBackupImporter':
- case 'DeliciousBookmarkImporter':
- include_once $dir.'/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
- }
- }
/**
* Map URLs to actions
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a user's favorite notices
+ *
+ * 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 API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009-2010 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/apibareauth.php';
+
+/**
+ * Returns the 20 most recent favorite notices for the authenticating user or user
+ * specified by the ID parameter in the requested format.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@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
+ * @link http://status.net/
+ */
+class ApiTimelineBookmarksAction extends ApiBareAuthAction
+{
+ var $notices = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->getTargetUser($this->arg('id'));
+
+ if (empty($this->user)) {
+ // TRANS: Client error displayed when requesting most recent favourite notices by a user for a non-existing user.
+ $this->clientError(_('No such user.'), 404, $this->format);
+ return;
+ }
+
+ $this->notices = $this->getNotices();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Just show the notices
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showTimeline();
+ }
+
+ /**
+ * Show the timeline of notices
+ *
+ * @return void
+ */
+ function showTimeline()
+ {
+ $profile = $this->user->getProfile();
+ $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(
+ // TRANS: Title for timeline of most recent favourite notices by a user.
+ // TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname.
+ _('%1$s / Bookmarks from %2$s'),
+ $sitename,
+ $this->user->nickname
+ );
+
+ $taguribase = TagURI::base();
+ $id = "tag:$taguribase:Bookmarks:" . $this->user->id;
+
+ $subtitle = sprintf(
+ // TRANS: Subtitle for timeline of most recent favourite notices by a user.
+ // TRANS: %1$s is the StatusNet sitename, %2$s is a user's full name,
+ // TRANS: %3$s is a user nickname.
+ _('%1$s updates bookmarked by %2$s / %3$s.'),
+ $sitename,
+ $profile->getBestName(),
+ $this->user->nickname
+ );
+ $logo = !empty($avatar)
+ ? $avatar->displayUrl()
+ : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
+
+ $link = common_local_url(
+ 'bookmarks',
+ array('nickname' => $this->user->nickname)
+ );
+
+ $self = $this->getSelfUri();
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlTimeline($this->notices);
+ break;
+ case 'rss':
+ $this->showRssTimeline(
+ $this->notices,
+ $title,
+ $link,
+ $subtitle,
+ null,
+ $logo,
+ $self
+ );
+ break;
+ case 'atom':
+ header('Content-Type: application/atom+xml; charset=utf-8');
+
+ $atom = new AtomNoticeFeed($this->auth_user);
+
+ $atom->setId($id);
+ $atom->setTitle($title);
+ $atom->setSubtitle($subtitle);
+ $atom->setLogo($logo);
+ $atom->setUpdated('now');
+
+ $atom->addLink($link);
+ $atom->setSelfLink($self);
+
+ $atom->addEntryFromNotices($this->notices);
+
+ $this->raw($atom->getString());
+ break;
+ case 'json':
+ $this->showJsonTimeline($this->notices);
+ break;
+ case 'as':
+ header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
+ $doc = new ActivityStreamJSONDocument($this->auth_user);
+ $doc->setTitle($title);
+ $doc->addLink($link,'alternate', 'text/html');
+ $doc->addItemsFromNotices($this->notices);
+ $this->raw($doc->asString());
+ break;
+ default:
+ // TRANS: Client error displayed when coming across a non-supported API method.
+ $this->clientError(_('API method not found.'), $code = 404);
+ break;
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @return array notices
+ */
+ function getNotices()
+ {
+ $notices = array();
+
+ common_debug("since id = " . $this->since_id . " max id = " . $this->max_id);
+
+ $notice = new BookmarksNoticeStream($this->user->id, true);
+ $notice = $notice->getNotices(
+ ($this->page-1) * $this->count,
+ $this->count,
+ $this->since_id,
+ $this->max_id
+ );
+
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+
+ return $notices;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+ function lastModified()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+ return strtotime($this->notices[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this stream
+ *
+ * Returns an Etag based on the action name, language, user ID, and
+ * timestamps of the first and last notice in the timeline
+ *
+ * @return string etag
+ */
+ function etag()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+
+ $last = count($this->notices) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_user_cache_hash($this->auth_user),
+ common_language(),
+ $this->user->id,
+ strtotime($this->notices[0]->created),
+ strtotime($this->notices[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Returns a pre-filled bookmark form for a given URL
+ *
+ * PHP version 5
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Returns a prefilled bookmark form for a given URL
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class BookmarkforurlAction extends Action
+{
+ protected $url = null;
+ protected $oembed = null;
+ protected $thumbnail = null;
+ protected $title = null;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $args misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ if (!$this->isPost()) {
+ throw new ClientException(_('POST only'), 405);
+ }
+
+ $this->checkSessionToken();
+ $this->url = $this->trimmed('url');
+
+ if (empty($this->url)) {
+ throw new ClientException(_('URL is required.'), 400);
+ }
+
+ if (!Validate::uri($this->url, array('allowed_schemes' => array('http', 'https')))) {
+ throw new ClientException(_('Invalid URL.'), 400);
+ }
+
+ $f = File::getKV('url', $this->url);
+
+ if (empty($url)) {
+ $f = File::processNew($this->url);
+ }
+
+ // How about now?
+
+ if (!empty($f)) {
+ $this->oembed = File_oembed::getKV('file_id', $f->id);
+ if (!empty($this->oembed)) {
+ $this->title = $this->oembed->title;
+ }
+ $this->thumbnail = File_thumbnail::getKV('file_id', $f->id);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $args is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+
+ function handle($args=null)
+ {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ $this->element('title', null, _('Bookmark form'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $bf = new BookmarkForm($this, $this->title, $this->url, null, null, $this->thumbnail);
+ $bf->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+
+ function isReadOnly($args)
+ {
+ return false;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Post a new bookmark in a popup window
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Action for posting a new bookmark
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class BookmarkpopupAction extends NewbookmarkAction
+{
+ /**
+ * Show the title section of the window
+ *
+ * @return void
+ */
+ function showTitle()
+ {
+ $this->element('title',
+ // TRANS: Title for mini-posting window loaded from bookmarklet.
+ // TRANS: %s is the StatusNet site name.
+ null, sprintf(_m('Bookmark on %s'),
+ common_config('site', 'name')));
+ }
+
+ /**
+ * Show the header section of the page
+ *
+ * Shows a stub page and the bookmark form.
+ *
+ * @return void
+ */
+ function showHeader()
+ {
+ $this->elementStart('div', array('id' => 'header'));
+ $this->elementStart('address');
+ $this->element('a', array('class' => 'url',
+ 'href' => common_local_url('top')),
+ '');
+ $this->elementEnd('address');
+ if (common_logged_in()) {
+ $form = new BookmarkForm($this,
+ $this->title,
+ $this->url);
+ $form->show();
+ }
+ $this->elementEnd('div');
+ }
+
+ /**
+ * Hide the core section of the page
+ *
+ * @return void
+ */
+ function showCore()
+ {
+ }
+
+ /**
+ * Hide the footer section of the page
+ *
+ * @return void
+ */
+ function showFooter()
+ {
+ }
+
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->script(Plugin::staticPath('Bookmark', 'bookmarkpopup.js'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * Give a warm greeting to our friendly user
+ *
+ * PHP version 5
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * List currently logged-in user's bookmakrs
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Stephane Berube <chimo@chromic.org>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link https://github.com/chimo/BookmarkList
+ */
+class BookmarksAction extends Action
+{
+ var $user = null;
+ var $gc = null;
+
+ /**
+ * Take arguments for running
+ *
+ * This method is called first, and it lets the action class get
+ * all its arguments and validate them. It's also the time
+ * to fetch any relevant data from the database.
+ *
+ * Action classes should run parent::prepare($args) as the first
+ * line of this method to make sure the default argument-processing
+ * happens.
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ if (common_config('singleuser', 'enabled')) {
+ $nickname = User::singleUserNickname();
+ } else {
+ // PHP 5.4
+ // $nickname = $this->returnToArgs()[1]['nickname'];
+
+ // PHP < 5.4
+ $nickname = $this->returnToArgs();
+ $nickname = $nickname[1]['nickname'];
+ }
+
+ $this->user = User::getKV('nickname', $nickname);
+
+ if (!$this->user) {
+ // TRANS: Client error displayed when trying to display bookmarks for a non-existing user.
+ $this->clientError(_('No such user.'));
+ return false;
+ }
+
+ $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+
+ $stream = new BookmarksNoticeStream($this->user->id, true);
+ $this->notices = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
+ NOTICES_PER_PAGE + 1);
+
+ if($this->page > 1 && $this->notices->N == 0) {
+ throw new ClientException(_('No such page.'), 404);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle request
+ *
+ * This is the main method for handling a request. Note that
+ * most preparation should be done in the prepare() method;
+ * by the time handle() is called the action should be
+ * more or less ready to go.
+ *
+ * @param array $args $_REQUEST args; handled in prepare()
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showPage();
+ }
+
+ /**
+ * Title of this page
+ *
+ * Override this method to show a custom title.
+ *
+ * @return string Title of the page
+ */
+ function title()
+ {
+
+ if (empty($this->user)) {
+ // TRANS: Page title for sample plugin.
+ return _m('Log in');
+ } else {
+ // TRANS: Page title for sample plugin. %s is a user nickname.
+ return sprintf(_m('%s\'s bookmarks'), $this->user->nickname);
+ }
+ }
+
+ /**
+ * Feeds for the <head> section
+ *
+ * @return array Feed objects to show
+ */
+ function getFeeds()
+ {
+ return array(new Feed(Feed::JSON,
+ common_local_url('ApiTimelineBookmarks',
+ array(
+ 'id' => $this->user->nickname,
+ 'format' => 'as')),
+ // TRANS: Feed link text. %s is a username.
+ sprintf(_('Feed for favorites of %s (Activity Streams JSON)'),
+ $this->user->nickname)),
+ new Feed(Feed::RSS1,
+ common_local_url('bookmarksrss',
+ array('nickname' => $this->user->nickname)),
+ // TRANS: Feed link text. %s is a username.
+ sprintf(_('Feed for favorites of %s (RSS 1.0)'),
+ $this->user->nickname)),
+ new Feed(Feed::RSS2,
+ common_local_url('ApiTimelineBookmarks',
+ array(
+ 'id' => $this->user->nickname,
+ 'format' => 'rss')),
+ // TRANS: Feed link text. %s is a username.
+ sprintf(_('Feed for favorites of %s (RSS 2.0)'),
+ $this->user->nickname)),
+ new Feed(Feed::ATOM,
+ common_local_url('ApiTimelineBookmarks',
+ array(
+ 'id' => $this->user->nickname,
+ 'format' => 'atom')),
+ // TRANS: Feed link text. %s is a username.
+ sprintf(_('Feed for favorites of %s (Atom)'),
+ $this->user->nickname)));
+ }
+
+ /**
+ * Show content in the content area
+ *
+ * The default StatusNet page has a lot of decorations: menus,
+ * logos, tabs, all that jazz. This method is used to show
+ * content in the content area of the page; it's the main
+ * thing you want to overload.
+ *
+ * This method also demonstrates use of a plural localized string.
+ *
+ * @return void
+ */
+ function showContent()
+ {
+
+ $nl = new NoticeList($this->notices, $this);
+
+ $cnt = $nl->show();
+
+ if ($cnt == 0) {
+ $this->showEmptyList();
+ }
+
+ $this->pagination($this->page > 1,
+ $cnt > NOTICES_PER_PAGE,
+ $this->page, 'bookmarks',
+ array('nickname' => $this->user->nickname));
+ }
+
+ function showEmptyList() {
+ $message = sprintf(_('This is %1$s\'s bookmark stream, but %1$s hasn\'t bookmarked anything yet.'), $this->user->nickname) . ' ';
+
+ $this->elementStart('div', 'guide');
+ $this->raw(common_markup_to_html($message));
+ $this->elementEnd('div');
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * Some actions only read from the database; others read and write.
+ * The simple database load-balancer built into StatusNet will
+ * direct read-only actions to database mirrors (if they are configured),
+ * and read-write actions to the master database.
+ *
+ * This defaults to false to avoid data integrity issues, but you
+ * should make sure to overload it for performance gains.
+ *
+ * @param array $args other arguments, if RO/RW status depends on them.
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * RSS feed for user bookmarks action class.
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/rssaction.php';
+
+/**
+ * RSS feed for user bookmarks action class.
+ *
+ * Formatting of RSS handled by Rss10Action
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @author Stephane Berube <chimo@chromic.org> (modified 'favoritesrss.php' to show bookmarks instead)
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class BookmarksrssAction extends Rss10Action
+{
+ /** The user whose bookmarks to display */
+
+ var $user = null;
+
+ /**
+ * Find the user to display by supplied nickname
+ *
+ * @param array $args Arguments from $_REQUEST
+ *
+ * @return boolean success
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $nickname = $this->trimmed('nickname');
+ $this->user = User::getKV('nickname', $nickname);
+
+ if (!$this->user) {
+ // TRANS: Client error displayed when trying to get the RSS feed with bookmarks of a user that does not exist.
+ $this->clientError(_('No such user.'));
+ return false;
+ } else {
+ $this->notices = $this->getNotices($this->limit);
+ return true;
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @param integer $limit max number of notices to return
+ *
+ * @return array notices
+ */
+ function getNotices($limit=0)
+ {
+ $user = $this->user;
+
+ $notice = new BookmarksNoticeStream($this->user->id, true);
+ $notice = $notice->getNotices(0, NOTICES_PER_PAGE);
+
+ $notices = array();
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+ return $notices;
+ }
+
+ /**
+ * Get channel.
+ *
+ * @return array associative array on channel information
+ */
+ function getChannel()
+ {
+ $user = $this->user;
+ $c = array('url' => common_local_url('bookmarksrss',
+ array('nickname' =>
+ $user->nickname)),
+ // TRANS: Title of RSS feed with bookmarks of a user.
+ // TRANS: %s is a user's nickname.
+ 'title' => sprintf(_("%s's bookmarks"), $user->nickname),
+ 'link' => common_local_url('bookmarks',
+ array('nickname' =>
+ $user->nickname)),
+ // TRANS: Desciption of RSS feed with bookmarks of a user.
+ // TRANS: %1$s is a user's nickname, %2$s is the name of the StatusNet site.
+ 'description' => sprintf(_('Bookmarks posted by %1$s on %2$s!'),
+ $user->nickname, common_config('site', 'name')));
+ return $c;
+ }
+
+ /**
+ * Get image.
+ *
+ * @return void
+ */
+ function getImage()
+ {
+ return null;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Import del.icio.us bookmarks backups
+ *
+ * PHP version 5
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * UI for importing del.icio.us bookmark backups
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ImportdeliciousAction extends Action
+{
+ protected $success = false;
+ private $inprogress = false;
+
+ /**
+ * Return the title of the page
+ *
+ * @return string page title
+ */
+ function title()
+ {
+ // TRANS: Title for page to import del.icio.us bookmark backups on.
+ return _m("Import del.icio.us bookmarks");
+ }
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $cur = common_current_user();
+
+ if (empty($cur)) {
+ // TRANS: Client exception thrown when trying to import bookmarks without being logged in.
+ throw new ClientException(_m('Only logged-in users can '.
+ 'import del.icio.us backups.'),
+ 403);
+ }
+
+ if (!$cur->hasRight(BookmarkPlugin::IMPORTDELICIOUS)) {
+ // TRANS: Client exception thrown when trying to import bookmarks without having the rights to do so.
+ throw new ClientException(_m('You may not restore your account.'), 403);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ parent::handle($argarray);
+
+ if ($this->isPost()) {
+ $this->importDelicious();
+ } else {
+ $this->showPage();
+ }
+ return;
+ }
+
+ /**
+ * Queue a file for importation
+ *
+ * Uses the DeliciousBackupImporter class; may take a long time!
+ *
+ * @return void
+ */
+ function importDelicious()
+ {
+ $this->checkSessionToken();
+
+ if (!isset($_FILES[ImportDeliciousForm::FILEINPUT]['error'])) {
+ // TRANS: Client exception thrown when trying to import bookmarks and upload fails.
+ throw new ClientException(_m('No uploaded file.'));
+ }
+
+ switch ($_FILES[ImportDeliciousForm::FILEINPUT]['error']) {
+ case UPLOAD_ERR_OK: // success, jump out
+ break;
+ case UPLOAD_ERR_INI_SIZE:
+ // TRANS: Client exception thrown when an uploaded file is too large.
+ throw new ClientException(_m('The uploaded file exceeds the ' .
+ 'upload_max_filesize directive in php.ini.'));
+ return;
+ case UPLOAD_ERR_FORM_SIZE:
+ throw new ClientException(
+ // TRANS: Client exception thrown when an uploaded file is too large.
+ _m('The uploaded file exceeds the MAX_FILE_SIZE directive' .
+ ' that was specified in the HTML form.'));
+ return;
+ case UPLOAD_ERR_PARTIAL:
+ @unlink($_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name']);
+ // TRANS: Client exception thrown when a file was only partially uploaded.
+ throw new ClientException(_m('The uploaded file was only' .
+ ' partially uploaded.'));
+ return;
+ case UPLOAD_ERR_NO_FILE:
+ // No file; probably just a non-AJAX submission.
+ // TRANS: Client exception thrown when a file upload has failed.
+ throw new ClientException(_m('No uploaded file.'));
+ return;
+ case UPLOAD_ERR_NO_TMP_DIR:
+ // TRANS: Client exception thrown when a temporary folder is not present.
+ throw new ClientException(_m('Missing a temporary folder.'));
+ return;
+ case UPLOAD_ERR_CANT_WRITE:
+ // TRANS: Client exception thrown when writing to disk is not possible.
+ throw new ClientException(_m('Failed to write file to disk.'));
+ return;
+ case UPLOAD_ERR_EXTENSION:
+ // TRANS: Client exception thrown when a file upload has been stopped.
+ throw new ClientException(_m('File upload stopped by extension.'));
+ return;
+ default:
+ common_log(LOG_ERR, __METHOD__ . ": Unknown upload error " .
+ $_FILES[ImportDeliciousForm::FILEINPUT]['error']);
+ // TRANS: Client exception thrown when a file upload operation has failed.
+ throw new ClientException(_m('System error uploading file.'));
+ return;
+ }
+
+ $filename = $_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name'];
+
+ try {
+ if (!file_exists($filename)) {
+ // TRANS: Server exception thrown when a file upload cannot be found.
+ // TRANS: %s is the file that could not be found.
+ throw new ServerException(sprintf(_m('No such file "%s".'),$filename));
+ }
+
+ if (!is_file($filename)) {
+ // TRANS: Server exception thrown when a file upload is incorrect.
+ // TRANS: %s is the irregular file.
+ throw new ServerException(sprintf(_m('Not a regular file: "%s".'),$filename));
+ }
+
+ if (!is_readable($filename)) {
+ // TRANS: Server exception thrown when a file upload is not readable.
+ // TRANS: %s is the file that could not be read.
+ throw new ServerException(sprintf(_m('File "%s" not readable.'),$filename));
+ }
+
+ common_debug(sprintf("Getting backup from file '%s'.", $filename));
+
+ $html = file_get_contents($filename);
+
+ // Enqueue for processing.
+
+ $qm = QueueManager::get();
+ $qm->enqueue(array(common_current_user(), $html), 'dlcsback');
+
+ if ($qm instanceof UnQueueManager) {
+ // No active queuing means we've actually just completed the job!
+ $this->success = true;
+ } else {
+ // We've fed data into background queues, and it's probably still running.
+ $this->inprogress = true;
+ }
+
+ $this->showPage();
+
+ } catch (Exception $e) {
+ // Delete the file and re-throw
+ @unlink($_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name']);
+ throw $e;
+ }
+ }
+
+ /**
+ * Show the content of the page
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ if ($this->success) {
+ $this->element('p', null,
+ // TRANS: Success message after importing bookmarks.
+ _m('Bookmarks have been imported. Your bookmarks should now appear in search and your profile page.'));
+ } else if ($this->inprogress) {
+ $this->element('p', null,
+ // TRANS: Busy message for importing bookmarks.
+ _m('Bookmarks are being imported. Please wait a few minutes for results.'));
+ } else {
+ $form = new ImportDeliciousForm($this);
+ $form->show();
+ }
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return !$this->isPost();
+ }
+}
+
+/**
+ * A form for backing up the account.
+ *
+ * @category Account
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ImportDeliciousForm extends Form
+{
+ const FILEINPUT = 'deliciousbackupfile';
+
+ /**
+ * Constructor
+ *
+ * Set the encoding type, since this is a file upload.
+ *
+ * @param HTMLOutputter $out output channel
+ *
+ * @return ImportDeliciousForm this
+ */
+ function __construct($out=null)
+ {
+ parent::__construct($out);
+ $this->enctype = 'multipart/form-data';
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+ function formClass()
+ {
+ return 'form_import_delicious';
+ }
+
+ /**
+ * URL the form posts to
+ *
+ * @return string the form's action URL
+ */
+ function action()
+ {
+ return common_local_url('importdelicious');
+ }
+
+ /**
+ * Output form data
+ *
+ * Really, just instructions for doing a backup.
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('p', 'instructions');
+
+ // TRANS: Form instructions for importing bookmarks.
+ $this->out->raw(_m('You can upload a backed-up '.
+ 'delicious.com bookmarks file.'));
+
+ $this->out->elementEnd('p');
+
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->out->elementStart('li', array ('id' => 'settings_attach'));
+ $this->out->element('input', array('name' => self::FILEINPUT,
+ 'type' => 'file',
+ 'id' => self::FILEINPUT));
+ $this->out->elementEnd('li');
+
+ $this->out->elementEnd('ul');
+ }
+
+ /**
+ * Buttons for the form
+ *
+ * In this case, a single submit button
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('submit',
+ // TRANS: Button text on form to import bookmarks.
+ _m('BUTTON', 'Upload'),
+ 'submit',
+ null,
+ // TRANS: Button title on form to import bookmarks.
+ _m('Upload the file.'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Add a new bookmark
+ *
+ * PHP version 5
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Add a new bookmark
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class NewbookmarkAction extends Action
+{
+ protected $user = null;
+ protected $error = null;
+ protected $complete = null;
+ protected $title = null;
+ protected $url = null;
+ protected $tags = null;
+ protected $description = null;
+
+ /**
+ * Returns the title of the action
+ *
+ * @return string Action title
+ */
+ function title()
+ {
+ // TRANS: Title for action to create a new bookmark.
+ return _m('New bookmark');
+ }
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ if ($this->boolean('ajax')) {
+ StatusNet::setApi(true);
+ }
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown when trying to create a new bookmark while not logged in.
+ throw new ClientException(_m('Must be logged in to post a bookmark.'),
+ 403);
+ }
+
+ if ($this->isPost()) {
+ $this->checkSessionToken();
+ }
+
+ $this->title = $this->trimmed('title');
+ $this->url = $this->trimmed('url');
+ $this->tags = $this->trimmed('tags');
+ $this->description = $this->trimmed('description');
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ parent::handle($argarray);
+
+ if ($this->isPost()) {
+ $this->newBookmark();
+ } else {
+ $this->showPage();
+ }
+
+ return;
+ }
+
+ /**
+ * Add a new bookmark
+ *
+ * @return void
+ */
+ function newBookmark()
+ {
+ try {
+ if (empty($this->title)) {
+ // TRANS: Client exception thrown when trying to create a new bookmark without a title.
+ throw new ClientException(_m('Bookmark must have a title.'));
+ }
+
+ if (empty($this->url)) {
+ // TRANS: Client exception thrown when trying to create a new bookmark without a URL.
+ throw new ClientException(_m('Bookmark must have an URL.'));
+ }
+
+ $options = array();
+
+ ToSelector::fillOptions($this, $options);
+
+ $saved = Bookmark::saveNew($this->user->getProfile(),
+ $this->title,
+ $this->url,
+ $this->tags,
+ $this->description,
+ $options);
+
+ } catch (ClientException $ce) {
+ if ($this->boolean('ajax')) {
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Page title after an AJAX error occurs
+ $this->element('title', null, _('Ajax Error'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->element('p', array('id' => 'error'), $ce->getMessage());
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ return;
+ } else {
+ $this->error = $ce->getMessage();
+ $this->showPage();
+ return;
+ }
+ }
+
+ if ($this->boolean('ajax')) {
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Page title after posting a bookmark.
+ $this->element('title', null, _m('Bookmark posted'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->showNotice($saved);
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect($saved->bestUrl(), 303);
+ }
+ }
+
+ /**
+ * Output a notice
+ *
+ * Used to generate the notice code for Ajax results.
+ *
+ * @param Notice $notice Notice that was saved
+ *
+ * @return void
+ */
+ function showNotice($notice)
+ {
+ class_exists('NoticeList'); // @fixme hack for autoloader
+ $nli = new NoticeListItem($notice, $this);
+ $nli->show();
+ }
+
+ /**
+ * Show the bookmark form
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ if (!empty($this->error)) {
+ $this->element('p', 'error', $this->error);
+ }
+
+ $form = new BookmarkForm($this,
+ $this->title,
+ $this->url,
+ $this->tags,
+ $this->description);
+
+ $form->show();
+
+ return;
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
+ $_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Notice stream of notices with a given attachment
+ *
+ * PHP version 5
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * List notices that contain/link to/use a given URL
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class NoticebyurlAction extends Action
+{
+ protected $url = null;
+ protected $file = null;
+ protected $notices = null;
+ protected $page = null;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $this->file = File::getKV('id', $this->trimmed('id'));
+
+ if (empty($this->file)) {
+ // TRANS: Client exception thrown when an unknown URL is provided.
+ throw new ClientException(_m('Unknown URL.'));
+ }
+
+ $pageArg = $this->trimmed('page');
+
+ $this->page = (empty($pageArg)) ? 1 : intval($pageArg);
+
+ $this->notices = $this->file->stream(($this->page - 1) * NOTICES_PER_PAGE,
+ NOTICES_PER_PAGE + 1);
+
+ return true;
+ }
+
+ /**
+ * Title of the page
+ *
+ * @return string page title
+ */
+ function title()
+ {
+ if ($this->page == 1) {
+ // TRANS: Title of notice stream of notices with a given attachment (first page).
+ // TRANS: %s is the URL.
+ return sprintf(_m('Notices linking to %s'), $this->file->url);
+ } else {
+ // TRANS: Title of notice stream of notices with a given attachment (all but first page).
+ // TRANS: %1$s is the URL, %2$s is the page number.
+ return sprintf(_m('Notices linking to %1$s, page %2$d'),
+ $this->file->url,
+ $this->page);
+ }
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ $this->showPage();
+ }
+
+ /**
+ * Show main page content.
+ *
+ * Shows a list of the notices that link to the given URL
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $nl = new NoticeList($this->notices, $this);
+
+ $nl->show();
+
+ $cnt = $nl->show();
+
+ $this->pagination($this->page > 1,
+ $cnt > NOTICES_PER_PAGE,
+ $this->page,
+ 'noticebyurl',
+ array('id' => $this->file->id));
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * Return last modified, if applicable.
+ *
+ * MAY override
+ *
+ * @return string last modified http header
+ */
+ function lastModified()
+ {
+ // For comparison with If-Last-Modified
+ // If not applicable, return null
+ return null;
+ }
+
+ /**
+ * Return etag, if applicable.
+ *
+ * MAY override
+ *
+ * @return string etag http header
+ */
+ function etag()
+ {
+ return null;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Show a single bookmark
+ *
+ * PHP version 5
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Show a single bookmark, with associated information
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ShowbookmarkAction extends ShownoticeAction
+{
+ protected $bookmark = null;
+
+ function getNotice()
+ {
+ $this->id = $this->trimmed('id');
+
+ $this->bookmark = Bookmark::getKV('id', $this->id);
+
+ if (empty($this->bookmark)) {
+ // TRANS: Client exception thrown when referring to a non-existing bookmark.
+ throw new ClientException(_m('No such bookmark.'), 404);
+ }
+
+ $notice = Notice::getKV('uri', $this->bookmark->uri);
+
+ if (empty($notice)) {
+ // Did we used to have it, and it got deleted?
+ // TRANS: Client exception thrown when referring to a non-existing bookmark.
+ throw new ClientException(_m('No such bookmark.'), 404);
+ }
+
+ return $notice;
+ }
+
+ /**
+ * Title of the page
+ *
+ * Used by Action class for layout.
+ *
+ * @return string page tile
+ */
+ function title()
+ {
+ // TRANS: Title for bookmark.
+ // TRANS: %1$s is a user nickname, %2$s is a bookmark title.
+ return sprintf(_m('%1$s\'s bookmark for "%2$s"'),
+ $this->user->nickname,
+ $this->bookmark->title);
+ }
+
+ /**
+ * Overload page title display to show bookmark link
+ *
+ * @return void
+ */
+ function showPageTitle()
+ {
+ $this->elementStart('h1');
+ $this->element('a',
+ array('href' => $this->bookmark->url),
+ $this->bookmark->title);
+ $this->elementEnd('h1');
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Show a user's favorite notices
- *
- * 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 API
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @author Evan Prodromou <evan@status.net>
- * @author Zach Copley <zach@status.net>
- * @copyright 2009-2010 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/apibareauth.php';
-require_once 'bookmarksnoticestream.php';
-
-/**
- * Returns the 20 most recent favorite notices for the authenticating user or user
- * specified by the ID parameter in the requested format.
- *
- * @category API
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @author Evan Prodromou <evan@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
- * @link http://status.net/
- */
-class ApiTimelineBookmarksAction extends ApiBareAuthAction
-{
- var $notices = null;
-
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $this->user = $this->getTargetUser($this->arg('id'));
-
- if (empty($this->user)) {
- // TRANS: Client error displayed when requesting most recent favourite notices by a user for a non-existing user.
- $this->clientError(_('No such user.'), 404, $this->format);
- return;
- }
-
- $this->notices = $this->getNotices();
-
- return true;
- }
-
- /**
- * Handle the request
- *
- * Just show the notices
- *
- * @param array $args $_REQUEST data (unused)
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
- $this->showTimeline();
- }
-
- /**
- * Show the timeline of notices
- *
- * @return void
- */
- function showTimeline()
- {
- $profile = $this->user->getProfile();
- $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
-
- $sitename = common_config('site', 'name');
- $title = sprintf(
- // TRANS: Title for timeline of most recent favourite notices by a user.
- // TRANS: %1$s is the StatusNet sitename, %2$s is a user nickname.
- _('%1$s / Bookmarks from %2$s'),
- $sitename,
- $this->user->nickname
- );
-
- $taguribase = TagURI::base();
- $id = "tag:$taguribase:Bookmarks:" . $this->user->id;
-
- $subtitle = sprintf(
- // TRANS: Subtitle for timeline of most recent favourite notices by a user.
- // TRANS: %1$s is the StatusNet sitename, %2$s is a user's full name,
- // TRANS: %3$s is a user nickname.
- _('%1$s updates bookmarked by %2$s / %3$s.'),
- $sitename,
- $profile->getBestName(),
- $this->user->nickname
- );
- $logo = !empty($avatar)
- ? $avatar->displayUrl()
- : Avatar::defaultImage(AVATAR_PROFILE_SIZE);
-
- $link = common_local_url(
- 'bookmarks',
- array('nickname' => $this->user->nickname)
- );
-
- $self = $this->getSelfUri();
-
- switch($this->format) {
- case 'xml':
- $this->showXmlTimeline($this->notices);
- break;
- case 'rss':
- $this->showRssTimeline(
- $this->notices,
- $title,
- $link,
- $subtitle,
- null,
- $logo,
- $self
- );
- break;
- case 'atom':
- header('Content-Type: application/atom+xml; charset=utf-8');
-
- $atom = new AtomNoticeFeed($this->auth_user);
-
- $atom->setId($id);
- $atom->setTitle($title);
- $atom->setSubtitle($subtitle);
- $atom->setLogo($logo);
- $atom->setUpdated('now');
-
- $atom->addLink($link);
- $atom->setSelfLink($self);
-
- $atom->addEntryFromNotices($this->notices);
-
- $this->raw($atom->getString());
- break;
- case 'json':
- $this->showJsonTimeline($this->notices);
- break;
- case 'as':
- header('Content-Type: ' . ActivityStreamJSONDocument::CONTENT_TYPE);
- $doc = new ActivityStreamJSONDocument($this->auth_user);
- $doc->setTitle($title);
- $doc->addLink($link,'alternate', 'text/html');
- $doc->addItemsFromNotices($this->notices);
- $this->raw($doc->asString());
- break;
- default:
- // TRANS: Client error displayed when coming across a non-supported API method.
- $this->clientError(_('API method not found.'), $code = 404);
- break;
- }
- }
-
- /**
- * Get notices
- *
- * @return array notices
- */
- function getNotices()
- {
- $notices = array();
-
- common_debug("since id = " . $this->since_id . " max id = " . $this->max_id);
-
- $notice = new BookmarksNoticeStream($this->user->id, true);
- $notice = $notice->getNotices(
- ($this->page-1) * $this->count,
- $this->count,
- $this->since_id,
- $this->max_id
- );
-
- while ($notice->fetch()) {
- $notices[] = clone($notice);
- }
-
- return $notices;
- }
-
- /**
- * Is this action read only?
- *
- * @param array $args other arguments
- *
- * @return boolean true
- */
- function isReadOnly($args)
- {
- return true;
- }
-
- /**
- * When was this feed last modified?
- *
- * @return string datestamp of the latest notice in the stream
- */
- function lastModified()
- {
- if (!empty($this->notices) && (count($this->notices) > 0)) {
- return strtotime($this->notices[0]->created);
- }
-
- return null;
- }
-
- /**
- * An entity tag for this stream
- *
- * Returns an Etag based on the action name, language, user ID, and
- * timestamps of the first and last notice in the timeline
- *
- * @return string etag
- */
- function etag()
- {
- if (!empty($this->notices) && (count($this->notices) > 0)) {
-
- $last = count($this->notices) - 1;
-
- return '"' . implode(
- ':',
- array($this->arg('action'),
- common_user_cache_hash($this->auth_user),
- common_language(),
- $this->user->id,
- strtotime($this->notices[0]->created),
- strtotime($this->notices[$last]->created))
- )
- . '"';
- }
-
- return null;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Form for adding a new bookmark
- *
- * PHP version 5
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form to add a new bookmark
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class BookmarkForm extends Form
-{
- private $_title = null;
- private $_url = null;
- private $_tags = null;
- private $_description = null;
- private $_thumbnail = null;
-
- /**
- * Construct a bookmark form
- *
- * @param HTMLOutputter $out output channel
- * @param string $title Title of the bookmark
- * @param string $url URL of the bookmark
- * @param string $tags Tags to show
- * @param string $description Description of the bookmark
- *
- * @return void
- */
- function __construct($out=null, $title=null, $url=null, $tags=null,
- $description=null, $thumbnail=null)
- {
- parent::__construct($out);
-
- $this->_title = $title;
- $this->_url = $url;
- $this->_tags = $tags;
- $this->_description = $description;
- $this->_thumbnail = $thumbnail;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'form_new_bookmark';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings ajax-notice';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('newbookmark');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'new_bookmark_data'));
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->out->input('bookmark-url',
- // TRANS: Field label on form for adding a new bookmark.
- _m('LABEL','URL'),
- $this->_url,
- null,
- 'url');
- $this->unli();
-
- if (!empty($this->_thumbnail)) {
-
- list($width, $height) = $this->scaleImage($this->_thumbnail->width,
- $this->_thumbnail->height);
-
- $this->out->element('img',
- array('src' => $this->_thumbnail->url,
- 'class' => 'bookmarkform-thumbnail',
- 'width' => $width,
- 'height' => $height));
- }
-
- $this->li();
- $this->out->input('bookmark-title',
- // TRANS: Field label on form for adding a new bookmark.
- _m('LABEL','Title'),
- $this->_title,
- null,
- 'title');
- $this->unli();
-
- $this->li();
- $this->out->textarea('bookmark-description',
- // TRANS: Field label on form for adding a new bookmark.
- _m('LABEL','Notes'),
- $this->_description,
- null,
- 'description');
- $this->unli();
-
- $this->li();
- $this->out->input('bookmark-tags',
- // TRANS: Field label on form for adding a new bookmark.
- _m('LABEL','Tags'),
- $this->_tags,
- // TRANS: Field title on form for adding a new bookmark.
- _m('Comma- or space-separated list of tags.'),
- 'tags');
- $this->unli();
-
- $this->out->elementEnd('ul');
-
- $toWidget = new ToSelector($this->out,
- common_current_user(),
- null);
- $toWidget->show();
-
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
-
- function formActions()
- {
- // TRANS: Button text for action to save a new bookmark.
- $this->out->submit('bookmark-submit', _m('BUTTON', 'Save'), 'submit', 'submit');
- }
-
- function scaleImage($width, $height)
- {
- $maxwidth = common_config('attachments', 'thumb_width');
- $maxheight = common_config('attachments', 'thumb_height');
-
- if ($width > $height && $width > $maxwidth) {
- $height = (int) ((((float)$maxwidth)/(float)($width))*(float)$height);
- $width = $maxwidth;
- } else if ($height > $maxheight) {
- $width = (int) ((((float)$maxheight)/(float)($height))*(float)$width);
- $height = $maxheight;
- }
-
- return array($width, $height);
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Returns a pre-filled bookmark form for a given URL
- *
- * PHP version 5
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Returns a prefilled bookmark form for a given URL
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class BookmarkforurlAction extends Action
-{
- protected $url = null;
- protected $oembed = null;
- protected $thumbnail = null;
- protected $title = null;
-
- /**
- * For initializing members of the class.
- *
- * @param array $args misc. arguments
- *
- * @return boolean true
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- if (!$this->isPost()) {
- throw new ClientException(_('POST only'), 405);
- }
-
- $this->checkSessionToken();
- $this->url = $this->trimmed('url');
-
- if (empty($this->url)) {
- throw new ClientException(_('URL is required.'), 400);
- }
-
- if (!Validate::uri($this->url, array('allowed_schemes' => array('http', 'https')))) {
- throw new ClientException(_('Invalid URL.'), 400);
- }
-
- $f = File::getKV('url', $this->url);
-
- if (empty($url)) {
- $f = File::processNew($this->url);
- }
-
- // How about now?
-
- if (!empty($f)) {
- $this->oembed = File_oembed::getKV('file_id', $f->id);
- if (!empty($this->oembed)) {
- $this->title = $this->oembed->title;
- }
- $this->thumbnail = File_thumbnail::getKV('file_id', $f->id);
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $args is ignored since it's now passed in in prepare()
- *
- * @return void
- */
-
- function handle($args=null)
- {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- $this->element('title', null, _('Bookmark form'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $bf = new BookmarkForm($this, $this->title, $this->url, null, null, $this->thumbnail);
- $bf->show();
- $this->elementEnd('body');
- $this->elementEnd('html');
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
-
- function isReadOnly($args)
- {
- return false;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Adapter to show bookmarks in a nicer way
- *
- * PHP version 5
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * An adapter to show bookmarks in a nicer way
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class BookmarkListItem extends NoticeListItemAdapter
-{
- function showNotice()
- {
- $this->nli->out->elementStart('div', 'entry-title');
- $this->nli->showAuthor();
- $this->showContent();
- $this->nli->out->elementEnd('div');
- }
-
- function showContent()
- {
- $notice = $this->nli->notice;
- $out = $this->nli->out;
-
- $nb = Bookmark::getByNotice($notice);
-
- if (empty($nb)) {
- common_log(LOG_ERR, "No bookmark for notice {$notice->id}");
- parent::showContent();
- return;
- } else if (empty($nb->url)) {
- common_log(LOG_ERR, "No url for bookmark {$nb->id} for notice {$notice->id}");
- parent::showContent();
- return;
- }
-
- $profile = $notice->getProfile();
-
- $out->elementStart('p', array('class' => 'entry-content'));
-
- // Whether to nofollow
-
- $attrs = array('href' => $nb->url,
- 'class' => 'bookmark-title');
-
- $nf = common_config('nofollow', 'external');
-
- if ($nf == 'never' || ($nf == 'sometimes' and $out instanceof ShowstreamAction)) {
- $attrs['rel'] = 'external';
- } else {
- $attrs['rel'] = 'nofollow external';
- }
-
- $out->elementStart('h3');
- $out->element('a',
- $attrs,
- $nb->title);
- $out->elementEnd('h3');
-
- // Replies look like "for:" tags
-
- $replies = $notice->getReplies();
- $tags = $notice->getTags();
-
- if (!empty($replies) || !empty($tags)) {
-
- $out->elementStart('ul', array('class' => 'bookmark-tags'));
-
- foreach ($replies as $reply) {
- $other = Profile::getKV('id', $reply);
- if (!empty($other)) {
- $out->elementStart('li');
- $out->element('a', array('rel' => 'tag',
- 'href' => $other->profileurl,
- 'title' => $other->getBestName()),
- sprintf('for:%s', $other->nickname));
- $out->elementEnd('li');
- $out->text(' ');
- }
- }
-
- foreach ($tags as $tag) {
- $tag = trim($tag);
- if (!empty($tag)) {
- $out->elementStart('li');
- $out->element('a',
- array('rel' => 'tag',
- 'href' => Notice_tag::url($tag)),
- $tag);
- $out->elementEnd('li');
- $out->text(' ');
- }
- }
-
- $out->elementEnd('ul');
- }
-
- if (!empty($nb->description)) {
- $out->element('p',
- array('class' => 'bookmark-description'),
- $nb->description);
- }
-
- $out->elementEnd('p');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Post a new bookmark in a popup window
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Sarven Capadisli <csarven@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Action for posting a new bookmark
- *
- * @category Bookmark
- * @package StatusNet
- * @author Sarven Capadisli <csarven@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class BookmarkpopupAction extends NewbookmarkAction
-{
- /**
- * Show the title section of the window
- *
- * @return void
- */
- function showTitle()
- {
- $this->element('title',
- // TRANS: Title for mini-posting window loaded from bookmarklet.
- // TRANS: %s is the StatusNet site name.
- null, sprintf(_m('Bookmark on %s'),
- common_config('site', 'name')));
- }
-
- /**
- * Show the header section of the page
- *
- * Shows a stub page and the bookmark form.
- *
- * @return void
- */
- function showHeader()
- {
- $this->elementStart('div', array('id' => 'header'));
- $this->elementStart('address');
- $this->element('a', array('class' => 'url',
- 'href' => common_local_url('top')),
- '');
- $this->elementEnd('address');
- if (common_logged_in()) {
- $form = new BookmarkForm($this,
- $this->title,
- $this->url);
- $form->show();
- }
- $this->elementEnd('div');
- }
-
- /**
- * Hide the core section of the page
- *
- * @return void
- */
- function showCore()
- {
- }
-
- /**
- * Hide the footer section of the page
- *
- * @return void
- */
- function showFooter()
- {
- }
-
- function showScripts()
- {
- parent::showScripts();
- $this->script(Plugin::staticPath('Bookmark', 'bookmarkpopup.js'));
- }
-}
+++ /dev/null
-<?php
-/**
- * Give a warm greeting to our friendly user
- *
- * PHP version 5
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once 'bookmarksnoticestream.php';
-
-/**
- * List currently logged-in user's bookmakrs
- *
- * @category Bookmark
- * @package StatusNet
- * @author Stephane Berube <chimo@chromic.org>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link https://github.com/chimo/BookmarkList
- */
-class BookmarksAction extends Action
-{
- var $user = null;
- var $gc = null;
-
- /**
- * Take arguments for running
- *
- * This method is called first, and it lets the action class get
- * all its arguments and validate them. It's also the time
- * to fetch any relevant data from the database.
- *
- * Action classes should run parent::prepare($args) as the first
- * line of this method to make sure the default argument-processing
- * happens.
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- if (common_config('singleuser', 'enabled')) {
- $nickname = User::singleUserNickname();
- } else {
- // PHP 5.4
- // $nickname = $this->returnToArgs()[1]['nickname'];
-
- // PHP < 5.4
- $nickname = $this->returnToArgs();
- $nickname = $nickname[1]['nickname'];
- }
-
- $this->user = User::getKV('nickname', $nickname);
-
- if (!$this->user) {
- // TRANS: Client error displayed when trying to display bookmarks for a non-existing user.
- $this->clientError(_('No such user.'));
- return false;
- }
-
- $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
-
- $stream = new BookmarksNoticeStream($this->user->id, true);
- $this->notices = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
- NOTICES_PER_PAGE + 1);
-
- if($this->page > 1 && $this->notices->N == 0) {
- throw new ClientException(_('No such page.'), 404);
- }
-
- return true;
- }
-
- /**
- * Handle request
- *
- * This is the main method for handling a request. Note that
- * most preparation should be done in the prepare() method;
- * by the time handle() is called the action should be
- * more or less ready to go.
- *
- * @param array $args $_REQUEST args; handled in prepare()
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
- $this->showPage();
- }
-
- /**
- * Title of this page
- *
- * Override this method to show a custom title.
- *
- * @return string Title of the page
- */
- function title()
- {
-
- if (empty($this->user)) {
- // TRANS: Page title for sample plugin.
- return _m('Log in');
- } else {
- // TRANS: Page title for sample plugin. %s is a user nickname.
- return sprintf(_m('%s\'s bookmarks'), $this->user->nickname);
- }
- }
-
- /**
- * Feeds for the <head> section
- *
- * @return array Feed objects to show
- */
- function getFeeds()
- {
- return array(new Feed(Feed::JSON,
- common_local_url('ApiTimelineBookmarks',
- array(
- 'id' => $this->user->nickname,
- 'format' => 'as')),
- // TRANS: Feed link text. %s is a username.
- sprintf(_('Feed for favorites of %s (Activity Streams JSON)'),
- $this->user->nickname)),
- new Feed(Feed::RSS1,
- common_local_url('bookmarksrss',
- array('nickname' => $this->user->nickname)),
- // TRANS: Feed link text. %s is a username.
- sprintf(_('Feed for favorites of %s (RSS 1.0)'),
- $this->user->nickname)),
- new Feed(Feed::RSS2,
- common_local_url('ApiTimelineBookmarks',
- array(
- 'id' => $this->user->nickname,
- 'format' => 'rss')),
- // TRANS: Feed link text. %s is a username.
- sprintf(_('Feed for favorites of %s (RSS 2.0)'),
- $this->user->nickname)),
- new Feed(Feed::ATOM,
- common_local_url('ApiTimelineBookmarks',
- array(
- 'id' => $this->user->nickname,
- 'format' => 'atom')),
- // TRANS: Feed link text. %s is a username.
- sprintf(_('Feed for favorites of %s (Atom)'),
- $this->user->nickname)));
- }
-
- /**
- * Show content in the content area
- *
- * The default StatusNet page has a lot of decorations: menus,
- * logos, tabs, all that jazz. This method is used to show
- * content in the content area of the page; it's the main
- * thing you want to overload.
- *
- * This method also demonstrates use of a plural localized string.
- *
- * @return void
- */
- function showContent()
- {
-
- $nl = new NoticeList($this->notices, $this);
-
- $cnt = $nl->show();
-
- if ($cnt == 0) {
- $this->showEmptyList();
- }
-
- $this->pagination($this->page > 1,
- $cnt > NOTICES_PER_PAGE,
- $this->page, 'bookmarks',
- array('nickname' => $this->user->nickname));
- }
-
- function showEmptyList() {
- $message = sprintf(_('This is %1$s\'s bookmark stream, but %1$s hasn\'t bookmarked anything yet.'), $this->user->nickname) . ' ';
-
- $this->elementStart('div', 'guide');
- $this->raw(common_markup_to_html($message));
- $this->elementEnd('div');
- }
-
- /**
- * Return true if read only.
- *
- * Some actions only read from the database; others read and write.
- * The simple database load-balancer built into StatusNet will
- * direct read-only actions to database mirrors (if they are configured),
- * and read-write actions to the master database.
- *
- * This defaults to false to avoid data integrity issues, but you
- * should make sure to overload it for performance gains.
- *
- * @param array $args other arguments, if RO/RW status depends on them.
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return true;
- }
-}
+++ /dev/null
-<?php
-
-class RawBookmarksNoticeStream extends NoticeStream
-{
- protected $user_id;
- protected $own;
-
- function __construct($user_id, $own)
- {
- $this->user_id = $user_id;
- $this->own = $own;
- }
-
- function getNoticeIds($offset, $limit, $since_id, $max_id)
- {
- $notice = new Notice();
- $qry = null;
-
- $qry = 'SELECT notice.* FROM notice ';
- $qry .= 'INNER JOIN bookmark ON bookmark.uri = notice.uri ';
- $qry .= 'WHERE bookmark.profile_id = ' . $this->user_id . ' ';
- $qry .= 'AND notice.is_local != ' . Notice::GATEWAY . ' ';
-
- if ($since_id != 0) {
- $qry .= 'AND notice.id > ' . $since_id . ' ';
- }
-
- if ($max_id != 0) {
- $qry .= 'AND notice.id <= ' . $max_id . ' ';
- }
-
- // NOTE: we sort by bookmark time, not by notice time!
- $qry .= 'ORDER BY created DESC ';
- if (!is_null($offset)) {
- $qry .= "LIMIT $limit OFFSET $offset";
- }
-
- $notice->query($qry);
- $ids = array();
- while ($notice->fetch()) {
- $ids[] = $notice->id;
- }
-
- $notice->free();
- unset($notice);
- return $ids;
- }
-}
-
-/**
- * Notice stream for bookmarks
- *
- * @category Stream
- * @package StatusNet
- * @author Stephane Berube <chimo@chromic.org>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class BookmarksNoticeStream extends ScopingNoticeStream
-{
- function __construct($user_id, $own, $profile = -1)
- {
- $stream = new RawBookmarksNoticeStream($user_id, $own);
-
- if ($own) {
- $key = 'bookmark:ids_by_user_own:'.$user_id;
- } else {
- $key = 'bookmark:ids_by_user:'.$user_id;
- }
-
- if (is_int($profile) && $profile == -1) {
- $profile = Profile::current();
- }
-
- parent::__construct(new CachingNoticeStream($stream, $key),
- $profile);
- }
-}
+++ /dev/null
-<?php
-/**
- * RSS feed for user bookmarks action class.
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/rssaction.php';
-require_once 'bookmarksnoticestream.php';
-
-/**
- * RSS feed for user bookmarks action class.
- *
- * Formatting of RSS handled by Rss10Action
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @author Zach Copley <zach@status.net>
- * @author Stephane Berube <chimo@chromic.org> (modified 'favoritesrss.php' to show bookmarks instead)
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class BookmarksrssAction extends Rss10Action
-{
- /** The user whose bookmarks to display */
-
- var $user = null;
-
- /**
- * Find the user to display by supplied nickname
- *
- * @param array $args Arguments from $_REQUEST
- *
- * @return boolean success
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $nickname = $this->trimmed('nickname');
- $this->user = User::getKV('nickname', $nickname);
-
- if (!$this->user) {
- // TRANS: Client error displayed when trying to get the RSS feed with bookmarks of a user that does not exist.
- $this->clientError(_('No such user.'));
- return false;
- } else {
- $this->notices = $this->getNotices($this->limit);
- return true;
- }
- }
-
- /**
- * Get notices
- *
- * @param integer $limit max number of notices to return
- *
- * @return array notices
- */
- function getNotices($limit=0)
- {
- $user = $this->user;
-
- $notice = new BookmarksNoticeStream($this->user->id, true);
- $notice = $notice->getNotices(0, NOTICES_PER_PAGE);
-
- $notices = array();
- while ($notice->fetch()) {
- $notices[] = clone($notice);
- }
- return $notices;
- }
-
- /**
- * Get channel.
- *
- * @return array associative array on channel information
- */
- function getChannel()
- {
- $user = $this->user;
- $c = array('url' => common_local_url('bookmarksrss',
- array('nickname' =>
- $user->nickname)),
- // TRANS: Title of RSS feed with bookmarks of a user.
- // TRANS: %s is a user's nickname.
- 'title' => sprintf(_("%s's bookmarks"), $user->nickname),
- 'link' => common_local_url('bookmarks',
- array('nickname' =>
- $user->nickname)),
- // TRANS: Desciption of RSS feed with bookmarks of a user.
- // TRANS: %1$s is a user's nickname, %2$s is the name of the StatusNet site.
- 'description' => sprintf(_('Bookmarks posted by %1$s on %2$s!'),
- $user->nickname, common_config('site', 'name')));
- return $c;
- }
-
- /**
- * Get image.
- *
- * @return void
- */
- function getImage()
- {
- return null;
- }
-
-}
--- /dev/null
+<?php
+/**
+ * Data class to mark notices as bookmarks
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * For storing the fact that a notice is a bookmark
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Bookmark extends Managed_DataObject
+{
+ public $__table = 'bookmark'; // table name
+ public $id; // char(36) primary_key not_null
+ public $profile_id; // int(4) not_null
+ public $url; // varchar(255) not_null
+ public $title; // varchar(255)
+ public $description; // text
+ public $uri; // varchar(255)
+ public $created; // datetime
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'id' => array('type' => 'char',
+ 'length' => 36,
+ 'not null' => true),
+ 'profile_id' => array('type' => 'int', 'not null' => true),
+ 'uri' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'url' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'title' => array('type' => 'varchar', 'length' => 255),
+ 'description' => array('type' => 'text'),
+ 'created' => array('type' => 'datetime', 'not null' => true),
+ ),
+ 'primary key' => array('id'),
+ 'unique keys' => array(
+ 'bookmark_uri_key' => array('uri'),
+ ),
+ 'foreign keys' => array(
+ 'bookmark_profile_id_fkey' => array('profile', array('profile_id' => 'id'))
+ ),
+ 'indexes' => array('bookmark_created_idx' => array('created'),
+ 'bookmark_url_idx' => array('url'),
+ 'bookmark_profile_id_idx' => array('profile_id'),
+ ),
+ );
+ }
+
+ /**
+ * Get a bookmark based on a notice
+ *
+ * @param Notice $notice Notice to check for
+ *
+ * @return Bookmark found bookmark or null
+ */
+ static function getByNotice($notice)
+ {
+ return self::getKV('uri', $notice->uri);
+ }
+
+ /**
+ * Get the bookmark that a user made for an URL
+ *
+ * @param Profile $profile Profile to check for
+ * @param string $url URL to check for
+ *
+ * @return Bookmark bookmark found or null
+ */
+ static function getByURL($profile, $url)
+ {
+ $nb = new Bookmark();
+
+ $nb->profile_id = $profile->id;
+ $nb->url = $url;
+
+ if ($nb->find(true)) {
+ return $nb;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Save a new notice bookmark
+ *
+ * @param Profile $profile To save the bookmark for
+ * @param string $title Title of the bookmark
+ * @param string $url URL of the bookmark
+ * @param mixed $rawtags array of tags or string
+ * @param string $description Description of the bookmark
+ * @param array $options Options for the Notice::saveNew()
+ *
+ * @return Notice saved notice
+ */
+ static function saveNew($profile, $title, $url, $rawtags, $description,
+ $options=null)
+ {
+ $nb = self::getByURL($profile, $url);
+
+ if (!empty($nb)) {
+ // TRANS: Client exception thrown when trying to save a new bookmark that already exists.
+ throw new ClientException(_m('Bookmark already exists.'));
+ }
+
+ if (empty($options)) {
+ $options = array();
+ }
+
+ if (array_key_exists('uri', $options)) {
+ $other = Bookmark::getKV('uri', $options['uri']);
+ if (!empty($other)) {
+ // TRANS: Client exception thrown when trying to save a new bookmark that already exists.
+ throw new ClientException(_m('Bookmark already exists.'));
+ }
+ }
+
+ if (is_string($rawtags)) {
+ if (empty($rawtags)) {
+ $rawtags = array();
+ } else {
+ $rawtags = preg_split('/[\s,]+/', $rawtags);
+ }
+ }
+
+ $nb = new Bookmark();
+
+ $nb->id = UUID::gen();
+ $nb->profile_id = $profile->id;
+ $nb->url = $url;
+ $nb->title = $title;
+ $nb->description = $description;
+
+ if (array_key_exists('created', $options)) {
+ $nb->created = $options['created'];
+ } else {
+ $nb->created = common_sql_now();
+ }
+
+ if (array_key_exists('uri', $options)) {
+ $nb->uri = $options['uri'];
+ } else {
+ // FIXME: hacks to work around router bugs in
+ // queue daemons
+
+ $r = Router::get();
+
+ $path = $r->build('showbookmark',
+ array('id' => $nb->id));
+
+ if (empty($path)) {
+ $nb->uri = common_path('bookmark/'.$nb->id, false, false);
+ } else {
+ $nb->uri = common_local_url('showbookmark',
+ array('id' => $nb->id),
+ null,
+ null,
+ false);
+ }
+ }
+
+ $nb->insert();
+
+ $tags = array();
+ $replies = array();
+
+ // filter "for:nickname" tags
+
+ foreach ($rawtags as $tag) {
+ if (strtolower(mb_substr($tag, 0, 4)) == 'for:') {
+ // skip if done by caller
+ if (!array_key_exists('replies', $options)) {
+ $nickname = mb_substr($tag, 4);
+ $other = common_relative_profile($profile,
+ $nickname);
+ if (!empty($other)) {
+ $replies[] = $other->getUri();
+ }
+ }
+ } else {
+ $tags[] = common_canonical_tag($tag);
+ }
+ }
+
+ $hashtags = array();
+ $taglinks = array();
+
+ foreach ($tags as $tag) {
+ $hashtags[] = '#'.$tag;
+ $attrs = array('href' => Notice_tag::url($tag),
+ 'rel' => $tag,
+ 'class' => 'tag');
+ $taglinks[] = XMLStringer::estring('a', $attrs, $tag);
+ }
+
+ // Use user's preferences for short URLs, if possible
+
+ try {
+ $user = User::getKV('id', $profile->id);
+
+ $shortUrl = File_redirection::makeShort($url,
+ empty($user) ? null : $user);
+ } catch (Exception $e) {
+ // Don't let this stop us.
+ $shortUrl = $url;
+ }
+
+ // TRANS: Bookmark content.
+ // TRANS: %1$s is a title, %2$s is a short URL, %3$s is the bookmark description,
+ // TRANS: %4$s is space separated list of hash tags.
+ $content = sprintf(_m('"%1$s" %2$s %3$s %4$s'),
+ $title,
+ $shortUrl,
+ $description,
+ implode(' ', $hashtags));
+
+ // TRANS: Rendered bookmark content.
+ // TRANS: %1$s is a URL, %2$s the bookmark title, %3$s is the bookmark description,
+ // TRANS: %4$s is space separated list of hash tags.
+ $rendered = sprintf(_m('<span class="xfolkentry">'.
+ '<a class="taggedlink" href="%1$s">%2$s</a> '.
+ '<span class="description">%3$s</span> '.
+ '<span class="meta">%4$s</span>'.
+ '</span>'),
+ htmlspecialchars($url),
+ htmlspecialchars($title),
+ htmlspecialchars($description),
+ implode(' ', $taglinks));
+
+ $options = array_merge(array('urls' => array($url),
+ 'rendered' => $rendered,
+ 'tags' => $tags,
+ 'replies' => $replies,
+ 'object_type' => ActivityObject::BOOKMARK),
+ $options);
+
+ if (!array_key_exists('uri', $options)) {
+ $options['uri'] = $nb->uri;
+ }
+
+ try {
+ $saved = Notice::saveNew($profile->id,
+ $content,
+ array_key_exists('source', $options) ?
+ $options['source'] : 'web',
+ $options);
+ } catch (Exception $e) {
+ $nb->delete();
+ throw $e;
+ }
+
+ if (empty($saved)) {
+ $nb->delete();
+ }
+
+ return $saved;
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Importer class for Delicious.com backups
- *
- * PHP version 5
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Importer class for Delicious bookmarks
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class DeliciousBackupImporter extends QueueHandler
-{
- /**
- * Transport of the importer
- *
- * @return string transport string
- */
- function transport()
- {
- return 'dlcsback';
- }
-
- /**
- * Import an in-memory bookmark list to a user's account
- *
- * Take a delicious.com backup file (same as Netscape bookmarks.html)
- * and import to StatusNet as Bookmark activities.
- *
- * The document format is terrible. It consists of a <dl> with
- * a bunch of <dt>'s, occasionally with <dd>'s adding descriptions.
- * There are sometimes <p>'s lost inside.
- *
- * @param array $data pair of user, text
- *
- * @return boolean success value
- */
- function handle($data)
- {
- list($user, $body) = $data;
-
- try {
- $doc = $this->importHTML($body);
- } catch (ClientException $cex) {
- // XXX: message to the user
- common_log(LOG_WARNING, $cex->getMessage());
- return true;
- }
-
- // If we can't parse it, it's no good
-
- if (empty($doc)) {
- return true;
- }
-
- $dls = $doc->getElementsByTagName('dl');
-
- if ($dls->length != 1) {
- // XXX: message to the user
- common_log(LOG_WARNING, 'Bad input file');
- return true;
- }
-
- $dl = $dls->item(0);
-
- $children = $dl->childNodes;
-
- $dt = null;
-
- for ($i = 0; $i < $children->length; $i++) {
- try {
- $child = $children->item($i);
- if ($child->nodeType != XML_ELEMENT_NODE) {
- continue;
- }
- switch (strtolower($child->tagName)) {
- case 'dt':
- // <dt> nodes contain primary information about a bookmark.
- // We can't import the current one just yet though, since
- // it may be followed by a <dd>.
- if (!empty($dt)) {
- // No DD provided
- $this->importBookmark($user, $dt);
- $dt = null;
- }
- $dt = $child;
- break;
- case 'dd':
- $dd = $child;
-
- if (!empty($dt)) {
- // This <dd> contains a description for the bookmark in
- // the preceding <dt> node.
- $saved = $this->importBookmark($user, $dt, $dd);
- }
-
- $dt = null;
- $dd = null;
- break;
- case 'p':
- common_log(LOG_INFO, 'Skipping the <p> in the <dl>.');
- break;
- default:
- common_log(LOG_WARNING,
- "Unexpected element $child->tagName ".
- " found in import.");
- }
- } catch (Exception $e) {
- common_log(LOG_ERR, $e->getMessage());
- $dt = $dd = null;
- }
- }
- if (!empty($dt)) {
- // There was a final bookmark without a description.
- try {
- $this->importBookmark($user, $dt);
- } catch (Exception $e) {
- common_log(LOG_ERR, $e->getMessage());
- }
- }
-
- return true;
- }
-
- /**
- * Import a single bookmark
- *
- * Takes a <dt>/<dd> pair. The <dt> has a single
- * <a> in it with some non-standard attributes.
- *
- * A <dt><dt><dd> sequence will appear as a <dt> with
- * anothe <dt> as a child. We handle this case recursively.
- *
- * @param User $user User to import data as
- * @param DOMElement $dt <dt> element
- * @param DOMElement $dd <dd> element
- *
- * @return Notice imported notice
- */
- function importBookmark($user, $dt, $dd = null)
- {
- $as = $dt->getElementsByTagName('a');
-
- if ($as->length == 0) {
- // TRANS: Client exception thrown when a bookmark in an import file is incorrectly formatted.
- throw new ClientException(_m("No <A> tag in a <DT>."));
- }
-
- $a = $as->item(0);
-
- $private = $a->getAttribute('private');
-
- if ($private != 0) {
- // TRANS: Client exception thrown when a bookmark in an import file is private.
- throw new ClientException(_m('Skipping private bookmark.'));
- }
-
- if (!empty($dd)) {
- $description = $dd->nodeValue;
- } else {
- $description = null;
- }
- $addDate = $a->getAttribute('add_date');
-
- $data = array(
- 'profile_id' => $user->id,
- 'title' => $a->nodeValue,
- 'description' => $description,
- 'url' => $a->getAttribute('href'),
- 'tags' => $a->getAttribute('tags'),
- 'created' => common_sql_date(intval($addDate))
- );
-
- $qm = QueueManager::get();
- $qm->enqueue($data, 'dlcsbkmk');
- }
-
- /**
- * Parse some HTML
- *
- * Hides the errors that the dom parser returns
- *
- * @param string $body Data to import
- *
- * @return DOMDocument parsed document
- */
-
- function importHTML($body)
- {
- // DOMDocument::loadHTML may throw warnings on unrecognized elements,
- // and notices on unrecognized namespaces.
- $old = error_reporting(error_reporting() & ~(E_WARNING | E_NOTICE));
- $dom = new DOMDocument();
- $ok = $dom->loadHTML($body);
- error_reporting($old);
-
- if ($ok) {
- foreach ($dom->getElementsByTagName('body') as $node) {
- $this->fixListsIn($node);
- }
- return $dom;
- } else {
- return null;
- }
- }
-
-
- function fixListsIn(DOMNode $body) {
- $toFix = array();
-
- foreach ($body->childNodes as $node) {
- if ($node->nodeType == XML_ELEMENT_NODE) {
- $el = strtolower($node->nodeName);
- if ($el == 'dl') {
- $toFix[] = $node;
- }
- }
- }
-
- foreach ($toFix as $node) {
- $this->fixList($node);
- }
- }
-
- function fixList(DOMNode $list) {
- $toFix = array();
-
- foreach ($list->childNodes as $node) {
- if ($node->nodeType == XML_ELEMENT_NODE) {
- $el = strtolower($node->nodeName);
- if ($el == 'dt' || $el == 'dd') {
- $toFix[] = $node;
- }
- if ($el == 'dl') {
- // Sublist.
- // Technically, these can only appear inside a <dd>...
- $this->fixList($node);
- }
- }
- }
-
- foreach ($toFix as $node) {
- $this->fixListItem($node);
- }
- }
-
- function fixListItem(DOMNode $item) {
- // The HTML parser in libxml2 doesn't seem to properly handle
- // many cases of implied close tags, apparently because it doesn't
- // understand the nesting rules specified in the HTML DTD.
- //
- // This leads to sequences of adjacent <dt>s or <dd>s being incorrectly
- // interpreted as parent->child trees instead of siblings:
- //
- // When parsing this input: "<dt>aaa <dt>bbb"
- // should be equivalent to: "<dt>aaa </dt><dt>bbb</dt>"
- // but we're seeing instead: "<dt>aaa <dt>bbb</dt></dt>"
- //
- // It does at least know that going from dt to dd, or dd to dt,
- // should make a break.
-
- $toMove = array();
-
- foreach ($item->childNodes as $node) {
- if ($node->nodeType == XML_ELEMENT_NODE) {
- $el = strtolower($node->nodeName);
- if ($el == 'dt' || $el == 'dd') {
- // dt & dd cannot contain each other;
- // This node was incorrectly placed; move it up a level!
- $toMove[] = $node;
- }
- if ($el == 'dl') {
- // Sublist.
- // Technically, these can only appear inside a <dd>.
- $this->fixList($node);
- }
- }
- }
-
- $parent = $item->parentNode;
- $next = $item->nextSibling;
- foreach ($toMove as $node) {
- $item->removeChild($node);
- $parent->insertBefore($node, $next);
- $this->fixListItem($node);
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Importer class for Delicious.com bookmarks
- *
- * PHP version 5
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Importer class for Delicious bookmarks
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class DeliciousBookmarkImporter extends QueueHandler
-{
- /**
- * Return the transport for this queue handler
- *
- * @return string 'dlcsbkmk'
- */
- function transport()
- {
- return 'dlcsbkmk';
- }
-
- /**
- * Handle the data
- *
- * @param array $data associative array of user & bookmark info from DeliciousBackupImporter::importBookmark()
- *
- * @return boolean success value
- */
- function handle($data)
- {
- $profile = Profile::getKV('id', $data['profile_id']);
-
- try {
- $saved = Bookmark::saveNew($profile,
- $data['title'],
- $data['url'],
- $data['tags'],
- $data['description'],
- array('created' => $data['created'],
- 'distribute' => false));
- } catch (ClientException $ce) {
- // Most likely a duplicate -- continue on with the rest!
- common_log(LOG_ERR, "Error importing delicious bookmark to $data[url]: " . $ce->getMessage());
- return true;
- } catch (Exception $ex) {
- if (preg_match("/DB Error: already exists/", $ex->getMessage())) {
- common_log(LOG_ERR, "Error importing delicious bookmark to $data[url]: " . $ce->getMessage());
- return true;
- } else {
- throw $ex;
- }
- }
-
- return true;
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Form for adding a new bookmark
+ *
+ * PHP version 5
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form to add a new bookmark
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class BookmarkForm extends Form
+{
+ private $_title = null;
+ private $_url = null;
+ private $_tags = null;
+ private $_description = null;
+ private $_thumbnail = null;
+
+ /**
+ * Construct a bookmark form
+ *
+ * @param HTMLOutputter $out output channel
+ * @param string $title Title of the bookmark
+ * @param string $url URL of the bookmark
+ * @param string $tags Tags to show
+ * @param string $description Description of the bookmark
+ *
+ * @return void
+ */
+ function __construct($out=null, $title=null, $url=null, $tags=null,
+ $description=null, $thumbnail=null)
+ {
+ parent::__construct($out);
+
+ $this->_title = $title;
+ $this->_url = $url;
+ $this->_tags = $tags;
+ $this->_description = $description;
+ $this->_thumbnail = $thumbnail;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'form_new_bookmark';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings ajax-notice';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('newbookmark');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'new_bookmark_data'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('bookmark-url',
+ // TRANS: Field label on form for adding a new bookmark.
+ _m('LABEL','URL'),
+ $this->_url,
+ null,
+ 'url');
+ $this->unli();
+
+ if (!empty($this->_thumbnail)) {
+
+ list($width, $height) = $this->scaleImage($this->_thumbnail->width,
+ $this->_thumbnail->height);
+
+ $this->out->element('img',
+ array('src' => $this->_thumbnail->url,
+ 'class' => 'bookmarkform-thumbnail',
+ 'width' => $width,
+ 'height' => $height));
+ }
+
+ $this->li();
+ $this->out->input('bookmark-title',
+ // TRANS: Field label on form for adding a new bookmark.
+ _m('LABEL','Title'),
+ $this->_title,
+ null,
+ 'title');
+ $this->unli();
+
+ $this->li();
+ $this->out->textarea('bookmark-description',
+ // TRANS: Field label on form for adding a new bookmark.
+ _m('LABEL','Notes'),
+ $this->_description,
+ null,
+ 'description');
+ $this->unli();
+
+ $this->li();
+ $this->out->input('bookmark-tags',
+ // TRANS: Field label on form for adding a new bookmark.
+ _m('LABEL','Tags'),
+ $this->_tags,
+ // TRANS: Field title on form for adding a new bookmark.
+ _m('Comma- or space-separated list of tags.'),
+ 'tags');
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+
+ $toWidget = new ToSelector($this->out,
+ common_current_user(),
+ null);
+ $toWidget->show();
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ // TRANS: Button text for action to save a new bookmark.
+ $this->out->submit('bookmark-submit', _m('BUTTON', 'Save'), 'submit', 'submit');
+ }
+
+ function scaleImage($width, $height)
+ {
+ $maxwidth = common_config('attachments', 'thumb_width');
+ $maxheight = common_config('attachments', 'thumb_height');
+
+ if ($width > $height && $width > $maxwidth) {
+ $height = (int) ((((float)$maxwidth)/(float)($width))*(float)$height);
+ $width = $maxwidth;
+ } else if ($height > $maxheight) {
+ $width = (int) ((((float)$maxheight)/(float)($height))*(float)$width);
+ $height = $maxheight;
+ }
+
+ return array($width, $height);
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * First bookmark form, with just the URL
+ *
+ * PHP version 5
+ *
+ * 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 Form
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * First bookmark form, with just the URL
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class InitialBookmarkForm extends Form
+{
+ function __construct($out=null)
+ {
+ parent::__construct($out);
+ }
+
+ function id()
+ {
+ return 'form_initial_bookmark';
+ }
+
+ function formClass()
+ {
+ return 'form_settings ajax';
+ }
+
+ function action()
+ {
+ return common_local_url('bookmarkforurl');
+ }
+
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'initial_bookmark_data'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('initial-bookmark-url',
+ // TRANS: Field label on form for adding a new bookmark.
+ _m('LABEL','URL'),
+ null,
+ null,
+ 'url');
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('fieldset');
+ }
+
+ function formActions()
+ {
+ // TRANS: Button text for action to save a new bookmark.
+ $this->out->submit('initial-bookmark-submit', _m('BUTTON', 'Add'), 'submit', 'submit');
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010 StatusNet, Inc.
- *
- * Import a bookmarks file as notices
- *
- * PHP version 5
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
-
-$shortoptions = 'i:n:f:';
-$longoptions = array('id=', 'nickname=', 'file=');
-
-$helptext = <<<END_OF_IMPORTBOOKMARKS_HELP
-importbookmarks.php [options]
-Restore a backed-up Delicious.com bookmark file
-
--i --id ID of user to import bookmarks for
--n --nickname nickname of the user to import for
--f --file file to read from (STDIN by default)
-END_OF_IMPORTBOOKMARKS_HELP;
-
-require_once INSTALLDIR.'/scripts/commandline.inc';
-
-/**
- * Get the bookmarks file as a string
- *
- * Uses the -f or --file parameter to open and read a
- * a bookmarks file
- *
- * @return string Contents of the file
- */
-
-function getBookmarksFile()
-{
- $filename = get_option_value('f', 'file');
-
- if (empty($filename)) {
- show_help();
- exit(1);
- }
-
- if (!file_exists($filename)) {
- // TRANS: Exception thrown when a file upload cannot be found.
- // TRANS: %s is the file that could not be found.
- throw new Exception(sprintf(_m('No such file "%s".'),$filename));
- }
-
- if (!is_file($filename)) {
- // TRANS: Exception thrown when a file upload is incorrect.
- // TRANS: %s is the irregular file.
- throw new Exception(sprintf(_m('Not a regular file: "%s".'),$filename));
- }
-
- if (!is_readable($filename)) {
- // TRANS: Exception thrown when a file upload is not readable.
- // TRANS: %s is the file that could not be read.
- throw new Exception(sprintf(_m('File "%s" not readable.'),$filename));
- }
-
- // TRANS: %s is the filename that contains a backup for a user.
- printfv(_m('Getting backup from file "%s".')."\n", $filename);
-
- $html = file_get_contents($filename);
-
- return $html;
-}
-
-try {
- $user = getUser();
- $html = getBookmarksFile();
-
- $qm = QueueManager::get();
-
- $qm->enqueue(array($user, $html), 'dlcsback');
-
-} catch (Exception $e) {
- print $e->getMessage()."\n";
- exit(1);
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Import del.icio.us bookmarks backups
- *
- * PHP version 5
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * UI for importing del.icio.us bookmark backups
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ImportdeliciousAction extends Action
-{
- protected $success = false;
- private $inprogress = false;
-
- /**
- * Return the title of the page
- *
- * @return string page title
- */
- function title()
- {
- // TRANS: Title for page to import del.icio.us bookmark backups on.
- return _m("Import del.icio.us bookmarks");
- }
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- $cur = common_current_user();
-
- if (empty($cur)) {
- // TRANS: Client exception thrown when trying to import bookmarks without being logged in.
- throw new ClientException(_m('Only logged-in users can '.
- 'import del.icio.us backups.'),
- 403);
- }
-
- if (!$cur->hasRight(BookmarkPlugin::IMPORTDELICIOUS)) {
- // TRANS: Client exception thrown when trying to import bookmarks without having the rights to do so.
- throw new ClientException(_m('You may not restore your account.'), 403);
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- parent::handle($argarray);
-
- if ($this->isPost()) {
- $this->importDelicious();
- } else {
- $this->showPage();
- }
- return;
- }
-
- /**
- * Queue a file for importation
- *
- * Uses the DeliciousBackupImporter class; may take a long time!
- *
- * @return void
- */
- function importDelicious()
- {
- $this->checkSessionToken();
-
- if (!isset($_FILES[ImportDeliciousForm::FILEINPUT]['error'])) {
- // TRANS: Client exception thrown when trying to import bookmarks and upload fails.
- throw new ClientException(_m('No uploaded file.'));
- }
-
- switch ($_FILES[ImportDeliciousForm::FILEINPUT]['error']) {
- case UPLOAD_ERR_OK: // success, jump out
- break;
- case UPLOAD_ERR_INI_SIZE:
- // TRANS: Client exception thrown when an uploaded file is too large.
- throw new ClientException(_m('The uploaded file exceeds the ' .
- 'upload_max_filesize directive in php.ini.'));
- return;
- case UPLOAD_ERR_FORM_SIZE:
- throw new ClientException(
- // TRANS: Client exception thrown when an uploaded file is too large.
- _m('The uploaded file exceeds the MAX_FILE_SIZE directive' .
- ' that was specified in the HTML form.'));
- return;
- case UPLOAD_ERR_PARTIAL:
- @unlink($_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name']);
- // TRANS: Client exception thrown when a file was only partially uploaded.
- throw new ClientException(_m('The uploaded file was only' .
- ' partially uploaded.'));
- return;
- case UPLOAD_ERR_NO_FILE:
- // No file; probably just a non-AJAX submission.
- // TRANS: Client exception thrown when a file upload has failed.
- throw new ClientException(_m('No uploaded file.'));
- return;
- case UPLOAD_ERR_NO_TMP_DIR:
- // TRANS: Client exception thrown when a temporary folder is not present.
- throw new ClientException(_m('Missing a temporary folder.'));
- return;
- case UPLOAD_ERR_CANT_WRITE:
- // TRANS: Client exception thrown when writing to disk is not possible.
- throw new ClientException(_m('Failed to write file to disk.'));
- return;
- case UPLOAD_ERR_EXTENSION:
- // TRANS: Client exception thrown when a file upload has been stopped.
- throw new ClientException(_m('File upload stopped by extension.'));
- return;
- default:
- common_log(LOG_ERR, __METHOD__ . ": Unknown upload error " .
- $_FILES[ImportDeliciousForm::FILEINPUT]['error']);
- // TRANS: Client exception thrown when a file upload operation has failed.
- throw new ClientException(_m('System error uploading file.'));
- return;
- }
-
- $filename = $_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name'];
-
- try {
- if (!file_exists($filename)) {
- // TRANS: Server exception thrown when a file upload cannot be found.
- // TRANS: %s is the file that could not be found.
- throw new ServerException(sprintf(_m('No such file "%s".'),$filename));
- }
-
- if (!is_file($filename)) {
- // TRANS: Server exception thrown when a file upload is incorrect.
- // TRANS: %s is the irregular file.
- throw new ServerException(sprintf(_m('Not a regular file: "%s".'),$filename));
- }
-
- if (!is_readable($filename)) {
- // TRANS: Server exception thrown when a file upload is not readable.
- // TRANS: %s is the file that could not be read.
- throw new ServerException(sprintf(_m('File "%s" not readable.'),$filename));
- }
-
- common_debug(sprintf("Getting backup from file '%s'.", $filename));
-
- $html = file_get_contents($filename);
-
- // Enqueue for processing.
-
- $qm = QueueManager::get();
- $qm->enqueue(array(common_current_user(), $html), 'dlcsback');
-
- if ($qm instanceof UnQueueManager) {
- // No active queuing means we've actually just completed the job!
- $this->success = true;
- } else {
- // We've fed data into background queues, and it's probably still running.
- $this->inprogress = true;
- }
-
- $this->showPage();
-
- } catch (Exception $e) {
- // Delete the file and re-throw
- @unlink($_FILES[ImportDeliciousForm::FILEINPUT]['tmp_name']);
- throw $e;
- }
- }
-
- /**
- * Show the content of the page
- *
- * @return void
- */
- function showContent()
- {
- if ($this->success) {
- $this->element('p', null,
- // TRANS: Success message after importing bookmarks.
- _m('Bookmarks have been imported. Your bookmarks should now appear in search and your profile page.'));
- } else if ($this->inprogress) {
- $this->element('p', null,
- // TRANS: Busy message for importing bookmarks.
- _m('Bookmarks are being imported. Please wait a few minutes for results.'));
- } else {
- $form = new ImportDeliciousForm($this);
- $form->show();
- }
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return !$this->isPost();
- }
-}
-
-/**
- * A form for backing up the account.
- *
- * @category Account
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ImportDeliciousForm extends Form
-{
- const FILEINPUT = 'deliciousbackupfile';
-
- /**
- * Constructor
- *
- * Set the encoding type, since this is a file upload.
- *
- * @param HTMLOutputter $out output channel
- *
- * @return ImportDeliciousForm this
- */
- function __construct($out=null)
- {
- parent::__construct($out);
- $this->enctype = 'multipart/form-data';
- }
-
- /**
- * Class of the form.
- *
- * @return string the form's class
- */
- function formClass()
- {
- return 'form_import_delicious';
- }
-
- /**
- * URL the form posts to
- *
- * @return string the form's action URL
- */
- function action()
- {
- return common_local_url('importdelicious');
- }
-
- /**
- * Output form data
- *
- * Really, just instructions for doing a backup.
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('p', 'instructions');
-
- // TRANS: Form instructions for importing bookmarks.
- $this->out->raw(_m('You can upload a backed-up '.
- 'delicious.com bookmarks file.'));
-
- $this->out->elementEnd('p');
-
- $this->out->elementStart('ul', 'form_data');
-
- $this->out->elementStart('li', array ('id' => 'settings_attach'));
- $this->out->element('input', array('name' => self::FILEINPUT,
- 'type' => 'file',
- 'id' => self::FILEINPUT));
- $this->out->elementEnd('li');
-
- $this->out->elementEnd('ul');
- }
-
- /**
- * Buttons for the form
- *
- * In this case, a single submit button
- *
- * @return void
- */
-
- function formActions()
- {
- $this->out->submit('submit',
- // TRANS: Button text on form to import bookmarks.
- _m('BUTTON', 'Upload'),
- 'submit',
- null,
- // TRANS: Button title on form to import bookmarks.
- _m('Upload the file.'));
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * First bookmark form, with just the URL
- *
- * PHP version 5
- *
- * 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 Form
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * First bookmark form, with just the URL
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class InitialBookmarkForm extends Form
-{
- function __construct($out=null)
- {
- parent::__construct($out);
- }
-
- function id()
- {
- return 'form_initial_bookmark';
- }
-
- function formClass()
- {
- return 'form_settings ajax';
- }
-
- function action()
- {
- return common_local_url('bookmarkforurl');
- }
-
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'initial_bookmark_data'));
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->out->input('initial-bookmark-url',
- // TRANS: Field label on form for adding a new bookmark.
- _m('LABEL','URL'),
- null,
- null,
- 'url');
- $this->unli();
-
- $this->out->elementEnd('ul');
- $this->out->elementEnd('fieldset');
- }
-
- function formActions()
- {
- // TRANS: Button text for action to save a new bookmark.
- $this->out->submit('initial-bookmark-submit', _m('BUTTON', 'Add'), 'submit', 'submit');
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Adapter to show bookmarks in a nicer way
+ *
+ * PHP version 5
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * An adapter to show bookmarks in a nicer way
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class BookmarkListItem extends NoticeListItemAdapter
+{
+ function showNotice()
+ {
+ $this->nli->out->elementStart('div', 'entry-title');
+ $this->nli->showAuthor();
+ $this->showContent();
+ $this->nli->out->elementEnd('div');
+ }
+
+ function showContent()
+ {
+ $notice = $this->nli->notice;
+ $out = $this->nli->out;
+
+ $nb = Bookmark::getByNotice($notice);
+
+ if (empty($nb)) {
+ common_log(LOG_ERR, "No bookmark for notice {$notice->id}");
+ parent::showContent();
+ return;
+ } else if (empty($nb->url)) {
+ common_log(LOG_ERR, "No url for bookmark {$nb->id} for notice {$notice->id}");
+ parent::showContent();
+ return;
+ }
+
+ $profile = $notice->getProfile();
+
+ $out->elementStart('p', array('class' => 'entry-content'));
+
+ // Whether to nofollow
+
+ $attrs = array('href' => $nb->url,
+ 'class' => 'bookmark-title');
+
+ $nf = common_config('nofollow', 'external');
+
+ if ($nf == 'never' || ($nf == 'sometimes' and $out instanceof ShowstreamAction)) {
+ $attrs['rel'] = 'external';
+ } else {
+ $attrs['rel'] = 'nofollow external';
+ }
+
+ $out->elementStart('h3');
+ $out->element('a',
+ $attrs,
+ $nb->title);
+ $out->elementEnd('h3');
+
+ // Replies look like "for:" tags
+
+ $replies = $notice->getReplies();
+ $tags = $notice->getTags();
+
+ if (!empty($replies) || !empty($tags)) {
+
+ $out->elementStart('ul', array('class' => 'bookmark-tags'));
+
+ foreach ($replies as $reply) {
+ $other = Profile::getKV('id', $reply);
+ if (!empty($other)) {
+ $out->elementStart('li');
+ $out->element('a', array('rel' => 'tag',
+ 'href' => $other->profileurl,
+ 'title' => $other->getBestName()),
+ sprintf('for:%s', $other->nickname));
+ $out->elementEnd('li');
+ $out->text(' ');
+ }
+ }
+
+ foreach ($tags as $tag) {
+ $tag = trim($tag);
+ if (!empty($tag)) {
+ $out->elementStart('li');
+ $out->element('a',
+ array('rel' => 'tag',
+ 'href' => Notice_tag::url($tag)),
+ $tag);
+ $out->elementEnd('li');
+ $out->text(' ');
+ }
+ }
+
+ $out->elementEnd('ul');
+ }
+
+ if (!empty($nb->description)) {
+ $out->element('p',
+ array('class' => 'bookmark-description'),
+ $nb->description);
+ }
+
+ $out->elementEnd('p');
+ }
+}
--- /dev/null
+<?php
+
+class RawBookmarksNoticeStream extends NoticeStream
+{
+ protected $user_id;
+ protected $own;
+
+ function __construct($user_id, $own)
+ {
+ $this->user_id = $user_id;
+ $this->own = $own;
+ }
+
+ function getNoticeIds($offset, $limit, $since_id, $max_id)
+ {
+ $notice = new Notice();
+ $qry = null;
+
+ $qry = 'SELECT notice.* FROM notice ';
+ $qry .= 'INNER JOIN bookmark ON bookmark.uri = notice.uri ';
+ $qry .= 'WHERE bookmark.profile_id = ' . $this->user_id . ' ';
+ $qry .= 'AND notice.is_local != ' . Notice::GATEWAY . ' ';
+
+ if ($since_id != 0) {
+ $qry .= 'AND notice.id > ' . $since_id . ' ';
+ }
+
+ if ($max_id != 0) {
+ $qry .= 'AND notice.id <= ' . $max_id . ' ';
+ }
+
+ // NOTE: we sort by bookmark time, not by notice time!
+ $qry .= 'ORDER BY created DESC ';
+ if (!is_null($offset)) {
+ $qry .= "LIMIT $limit OFFSET $offset";
+ }
+
+ $notice->query($qry);
+ $ids = array();
+ while ($notice->fetch()) {
+ $ids[] = $notice->id;
+ }
+
+ $notice->free();
+ unset($notice);
+ return $ids;
+ }
+}
+
+/**
+ * Notice stream for bookmarks
+ *
+ * @category Stream
+ * @package StatusNet
+ * @author Stephane Berube <chimo@chromic.org>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class BookmarksNoticeStream extends ScopingNoticeStream
+{
+ function __construct($user_id, $own, $profile = -1)
+ {
+ $stream = new RawBookmarksNoticeStream($user_id, $own);
+
+ if ($own) {
+ $key = 'bookmark:ids_by_user_own:'.$user_id;
+ } else {
+ $key = 'bookmark:ids_by_user:'.$user_id;
+ }
+
+ if (is_int($profile) && $profile == -1) {
+ $profile = Profile::current();
+ }
+
+ parent::__construct(new CachingNoticeStream($stream, $key),
+ $profile);
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Importer class for Delicious.com backups
+ *
+ * PHP version 5
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Importer class for Delicious bookmarks
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class DeliciousBackupImporter extends QueueHandler
+{
+ /**
+ * Transport of the importer
+ *
+ * @return string transport string
+ */
+ function transport()
+ {
+ return 'dlcsback';
+ }
+
+ /**
+ * Import an in-memory bookmark list to a user's account
+ *
+ * Take a delicious.com backup file (same as Netscape bookmarks.html)
+ * and import to StatusNet as Bookmark activities.
+ *
+ * The document format is terrible. It consists of a <dl> with
+ * a bunch of <dt>'s, occasionally with <dd>'s adding descriptions.
+ * There are sometimes <p>'s lost inside.
+ *
+ * @param array $data pair of user, text
+ *
+ * @return boolean success value
+ */
+ function handle($data)
+ {
+ list($user, $body) = $data;
+
+ try {
+ $doc = $this->importHTML($body);
+ } catch (ClientException $cex) {
+ // XXX: message to the user
+ common_log(LOG_WARNING, $cex->getMessage());
+ return true;
+ }
+
+ // If we can't parse it, it's no good
+
+ if (empty($doc)) {
+ return true;
+ }
+
+ $dls = $doc->getElementsByTagName('dl');
+
+ if ($dls->length != 1) {
+ // XXX: message to the user
+ common_log(LOG_WARNING, 'Bad input file');
+ return true;
+ }
+
+ $dl = $dls->item(0);
+
+ $children = $dl->childNodes;
+
+ $dt = null;
+
+ for ($i = 0; $i < $children->length; $i++) {
+ try {
+ $child = $children->item($i);
+ if ($child->nodeType != XML_ELEMENT_NODE) {
+ continue;
+ }
+ switch (strtolower($child->tagName)) {
+ case 'dt':
+ // <dt> nodes contain primary information about a bookmark.
+ // We can't import the current one just yet though, since
+ // it may be followed by a <dd>.
+ if (!empty($dt)) {
+ // No DD provided
+ $this->importBookmark($user, $dt);
+ $dt = null;
+ }
+ $dt = $child;
+ break;
+ case 'dd':
+ $dd = $child;
+
+ if (!empty($dt)) {
+ // This <dd> contains a description for the bookmark in
+ // the preceding <dt> node.
+ $saved = $this->importBookmark($user, $dt, $dd);
+ }
+
+ $dt = null;
+ $dd = null;
+ break;
+ case 'p':
+ common_log(LOG_INFO, 'Skipping the <p> in the <dl>.');
+ break;
+ default:
+ common_log(LOG_WARNING,
+ "Unexpected element $child->tagName ".
+ " found in import.");
+ }
+ } catch (Exception $e) {
+ common_log(LOG_ERR, $e->getMessage());
+ $dt = $dd = null;
+ }
+ }
+ if (!empty($dt)) {
+ // There was a final bookmark without a description.
+ try {
+ $this->importBookmark($user, $dt);
+ } catch (Exception $e) {
+ common_log(LOG_ERR, $e->getMessage());
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Import a single bookmark
+ *
+ * Takes a <dt>/<dd> pair. The <dt> has a single
+ * <a> in it with some non-standard attributes.
+ *
+ * A <dt><dt><dd> sequence will appear as a <dt> with
+ * anothe <dt> as a child. We handle this case recursively.
+ *
+ * @param User $user User to import data as
+ * @param DOMElement $dt <dt> element
+ * @param DOMElement $dd <dd> element
+ *
+ * @return Notice imported notice
+ */
+ function importBookmark($user, $dt, $dd = null)
+ {
+ $as = $dt->getElementsByTagName('a');
+
+ if ($as->length == 0) {
+ // TRANS: Client exception thrown when a bookmark in an import file is incorrectly formatted.
+ throw new ClientException(_m("No <A> tag in a <DT>."));
+ }
+
+ $a = $as->item(0);
+
+ $private = $a->getAttribute('private');
+
+ if ($private != 0) {
+ // TRANS: Client exception thrown when a bookmark in an import file is private.
+ throw new ClientException(_m('Skipping private bookmark.'));
+ }
+
+ if (!empty($dd)) {
+ $description = $dd->nodeValue;
+ } else {
+ $description = null;
+ }
+ $addDate = $a->getAttribute('add_date');
+
+ $data = array(
+ 'profile_id' => $user->id,
+ 'title' => $a->nodeValue,
+ 'description' => $description,
+ 'url' => $a->getAttribute('href'),
+ 'tags' => $a->getAttribute('tags'),
+ 'created' => common_sql_date(intval($addDate))
+ );
+
+ $qm = QueueManager::get();
+ $qm->enqueue($data, 'dlcsbkmk');
+ }
+
+ /**
+ * Parse some HTML
+ *
+ * Hides the errors that the dom parser returns
+ *
+ * @param string $body Data to import
+ *
+ * @return DOMDocument parsed document
+ */
+
+ function importHTML($body)
+ {
+ // DOMDocument::loadHTML may throw warnings on unrecognized elements,
+ // and notices on unrecognized namespaces.
+ $old = error_reporting(error_reporting() & ~(E_WARNING | E_NOTICE));
+ $dom = new DOMDocument();
+ $ok = $dom->loadHTML($body);
+ error_reporting($old);
+
+ if ($ok) {
+ foreach ($dom->getElementsByTagName('body') as $node) {
+ $this->fixListsIn($node);
+ }
+ return $dom;
+ } else {
+ return null;
+ }
+ }
+
+
+ function fixListsIn(DOMNode $body) {
+ $toFix = array();
+
+ foreach ($body->childNodes as $node) {
+ if ($node->nodeType == XML_ELEMENT_NODE) {
+ $el = strtolower($node->nodeName);
+ if ($el == 'dl') {
+ $toFix[] = $node;
+ }
+ }
+ }
+
+ foreach ($toFix as $node) {
+ $this->fixList($node);
+ }
+ }
+
+ function fixList(DOMNode $list) {
+ $toFix = array();
+
+ foreach ($list->childNodes as $node) {
+ if ($node->nodeType == XML_ELEMENT_NODE) {
+ $el = strtolower($node->nodeName);
+ if ($el == 'dt' || $el == 'dd') {
+ $toFix[] = $node;
+ }
+ if ($el == 'dl') {
+ // Sublist.
+ // Technically, these can only appear inside a <dd>...
+ $this->fixList($node);
+ }
+ }
+ }
+
+ foreach ($toFix as $node) {
+ $this->fixListItem($node);
+ }
+ }
+
+ function fixListItem(DOMNode $item) {
+ // The HTML parser in libxml2 doesn't seem to properly handle
+ // many cases of implied close tags, apparently because it doesn't
+ // understand the nesting rules specified in the HTML DTD.
+ //
+ // This leads to sequences of adjacent <dt>s or <dd>s being incorrectly
+ // interpreted as parent->child trees instead of siblings:
+ //
+ // When parsing this input: "<dt>aaa <dt>bbb"
+ // should be equivalent to: "<dt>aaa </dt><dt>bbb</dt>"
+ // but we're seeing instead: "<dt>aaa <dt>bbb</dt></dt>"
+ //
+ // It does at least know that going from dt to dd, or dd to dt,
+ // should make a break.
+
+ $toMove = array();
+
+ foreach ($item->childNodes as $node) {
+ if ($node->nodeType == XML_ELEMENT_NODE) {
+ $el = strtolower($node->nodeName);
+ if ($el == 'dt' || $el == 'dd') {
+ // dt & dd cannot contain each other;
+ // This node was incorrectly placed; move it up a level!
+ $toMove[] = $node;
+ }
+ if ($el == 'dl') {
+ // Sublist.
+ // Technically, these can only appear inside a <dd>.
+ $this->fixList($node);
+ }
+ }
+ }
+
+ $parent = $item->parentNode;
+ $next = $item->nextSibling;
+ foreach ($toMove as $node) {
+ $item->removeChild($node);
+ $parent->insertBefore($node, $next);
+ $this->fixListItem($node);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Importer class for Delicious.com bookmarks
+ *
+ * PHP version 5
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Importer class for Delicious bookmarks
+ *
+ * @category Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class DeliciousBookmarkImporter extends QueueHandler
+{
+ /**
+ * Return the transport for this queue handler
+ *
+ * @return string 'dlcsbkmk'
+ */
+ function transport()
+ {
+ return 'dlcsbkmk';
+ }
+
+ /**
+ * Handle the data
+ *
+ * @param array $data associative array of user & bookmark info from DeliciousBackupImporter::importBookmark()
+ *
+ * @return boolean success value
+ */
+ function handle($data)
+ {
+ $profile = Profile::getKV('id', $data['profile_id']);
+
+ try {
+ $saved = Bookmark::saveNew($profile,
+ $data['title'],
+ $data['url'],
+ $data['tags'],
+ $data['description'],
+ array('created' => $data['created'],
+ 'distribute' => false));
+ } catch (ClientException $ce) {
+ // Most likely a duplicate -- continue on with the rest!
+ common_log(LOG_ERR, "Error importing delicious bookmark to $data[url]: " . $ce->getMessage());
+ return true;
+ } catch (Exception $ex) {
+ if (preg_match("/DB Error: already exists/", $ex->getMessage())) {
+ common_log(LOG_ERR, "Error importing delicious bookmark to $data[url]: " . $ce->getMessage());
+ return true;
+ } else {
+ throw $ex;
+ }
+ }
+
+ return true;
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Add a new bookmark
- *
- * PHP version 5
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Add a new bookmark
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class NewbookmarkAction extends Action
-{
- protected $user = null;
- protected $error = null;
- protected $complete = null;
- protected $title = null;
- protected $url = null;
- protected $tags = null;
- protected $description = null;
-
- /**
- * Returns the title of the action
- *
- * @return string Action title
- */
- function title()
- {
- // TRANS: Title for action to create a new bookmark.
- return _m('New bookmark');
- }
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- if ($this->boolean('ajax')) {
- StatusNet::setApi(true);
- }
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Client exception thrown when trying to create a new bookmark while not logged in.
- throw new ClientException(_m('Must be logged in to post a bookmark.'),
- 403);
- }
-
- if ($this->isPost()) {
- $this->checkSessionToken();
- }
-
- $this->title = $this->trimmed('title');
- $this->url = $this->trimmed('url');
- $this->tags = $this->trimmed('tags');
- $this->description = $this->trimmed('description');
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- parent::handle($argarray);
-
- if ($this->isPost()) {
- $this->newBookmark();
- } else {
- $this->showPage();
- }
-
- return;
- }
-
- /**
- * Add a new bookmark
- *
- * @return void
- */
- function newBookmark()
- {
- try {
- if (empty($this->title)) {
- // TRANS: Client exception thrown when trying to create a new bookmark without a title.
- throw new ClientException(_m('Bookmark must have a title.'));
- }
-
- if (empty($this->url)) {
- // TRANS: Client exception thrown when trying to create a new bookmark without a URL.
- throw new ClientException(_m('Bookmark must have an URL.'));
- }
-
- $options = array();
-
- ToSelector::fillOptions($this, $options);
-
- $saved = Bookmark::saveNew($this->user->getProfile(),
- $this->title,
- $this->url,
- $this->tags,
- $this->description,
- $options);
-
- } catch (ClientException $ce) {
- if ($this->boolean('ajax')) {
- header('Content-Type: text/xml;charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: Page title after an AJAX error occurs
- $this->element('title', null, _('Ajax Error'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $this->element('p', array('id' => 'error'), $ce->getMessage());
- $this->elementEnd('body');
- $this->elementEnd('html');
- return;
- } else {
- $this->error = $ce->getMessage();
- $this->showPage();
- return;
- }
- }
-
- if ($this->boolean('ajax')) {
- header('Content-Type: text/xml;charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: Page title after posting a bookmark.
- $this->element('title', null, _m('Bookmark posted'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $this->showNotice($saved);
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- common_redirect($saved->bestUrl(), 303);
- }
- }
-
- /**
- * Output a notice
- *
- * Used to generate the notice code for Ajax results.
- *
- * @param Notice $notice Notice that was saved
- *
- * @return void
- */
- function showNotice($notice)
- {
- class_exists('NoticeList'); // @fixme hack for autoloader
- $nli = new NoticeListItem($notice, $this);
- $nli->show();
- }
-
- /**
- * Show the bookmark form
- *
- * @return void
- */
- function showContent()
- {
- if (!empty($this->error)) {
- $this->element('p', 'error', $this->error);
- }
-
- $form = new BookmarkForm($this,
- $this->title,
- $this->url,
- $this->tags,
- $this->description);
-
- $form->show();
-
- return;
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
- $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- return true;
- } else {
- return false;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Notice stream of notices with a given attachment
- *
- * PHP version 5
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * List notices that contain/link to/use a given URL
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class NoticebyurlAction extends Action
-{
- protected $url = null;
- protected $file = null;
- protected $notices = null;
- protected $page = null;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- $this->file = File::getKV('id', $this->trimmed('id'));
-
- if (empty($this->file)) {
- // TRANS: Client exception thrown when an unknown URL is provided.
- throw new ClientException(_m('Unknown URL.'));
- }
-
- $pageArg = $this->trimmed('page');
-
- $this->page = (empty($pageArg)) ? 1 : intval($pageArg);
-
- $this->notices = $this->file->stream(($this->page - 1) * NOTICES_PER_PAGE,
- NOTICES_PER_PAGE + 1);
-
- return true;
- }
-
- /**
- * Title of the page
- *
- * @return string page title
- */
- function title()
- {
- if ($this->page == 1) {
- // TRANS: Title of notice stream of notices with a given attachment (first page).
- // TRANS: %s is the URL.
- return sprintf(_m('Notices linking to %s'), $this->file->url);
- } else {
- // TRANS: Title of notice stream of notices with a given attachment (all but first page).
- // TRANS: %1$s is the URL, %2$s is the page number.
- return sprintf(_m('Notices linking to %1$s, page %2$d'),
- $this->file->url,
- $this->page);
- }
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- $this->showPage();
- }
-
- /**
- * Show main page content.
- *
- * Shows a list of the notices that link to the given URL
- *
- * @return void
- */
- function showContent()
- {
- $nl = new NoticeList($this->notices, $this);
-
- $nl->show();
-
- $cnt = $nl->show();
-
- $this->pagination($this->page > 1,
- $cnt > NOTICES_PER_PAGE,
- $this->page,
- 'noticebyurl',
- array('id' => $this->file->id));
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return true;
- }
-
- /**
- * Return last modified, if applicable.
- *
- * MAY override
- *
- * @return string last modified http header
- */
- function lastModified()
- {
- // For comparison with If-Last-Modified
- // If not applicable, return null
- return null;
- }
-
- /**
- * Return etag, if applicable.
- *
- * MAY override
- *
- * @return string etag http header
- */
- function etag()
- {
- return null;
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010 StatusNet, Inc.
+ *
+ * Import a bookmarks file as notices
+ *
+ * PHP version 5
+ *
+ * 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 Bookmark
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
+
+$shortoptions = 'i:n:f:';
+$longoptions = array('id=', 'nickname=', 'file=');
+
+$helptext = <<<END_OF_IMPORTBOOKMARKS_HELP
+importbookmarks.php [options]
+Restore a backed-up Delicious.com bookmark file
+
+-i --id ID of user to import bookmarks for
+-n --nickname nickname of the user to import for
+-f --file file to read from (STDIN by default)
+END_OF_IMPORTBOOKMARKS_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+/**
+ * Get the bookmarks file as a string
+ *
+ * Uses the -f or --file parameter to open and read a
+ * a bookmarks file
+ *
+ * @return string Contents of the file
+ */
+
+function getBookmarksFile()
+{
+ $filename = get_option_value('f', 'file');
+
+ if (empty($filename)) {
+ show_help();
+ exit(1);
+ }
+
+ if (!file_exists($filename)) {
+ // TRANS: Exception thrown when a file upload cannot be found.
+ // TRANS: %s is the file that could not be found.
+ throw new Exception(sprintf(_m('No such file "%s".'),$filename));
+ }
+
+ if (!is_file($filename)) {
+ // TRANS: Exception thrown when a file upload is incorrect.
+ // TRANS: %s is the irregular file.
+ throw new Exception(sprintf(_m('Not a regular file: "%s".'),$filename));
+ }
+
+ if (!is_readable($filename)) {
+ // TRANS: Exception thrown when a file upload is not readable.
+ // TRANS: %s is the file that could not be read.
+ throw new Exception(sprintf(_m('File "%s" not readable.'),$filename));
+ }
+
+ // TRANS: %s is the filename that contains a backup for a user.
+ printfv(_m('Getting backup from file "%s".')."\n", $filename);
+
+ $html = file_get_contents($filename);
+
+ return $html;
+}
+
+try {
+ $user = getUser();
+ $html = getBookmarksFile();
+
+ $qm = QueueManager::get();
+
+ $qm->enqueue(array($user, $html), 'dlcsback');
+
+} catch (Exception $e) {
+ print $e->getMessage()."\n";
+ exit(1);
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Show a single bookmark
- *
- * PHP version 5
- *
- * 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 Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Show a single bookmark, with associated information
- *
- * @category Bookmark
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ShowbookmarkAction extends ShownoticeAction
-{
- protected $bookmark = null;
-
- function getNotice()
- {
- $this->id = $this->trimmed('id');
-
- $this->bookmark = Bookmark::getKV('id', $this->id);
-
- if (empty($this->bookmark)) {
- // TRANS: Client exception thrown when referring to a non-existing bookmark.
- throw new ClientException(_m('No such bookmark.'), 404);
- }
-
- $notice = Notice::getKV('uri', $this->bookmark->uri);
-
- if (empty($notice)) {
- // Did we used to have it, and it got deleted?
- // TRANS: Client exception thrown when referring to a non-existing bookmark.
- throw new ClientException(_m('No such bookmark.'), 404);
- }
-
- return $notice;
- }
-
- /**
- * Title of the page
- *
- * Used by Action class for layout.
- *
- * @return string page tile
- */
- function title()
- {
- // TRANS: Title for bookmark.
- // TRANS: %1$s is a user nickname, %2$s is a bookmark title.
- return sprintf(_m('%1$s\'s bookmark for "%2$s"'),
- $this->user->nickname,
- $this->bookmark->title);
- }
-
- /**
- * Overload page title display to show bookmark link
- *
- * @return void
- */
- function showPageTitle()
- {
- $this->elementStart('h1');
- $this->element('a',
- array('href' => $this->bookmark->url),
- $this->bookmark->title);
- $this->elementEnd('h1');
- }
-}
case 'phpCAS':
require_once(INSTALLDIR.'/plugins/CasAuthentication/extlib/CAS.php');
return false;
- case 'CasloginAction':
- require_once(INSTALLDIR.'/plugins/CasAuthentication/' . strtolower(mb_substr($cls, 0, -6)) . '.php');
- return false;
}
+
+ // if it's not our exception, try standard places
+ return parent::onAutoload($cls);
}
function onArgsInitialize(&$args)
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+class CasloginAction extends Action
+{
+ function handle($args)
+ {
+ parent::handle($args);
+ if (common_is_real_login()) {
+ // TRANS: Client error displayed when trying to log in while already logged on.
+ $this->clientError(_m('Already logged in.'));
+ } else {
+ global $casSettings;
+ phpCAS::client(CAS_VERSION_2_0,$casSettings['server'],$casSettings['port'],$casSettings['path'],false);
+ phpCAS::setNoCasServerValidation();
+ phpCAS::handleLogoutRequests();
+ phpCAS::forceAuthentication();
+ global $casTempPassword;
+ $casTempPassword = common_good_rand(16);
+ $user = common_check_user(phpCAS::getUser(), $casTempPassword);
+ if (!$user) {
+ // TRANS: Server error displayed when trying to log in with incorrect username or password.
+ $this->serverError(_m('Incorrect username or password.'));
+ return;
+ }
+
+ // success!
+ if (!common_set_user($user)) {
+ // TRANS: Server error displayed when login fails in CAS authentication plugin.
+ $this->serverError(_m('Error setting user. You are probably not authorized.'));
+ return;
+ }
+
+ common_real_login(true);
+
+ $url = common_get_returnto();
+
+ if ($url) {
+ // We don't have to return to it again
+ common_set_returnto(null);
+ } else {
+ if(common_config('site', 'private') && $casSettings['takeOverLogin']) {
+ //SSO users expect to just go to the URL they entered
+ //if we don't have a returnto set, the user entered the
+ //main StatusNet url, so send them there.
+ $url = common_local_url('public');
+ } else {
+ //With normal logins (regular form-based username/password),
+ //the user would expect to go to their home after logging in.
+ $url = common_local_url('public',
+ array('nickname' =>
+ $user->nickname));
+ }
+ }
+
+ common_redirect($url, 303);
+ }
+ }
+}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-class CasloginAction extends Action
-{
- function handle($args)
- {
- parent::handle($args);
- if (common_is_real_login()) {
- // TRANS: Client error displayed when trying to log in while already logged on.
- $this->clientError(_m('Already logged in.'));
- } else {
- global $casSettings;
- phpCAS::client(CAS_VERSION_2_0,$casSettings['server'],$casSettings['port'],$casSettings['path'],false);
- phpCAS::setNoCasServerValidation();
- phpCAS::handleLogoutRequests();
- phpCAS::forceAuthentication();
- global $casTempPassword;
- $casTempPassword = common_good_rand(16);
- $user = common_check_user(phpCAS::getUser(), $casTempPassword);
- if (!$user) {
- // TRANS: Server error displayed when trying to log in with incorrect username or password.
- $this->serverError(_m('Incorrect username or password.'));
- return;
- }
-
- // success!
- if (!common_set_user($user)) {
- // TRANS: Server error displayed when login fails in CAS authentication plugin.
- $this->serverError(_m('Error setting user. You are probably not authorized.'));
- return;
- }
-
- common_real_login(true);
-
- $url = common_get_returnto();
-
- if ($url) {
- // We don't have to return to it again
- common_set_returnto(null);
- } else {
- if(common_config('site', 'private') && $casSettings['takeOverLogin']) {
- //SSO users expect to just go to the URL they entered
- //if we don't have a returnto set, the user entered the
- //main StatusNet url, so send them there.
- $url = common_local_url('public');
- } else {
- //With normal logins (regular form-based username/password),
- //the user would expect to go to their home after logging in.
- $url = common_local_url('public',
- array('nickname' =>
- $user->nickname));
- }
- }
-
- common_redirect($url, 303);
- }
- }
-}
exit(1);
}
-require_once(INSTALLDIR.'/plugins/ClientSideShorten/shorten.php');
-
class ClientSideShortenPlugin extends Plugin
{
function __construct()
parent::__construct();
}
- function onAutoload($cls)
- {
- switch ($cls)
- {
- case 'ShortenAction':
- require_once(INSTALLDIR.'/plugins/ClientSideShorten/shorten.php');
- return false;
- }
- }
-
function onEndShowScripts($action){
if (common_logged_in()) {
$user = common_current_user();
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List users for autocompletion
+ *
+ * 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
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Shorten all URLs in a string
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class ShortenAction extends Action
+{
+ private $text;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $this->groups=array();
+ $this->users=array();
+ $this->text = $this->arg('text');
+ if(is_null($this->text)){
+ // TRANS: Client exception thrown when a text argument is not present.
+ throw new ClientException(_m('"text" argument must be specified.'));
+ }
+ return true;
+ }
+
+ function handle($args=null)
+ {
+ parent::handle($args);
+ header('Content-Type: text/plain');
+ $shortened_text = common_shorten_links($this->text);
+ print $shortened_text;
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * List users for autocompletion
- *
- * 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
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2008-2009 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * Shorten all URLs in a string
- *
- * @category Plugin
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class ShortenAction extends Action
-{
- private $text;
-
- function prepare($args)
- {
- parent::prepare($args);
- $this->groups=array();
- $this->users=array();
- $this->text = $this->arg('text');
- if(is_null($this->text)){
- // TRANS: Client exception thrown when a text argument is not present.
- throw new ClientException(_m('"text" argument must be specified.'));
- }
- return true;
- }
-
- function handle($args=null)
- {
- parent::handle($args);
- header('Content-Type: text/plain');
- $shortened_text = common_shorten_links($this->text);
- print $shortened_text;
- }
-}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing,
- * false means stop.
- */
- function onAutoload($cls)
- {
- // common_debug("class = $cls");
-
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'UserdirectoryAction':
- case 'GroupdirectoryAction':
- include_once $dir
- . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'AlphaNav':
- include_once $dir
- . '/lib/' . strtolower($cls) . '.php';
- return false;
- case 'SortableSubscriptionList':
- case 'SortableGroupList':
- include_once $dir
- . '/lib/' . strtolower($cls) . '.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Map URLs to actions
*
}
}
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'GlobalregisterAction':
- case 'GloballoginAction':
- case 'GlobalrecoverAction':
- include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'DomainStatusNetworkInstaller':
- case 'GlobalApiAction':
- case 'FreeEmail':
- include_once $dir . '/lib/' . strtolower($cls) . '.php';
- return false;
- default:
- return true;
- }
- }
-
static function toDomain($raw)
{
$parts = explode('@', $raw);
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * An action that requires an API key
+ *
+ * PHP version 5
+ *
+ * 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 DomainStatusNetwork
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * An action that requires an API key
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class GlobalApiAction extends Action
+{
+ var $email;
+
+ /**
+ * Check for an API key, and throw an exception if it's not set
+ *
+ * @param array $args URL and POST params
+ *
+ * @return boolean continuation flag
+ */
+
+ function prepare($args)
+ {
+ StatusNet::setApi(true); // reduce exception reports to aid in debugging
+
+ parent::prepare($args);
+
+ if (!common_config('globalapi', 'enabled')) {
+ throw new ClientException(_('Global API not enabled.'), 403);
+ }
+
+ $apikey = $this->trimmed('apikey');
+
+ if (empty($apikey)) {
+ throw new ClientException(_('No API key.'), 403);
+ }
+
+ $expected = common_config('globalapi', 'key');
+
+ if ($expected != $apikey) {
+ // FIXME: increment a counter by IP address to prevent brute-force
+ // attacks on the key.
+ throw new ClientException(_('Bad API key.'), 403);
+ }
+
+ $email = common_canonical_email($this->trimmed('email'));
+
+ if (empty($email)) {
+ throw new ClientException(_('No email address.'));
+ }
+
+ if (!Validate::email($email, common_config('email', 'check_domain'))) {
+ throw new ClientException(_('Invalid email address.'));
+ }
+
+ $this->email = $email;
+
+ return true;
+ }
+
+ function showError($message, $code=400)
+ {
+ $this->showOutput(array('error' => $message), $code);
+ }
+
+ function showSuccess($values=null, $code=200)
+ {
+ if (empty($values)) {
+ $values = array();
+ }
+ $values['success'] = 1;
+ $this->showOutput($values, $code);
+ }
+
+ function showOutput($values, $code)
+ {
+ if (array_key_exists($code, ClientErrorAction::$status)) {
+ $status_string = ClientErrorAction::$status[$code];
+ } else if (array_key_exists($code, ServerErrorAction::$status)) {
+ $status_string = ServerErrorAction::$status[$code];
+ } else {
+ // bad code!
+ $code = 500;
+ $status_string = ServerErrorAction::$status[$code];
+ }
+
+ header('HTTP/1.1 '.$code.' '.$status_string);
+
+ header('Content-Type: application/json; charset=utf-8');
+ print(json_encode($values));
+ print("\n");
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * An action that requires an API key
- *
- * PHP version 5
- *
- * 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 DomainStatusNetwork
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * An action that requires an API key
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class GlobalApiAction extends Action
-{
- var $email;
-
- /**
- * Check for an API key, and throw an exception if it's not set
- *
- * @param array $args URL and POST params
- *
- * @return boolean continuation flag
- */
-
- function prepare($args)
- {
- StatusNet::setApi(true); // reduce exception reports to aid in debugging
-
- parent::prepare($args);
-
- if (!common_config('globalapi', 'enabled')) {
- throw new ClientException(_('Global API not enabled.'), 403);
- }
-
- $apikey = $this->trimmed('apikey');
-
- if (empty($apikey)) {
- throw new ClientException(_('No API key.'), 403);
- }
-
- $expected = common_config('globalapi', 'key');
-
- if ($expected != $apikey) {
- // FIXME: increment a counter by IP address to prevent brute-force
- // attacks on the key.
- throw new ClientException(_('Bad API key.'), 403);
- }
-
- $email = common_canonical_email($this->trimmed('email'));
-
- if (empty($email)) {
- throw new ClientException(_('No email address.'));
- }
-
- if (!Validate::email($email, common_config('email', 'check_domain'))) {
- throw new ClientException(_('Invalid email address.'));
- }
-
- $this->email = $email;
-
- return true;
- }
-
- function showError($message, $code=400)
- {
- $this->showOutput(array('error' => $message), $code);
- }
-
- function showSuccess($values=null, $code=200)
- {
- if (empty($values)) {
- $values = array();
- }
- $values['success'] = 1;
- $this->showOutput($values, $code);
- }
-
- function showOutput($values, $code)
- {
- if (array_key_exists($code, ClientErrorAction::$status)) {
- $status_string = ClientErrorAction::$status[$code];
- } else if (array_key_exists($code, ServerErrorAction::$status)) {
- $status_string = ServerErrorAction::$status[$code];
- } else {
- // bad code!
- $code = 500;
- $status_string = ServerErrorAction::$status[$code];
- }
-
- header('HTTP/1.1 '.$code.' '.$status_string);
-
- header('Content-Type: application/json; charset=utf-8');
- print(json_encode($values));
- print("\n");
- }
-}
*/
class DomainWhitelistPlugin extends Plugin
{
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false
- * means stop.
- */
- function onAutoload($cls) {
- $base = dirname(__FILE__);
- $lower = strtolower($cls);
-
- $files = array("$base/classes/$cls.php",
- "$base/lib/$lower.php");
- if (substr($lower, -6) == 'action') {
- $files[] = "$base/actions/" . substr($lower, 0, -6) . ".php";
- }
- foreach ($files as $file) {
- if (file_exists($file)) {
- include_once $file;
- return false;
- }
- }
- return true;
- }
-
/**
* Get the path to the plugin's installation directory. Used
* to link in js files and whatnot.
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Fancy form for inviting collegues
+ *
+ * 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 Form
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/lib/form.php';
+
+/**
+ * Form for inviting collegues and friends
+ *
+ * @category Form
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ *
+ */
+class WhitelistInviteForm extends Form
+{
+ private $whitelist = null;
+
+ /**
+ * Constructor
+ *
+ * @param Action $out output channel
+ */
+ function __construct($out, $whitelist)
+ {
+ parent::__construct($out);
+ $this->whitelist = $whitelist;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return string ID of the form
+ */
+ function id()
+ {
+ return 'form_invite';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('invite');
+ }
+
+ /**
+ * Name of the form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend.
+ $this->out->element('legend', null, _m('Invite collegues'));
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('ul', 'form_data');
+ for ($i = 0; $i < 3; $i++) {
+ $this->showEmailLI();
+ }
+ $this->out->elementStart('li');
+ $this->out->textarea(
+ // TRANS: Field label for a personal message to send to invitees.
+ 'personal', _m('Personal message'),
+ $this->out->trimmed('personal'),
+ // TRANS: Field title for a personal message to send to invitees.
+ _m('Optionally add a personal message to the invitation.')
+ );
+ $this->out->elementEnd('li');
+ $this->out->elementEnd('ul');
+ }
+
+ function showEmailLI()
+ {
+ $this->out->elementStart('li');
+ $this->out->input('username[]', '');
+ $this->out->text('@');
+ if (count($this->whitelist) == 1) {
+ $this->out->element(
+ 'span',
+ array('class' => 'email_invite'),
+ $this->whitelist[0]
+ );
+ $this->out->hidden('domain[]', $this->whitelist[0]);
+ } else {
+ $content = array();
+ foreach($this->whitelist as $domain) {
+ $content[$domain] = $domain;
+ }
+ $this->out->dropdown('domain[]', '', $content);
+ }
+ $this->showMultiControls();
+ $this->out->elementEnd('li');
+ }
+
+ function showMultiControls()
+ {
+ $this->out->element(
+ 'a',
+ array(
+ 'class' => 'remove_row',
+ 'href' => 'javascript://',
+ 'style' => 'display: none;'
+ ),
+ '-'
+ );
+
+ $this->out->element(
+ 'a',
+ array(
+ 'class' => 'add_row',
+ 'href' => 'javascript://',
+ 'style' => 'display: none;'
+ ),
+ // TRANS: Link description to action to add another item to a list.
+ _m('Add another item')
+ );
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $this->out->submit(
+ 'send',
+ // TRANS: Send button for inviting friends.
+ _m('BUTTON','Send'), 'submit form_action-primary',
+ 'send',
+ // TRANS: Submit button title.
+ _m('Send invitations.')
+ );
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Fancy form for inviting collegues
- *
- * 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 Form
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/lib/form.php';
-
-/**
- * Form for inviting collegues and friends
- *
- * @category Form
- * @package StatusNet
- * @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
- * @link http://status.net/
- *
- */
-class WhitelistInviteForm extends Form
-{
- private $whitelist = null;
-
- /**
- * Constructor
- *
- * @param Action $out output channel
- */
- function __construct($out, $whitelist)
- {
- parent::__construct($out);
- $this->whitelist = $whitelist;
- }
-
- /**
- * ID of the form
- *
- * @return string ID of the form
- */
- function id()
- {
- return 'form_invite';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('invite');
- }
-
- /**
- * Name of the form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend.
- $this->out->element('legend', null, _m('Invite collegues'));
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('ul', 'form_data');
- for ($i = 0; $i < 3; $i++) {
- $this->showEmailLI();
- }
- $this->out->elementStart('li');
- $this->out->textarea(
- // TRANS: Field label for a personal message to send to invitees.
- 'personal', _m('Personal message'),
- $this->out->trimmed('personal'),
- // TRANS: Field title for a personal message to send to invitees.
- _m('Optionally add a personal message to the invitation.')
- );
- $this->out->elementEnd('li');
- $this->out->elementEnd('ul');
- }
-
- function showEmailLI()
- {
- $this->out->elementStart('li');
- $this->out->input('username[]', '');
- $this->out->text('@');
- if (count($this->whitelist) == 1) {
- $this->out->element(
- 'span',
- array('class' => 'email_invite'),
- $this->whitelist[0]
- );
- $this->out->hidden('domain[]', $this->whitelist[0]);
- } else {
- $content = array();
- foreach($this->whitelist as $domain) {
- $content[$domain] = $domain;
- }
- $this->out->dropdown('domain[]', '', $content);
- }
- $this->showMultiControls();
- $this->out->elementEnd('li');
- }
-
- function showMultiControls()
- {
- $this->out->element(
- 'a',
- array(
- 'class' => 'remove_row',
- 'href' => 'javascript://',
- 'style' => 'display: none;'
- ),
- '-'
- );
-
- $this->out->element(
- 'a',
- array(
- 'class' => 'add_row',
- 'href' => 'javascript://',
- 'style' => 'display: none;'
- ),
- // TRANS: Link description to action to add another item to a list.
- _m('Add another item')
- );
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $this->out->submit(
- 'send',
- // TRANS: Send button for inviting friends.
- _m('BUTTON','Send'), 'submit form_action-primary',
- 'send',
- // TRANS: Submit button title.
- _m('Send invitations.')
- );
- }
-}
{
const CONFIRMTYPE = 'register';
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'EmailregisterAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'EmailRegistrationForm':
- case 'ConfirmRegistrationForm':
- include_once $dir . '/' . strtolower($cls) . '.php';
- return false;
- default:
- return true;
- }
- }
-
function onArgsInitialize(&$args)
{
if (array_key_exists('action', $args) && $args['action'] == 'register') {
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Register a user by their email address
+ *
+ * PHP version 5
+ *
+ * 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 Email registration
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Email registration
+ *
+ * There are four cases where we're called:
+ *
+ * 1. GET, no arguments. Initial registration; ask for an email address.
+ * 2. POST, email address argument. Initial registration; send an email to confirm.
+ * 3. GET, code argument. Confirming an invitation or a registration; look them up,
+ * create the relevant user if possible, login as that user, and
+ * show a password-entry form.
+ * 4. POST, password argument. After confirmation, set the password for the new
+ * user, and redirect to a registration complete action with some instructions.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class EmailregisterAction extends Action
+{
+ const NEWEMAIL = 1;
+ const SETPASSWORD = 2;
+ const NEWREGISTER = 3;
+ const CONFIRMINVITE = 4;
+ const CONFIRMREGISTER = 5;
+
+ const CONFIRMTYPE = 'register';
+
+ protected $user;
+ protected $email;
+ protected $code;
+ protected $invitation;
+ protected $confirmation;
+ protected $password1;
+ protected $password2;
+ protected $state;
+ protected $error;
+ protected $complete;
+
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ if (common_config('site', 'closed')) {
+ // TRANS: Client exception trown when registration by e-mail is not allowed.
+ throw new ClientException(_m('Registration not allowed.'), 403);
+ }
+
+ if ($this->isPost()) {
+
+ $this->checkSessionToken();
+
+ $this->email = $this->trimmed('email');
+
+ if (!empty($this->email)) {
+ if (common_config('site', 'inviteonly')) {
+ // TRANS: Client exception trown when trying to register without an invitation.
+ throw new ClientException(_m('Sorry, only invited people can register.'), 403);
+ }
+ $this->email = common_canonical_email($this->email);
+ $this->state = self::NEWEMAIL;
+ } else {
+ $this->state = self::SETPASSWORD;
+
+ $this->code = $this->trimmed('code');
+
+ if (empty($this->code)) {
+ // TRANS: Client exception thrown when no confirmation code was provided.
+ throw new ClientException(_m('No confirmation code.'));
+ }
+
+ $this->invitation = Invitation::getKV('code', $this->code);
+
+ if (!empty($this->invitation)) {
+ if (!empty($this->invitation->registered_user_id)) {
+ // TRANS: Client exception trown when using an invitation multiple times.
+ throw new ClientException(_m('Invitation already used.'), 403);
+ }
+ } else {
+
+ $this->confirmation = Confirm_address::getKV('code', $this->code);
+
+ if (empty($this->confirmation)) {
+ // TRANS: Client exception thrown when given confirmation code was not issued.
+ throw new ClientException(_m('No such confirmation code.'), 403);
+ }
+ }
+
+ $this->password1 = $this->trimmed('password1');
+ $this->password2 = $this->trimmed('password2');
+
+ $this->tos = $this->boolean('tos');
+ }
+ } else { // GET
+ $this->code = $this->trimmed('code');
+
+ if (empty($this->code)) {
+ if (common_config('site', 'inviteonly')) {
+ // TRANS: Client exception trown when trying to register without an invitation.
+ throw new ClientException(_m('Sorry, only invited people can register.'), 403);
+ }
+ $this->state = self::NEWREGISTER;
+ } else {
+ $this->invitation = Invitation::getKV('code', $this->code);
+ if (!empty($this->invitation)) {
+ if (!empty($this->invitation->registered_user_id)) {
+ // TRANS: Client exception trown when using an invitation multiple times.
+ throw new ClientException(_m('Invitation already used.'), 403);
+ }
+ $this->state = self::CONFIRMINVITE;
+ } else {
+ $this->state = self::CONFIRMREGISTER;
+ $this->confirmation = Confirm_address::getKV('code', $this->code);
+
+ if (empty($this->confirmation)) {
+ // TRANS: Client exception thrown when given confirmation code was not issued.
+ throw new ClientException(_m('No such confirmation code.'), 405);
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ function title()
+ {
+ switch ($this->state) {
+ case self::NEWREGISTER:
+ case self::NEWEMAIL:
+ // TRANS: Title for registration page.
+ return _m('TITLE','Register');
+ break;
+ case self::SETPASSWORD:
+ case self::CONFIRMINVITE:
+ case self::CONFIRMREGISTER:
+ // TRANS: Title for page where to register with a confirmation code.
+ return _m('TITLE','Complete registration');
+ break;
+ }
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ $cur = common_current_user();
+
+ if (!empty($cur)) {
+ common_redirect(common_local_url('all', array('nickname' => $cur->nickname)));
+ return;
+ }
+
+ switch ($this->state) {
+ case self::NEWREGISTER:
+ $this->showRegistrationForm();
+ break;
+ case self::NEWEMAIL:
+ $this->registerUser();
+ break;
+ case self::CONFIRMINVITE:
+ $this->confirmRegistration();
+ break;
+ case self::CONFIRMREGISTER:
+ $this->confirmRegistration();
+ break;
+ case self::SETPASSWORD:
+ $this->setPassword();
+ break;
+ }
+ return;
+ }
+
+ function showRegistrationForm()
+ {
+ $this->form = new EmailRegistrationForm($this, $this->email);
+ $this->showPage();
+ }
+
+ function registerUser()
+ {
+ try {
+ $confirm = EmailRegistrationPlugin::registerEmail($this->email);
+ } catch (ClientException $ce) {
+ $this->error = $ce->getMessage();
+ $this->showRegistrationForm();
+ return;
+ }
+
+ EmailRegistrationPlugin::sendConfirmEmail($confirm);
+
+ // TRANS: Confirmation text after initial registration.
+ // TRANS: %s an e-mail address.
+ $prompt = sprintf(_m('An email was sent to %s to confirm that address. Check your email inbox for instructions.'),
+ $this->email);
+
+ $this->complete = $prompt;
+
+ $this->showPage();
+ }
+
+ function confirmRegistration()
+ {
+ if (!empty($this->invitation)) {
+ $email = $this->invitation->address;
+ } else if (!empty($this->confirmation)) {
+ $email = $this->confirmation->address;
+ }
+
+ $nickname = $this->nicknameFromEmail($email);
+
+ $this->form = new ConfirmRegistrationForm($this,
+ $nickname,
+ $email,
+ $this->code);
+ $this->showPage();
+ }
+
+ function setPassword()
+ {
+ if (Event::handle('StartRegistrationTry', array($this))) {
+ if (!empty($this->invitation)) {
+ $email = trim($this->invitation->address);
+ } else if (!empty($this->confirmation)) {
+ $email = trim($this->confirmation->address);
+ } else {
+ // TRANS: Client exception trown when trying to set password with an invalid confirmation code.
+ throw new Exception(_m('No confirmation thing.'));
+ }
+
+ if (!$this->tos) {
+ // TRANS: Error text when trying to register without agreeing to the terms.
+ $this->error = _m('You must accept the terms of service and privacy policy to register.');
+ } else if (empty($this->password1)) {
+ // TRANS: Error text when trying to register without a password.
+ $this->error = _m('You must set a password');
+ } else if (strlen($this->password1) < 6) {
+ // TRANS: Error text when trying to register with too short a password.
+ $this->error = _m('Password must be 6 or more characters.');
+ } else if ($this->password1 != $this->password2) {
+ // TRANS: Error text when trying to register without providing the same password twice.
+ $this->error = _m('Passwords do not match.');
+ }
+
+ if (!empty($this->error)) {
+ $nickname = $this->nicknameFromEmail($email);
+ $this->form = new ConfirmRegistrationForm($this, $nickname, $email, $this->code);
+ $this->showPage();
+ return;
+ }
+
+ $nickname = $this->nicknameFromEmail($email);
+
+ try {
+ $fields = array('nickname' => $nickname,
+ 'email' => $email,
+ 'password' => $this->password1,
+ 'email_confirmed' => true);
+
+ if (!empty($this->invitation)) {
+ $fields['code'] = $this->invitation->code;
+ }
+ $this->user = User::register($fields);
+ } catch (ClientException $e) {
+ $this->error = $e->getMessage();
+ $nickname = $this->nicknameFromEmail($email);
+ $this->form = new ConfirmRegistrationForm($this, $nickname, $email, $this->code);
+ $this->showPage();
+ return;
+ }
+
+ if (empty($this->user)) {
+ // TRANS: Exception trown when using an invitation multiple times.
+ throw new Exception(_m('Failed to register user.'));
+ }
+
+ common_set_user($this->user);
+ // this is a real login
+ common_real_login(true);
+
+ // Re-init language env in case it changed (not yet, but soon)
+ common_init_language();
+
+ if (!empty($this->confirmation)) {
+ $this->confirmation->delete();
+ }
+
+ Event::handle('EndRegistrationTry', array($this));
+ }
+
+ if (Event::handle('StartRegisterSuccess', array($this))) {
+ common_redirect(common_local_url('doc', array('title' => 'welcome')),
+ 303);
+ Event::handle('EndRegisterSuccess', array($this));
+ }
+ }
+
+ function sendConfirmEmail($confirm)
+ {
+ $sitename = common_config('site', 'name');
+
+ $recipients = array($confirm->address);
+
+ $headers['From'] = mail_notify_from();
+ $headers['To'] = trim($confirm->address);
+ // TRANS: Subject for confirmation e-mail.
+ // TRANS: %s is the StatusNet sitename.
+ $headers['Subject'] = sprintf(_m('Confirm your registration on %s'), $sitename);
+
+ $confirmUrl = common_local_url('register', array('code' => $confirm->code));
+
+ // TRANS: Body for confirmation e-mail.
+ // TRANS: %1$s is the StatusNet sitename, %2$s is the confirmation URL.
+ $body = sprintf(_m('Someone (probably you) has requested an account on %1$s using this email address.'.
+ "\n".
+ 'To confirm the address, click the following URL or copy it into the address bar of your browser.'.
+ "\n".
+ '%2$s'.
+ "\n".
+ 'If it was not you, you can safely ignore this message.'),
+ $sitename,
+ $confirmUrl);
+
+ mail_send($recipients, $headers, $body);
+ }
+
+ function showContent()
+ {
+ if ($this->complete) {
+ $this->elementStart('p', 'success');
+ $this->raw($this->complete);
+ $this->elementEnd('p');
+ } else {
+ if ($this->error) {
+ $this->elementStart('p', 'error');
+ $this->raw($this->error);
+ $this->elementEnd('p');
+ }
+
+ if (!empty($this->form)) {
+ $this->form->show();
+ }
+ }
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return false;
+ }
+
+ function nicknameFromEmail($email)
+ {
+ return EmailRegistrationPlugin::nicknameFromEmail($email);
+ }
+
+ /**
+ * A local menu
+ *
+ * Shows different login/register actions.
+ *
+ * @return void
+ */
+ function showLocalNav()
+ {
+ $nav = new LoginGroupNav($this);
+ $nav->show();
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Registration confirmation form
- *
- * PHP version 5
- *
- * 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 Email registration
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Registration confirmation form
- *
- * @category Email registration
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ConfirmRegistrationForm extends Form
-{
- protected $code;
- protected $nickname;
- protected $email;
-
- function __construct($out, $nickname, $email, $code)
- {
- parent::__construct($out);
- $this->nickname = $nickname;
- $this->email = $email;
- $this->code = $code;
- }
-
- function formData()
- {
- $this->out->element('p', 'instructions',
- // TRANS: Form instructions.
- sprintf(_m('Enter a password to confirm your new account.')));
-
- $this->hidden('code', $this->code);
-
- $this->out->elementStart('ul', 'form_data');
-
- $this->elementStart('li');
-
- // TRANS: Field label in e-mail registration form.
- $this->element('label', array('for' => 'nickname-ignore'), _m('LABEL','User name'));
-
- $this->element('input', array('name' => 'nickname-ignore',
- 'type' => 'text',
- 'id' => 'nickname-ignore',
- 'disabled' => 'true',
- 'value' => $this->nickname));
-
- $this->elementEnd('li');
-
- $this->elementStart('li');
-
- // TRANS: Field label.
- $this->element('label', array('for' => 'email-ignore'), _m('Email address'));
-
- $this->element('input', array('name' => 'email-ignore',
- 'type' => 'text',
- 'id' => 'email-ignore',
- 'disabled' => 'true',
- 'value' => $this->email));
-
- $this->elementEnd('li');
-
- $this->elementStart('li');
- // TRANS: Field label on account registration page.
- $this->password('password1', _m('Password'),
- // TRANS: Field title on account registration page.
- _m('6 or more characters.'));
- $this->elementEnd('li');
- $this->elementStart('li');
- // TRANS: Field label on account registration page. In this field the password has to be entered a second time.
- $this->password('password2', _m('PASSWORD','Confirm'),
- // TRANS: Field title on account registration page.
- _m('Same as password above.'));
- $this->elementEnd('li');
-
- $this->elementStart('li');
-
- $this->element('input', array('name' => 'tos',
- 'type' => 'checkbox',
- 'class' => 'checkbox',
- 'id' => 'tos',
- 'value' => 'true'));
- $this->text(' ');
-
- $this->elementStart('label', array('class' => 'checkbox',
- 'for' => 'tos'));
-
- // TRANS: Checkbox title for terms of service and privacy policy.
- $this->raw(sprintf(_m('I agree to the <a href="%1$s">Terms of service</a> and '.
- '<a href="%1$s">Privacy policy</a> of this site.'),
- common_local_url('doc', array('title' => 'tos')),
- common_local_url('doc', array('title' => 'privacy'))));
-
- $this->elementEnd('label');
-
- $this->elementEnd('li');
-
- $this->out->elementEnd('ul');
- }
-
- function method()
- {
- return 'post';
- }
-
- /**
- * Buttons for form actions
- *
- * Submit and cancel buttons (or whatever)
- * Sub-classes should overload this to show their own buttons.
- *
- * @return void
- */
-
- function formActions()
- {
- // TRANS: Button text for action to register.
- $this->out->submit('submit', _m('BUTTON', 'Register'));
- }
-
- /**
- * ID of the form
- *
- * Should be unique on the page. Sub-classes should overload this
- * to show their own IDs.
- *
- * @return int ID of the form
- */
-
- function id()
- {
- return 'form_email_registration';
- }
-
- /**
- * Action of the form.
- *
- * URL to post to. Should be overloaded by subclasses to give
- * somewhere to post to.
- *
- * @return string URL to post to
- */
-
- function action()
- {
- return common_local_url('register');
- }
-
- function formClass()
- {
- return 'form_confirm_registration form_settings';
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Register a user by their email address
- *
- * PHP version 5
- *
- * 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 Email registration
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Email registration
- *
- * There are four cases where we're called:
- *
- * 1. GET, no arguments. Initial registration; ask for an email address.
- * 2. POST, email address argument. Initial registration; send an email to confirm.
- * 3. GET, code argument. Confirming an invitation or a registration; look them up,
- * create the relevant user if possible, login as that user, and
- * show a password-entry form.
- * 4. POST, password argument. After confirmation, set the password for the new
- * user, and redirect to a registration complete action with some instructions.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class EmailregisterAction extends Action
-{
- const NEWEMAIL = 1;
- const SETPASSWORD = 2;
- const NEWREGISTER = 3;
- const CONFIRMINVITE = 4;
- const CONFIRMREGISTER = 5;
-
- const CONFIRMTYPE = 'register';
-
- protected $user;
- protected $email;
- protected $code;
- protected $invitation;
- protected $confirmation;
- protected $password1;
- protected $password2;
- protected $state;
- protected $error;
- protected $complete;
-
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- if (common_config('site', 'closed')) {
- // TRANS: Client exception trown when registration by e-mail is not allowed.
- throw new ClientException(_m('Registration not allowed.'), 403);
- }
-
- if ($this->isPost()) {
-
- $this->checkSessionToken();
-
- $this->email = $this->trimmed('email');
-
- if (!empty($this->email)) {
- if (common_config('site', 'inviteonly')) {
- // TRANS: Client exception trown when trying to register without an invitation.
- throw new ClientException(_m('Sorry, only invited people can register.'), 403);
- }
- $this->email = common_canonical_email($this->email);
- $this->state = self::NEWEMAIL;
- } else {
- $this->state = self::SETPASSWORD;
-
- $this->code = $this->trimmed('code');
-
- if (empty($this->code)) {
- // TRANS: Client exception thrown when no confirmation code was provided.
- throw new ClientException(_m('No confirmation code.'));
- }
-
- $this->invitation = Invitation::getKV('code', $this->code);
-
- if (!empty($this->invitation)) {
- if (!empty($this->invitation->registered_user_id)) {
- // TRANS: Client exception trown when using an invitation multiple times.
- throw new ClientException(_m('Invitation already used.'), 403);
- }
- } else {
-
- $this->confirmation = Confirm_address::getKV('code', $this->code);
-
- if (empty($this->confirmation)) {
- // TRANS: Client exception thrown when given confirmation code was not issued.
- throw new ClientException(_m('No such confirmation code.'), 403);
- }
- }
-
- $this->password1 = $this->trimmed('password1');
- $this->password2 = $this->trimmed('password2');
-
- $this->tos = $this->boolean('tos');
- }
- } else { // GET
- $this->code = $this->trimmed('code');
-
- if (empty($this->code)) {
- if (common_config('site', 'inviteonly')) {
- // TRANS: Client exception trown when trying to register without an invitation.
- throw new ClientException(_m('Sorry, only invited people can register.'), 403);
- }
- $this->state = self::NEWREGISTER;
- } else {
- $this->invitation = Invitation::getKV('code', $this->code);
- if (!empty($this->invitation)) {
- if (!empty($this->invitation->registered_user_id)) {
- // TRANS: Client exception trown when using an invitation multiple times.
- throw new ClientException(_m('Invitation already used.'), 403);
- }
- $this->state = self::CONFIRMINVITE;
- } else {
- $this->state = self::CONFIRMREGISTER;
- $this->confirmation = Confirm_address::getKV('code', $this->code);
-
- if (empty($this->confirmation)) {
- // TRANS: Client exception thrown when given confirmation code was not issued.
- throw new ClientException(_m('No such confirmation code.'), 405);
- }
- }
- }
- }
-
- return true;
- }
-
- function title()
- {
- switch ($this->state) {
- case self::NEWREGISTER:
- case self::NEWEMAIL:
- // TRANS: Title for registration page.
- return _m('TITLE','Register');
- break;
- case self::SETPASSWORD:
- case self::CONFIRMINVITE:
- case self::CONFIRMREGISTER:
- // TRANS: Title for page where to register with a confirmation code.
- return _m('TITLE','Complete registration');
- break;
- }
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- $cur = common_current_user();
-
- if (!empty($cur)) {
- common_redirect(common_local_url('all', array('nickname' => $cur->nickname)));
- return;
- }
-
- switch ($this->state) {
- case self::NEWREGISTER:
- $this->showRegistrationForm();
- break;
- case self::NEWEMAIL:
- $this->registerUser();
- break;
- case self::CONFIRMINVITE:
- $this->confirmRegistration();
- break;
- case self::CONFIRMREGISTER:
- $this->confirmRegistration();
- break;
- case self::SETPASSWORD:
- $this->setPassword();
- break;
- }
- return;
- }
-
- function showRegistrationForm()
- {
- $this->form = new EmailRegistrationForm($this, $this->email);
- $this->showPage();
- }
-
- function registerUser()
- {
- try {
- $confirm = EmailRegistrationPlugin::registerEmail($this->email);
- } catch (ClientException $ce) {
- $this->error = $ce->getMessage();
- $this->showRegistrationForm();
- return;
- }
-
- EmailRegistrationPlugin::sendConfirmEmail($confirm);
-
- // TRANS: Confirmation text after initial registration.
- // TRANS: %s an e-mail address.
- $prompt = sprintf(_m('An email was sent to %s to confirm that address. Check your email inbox for instructions.'),
- $this->email);
-
- $this->complete = $prompt;
-
- $this->showPage();
- }
-
- function confirmRegistration()
- {
- if (!empty($this->invitation)) {
- $email = $this->invitation->address;
- } else if (!empty($this->confirmation)) {
- $email = $this->confirmation->address;
- }
-
- $nickname = $this->nicknameFromEmail($email);
-
- $this->form = new ConfirmRegistrationForm($this,
- $nickname,
- $email,
- $this->code);
- $this->showPage();
- }
-
- function setPassword()
- {
- if (Event::handle('StartRegistrationTry', array($this))) {
- if (!empty($this->invitation)) {
- $email = trim($this->invitation->address);
- } else if (!empty($this->confirmation)) {
- $email = trim($this->confirmation->address);
- } else {
- // TRANS: Client exception trown when trying to set password with an invalid confirmation code.
- throw new Exception(_m('No confirmation thing.'));
- }
-
- if (!$this->tos) {
- // TRANS: Error text when trying to register without agreeing to the terms.
- $this->error = _m('You must accept the terms of service and privacy policy to register.');
- } else if (empty($this->password1)) {
- // TRANS: Error text when trying to register without a password.
- $this->error = _m('You must set a password');
- } else if (strlen($this->password1) < 6) {
- // TRANS: Error text when trying to register with too short a password.
- $this->error = _m('Password must be 6 or more characters.');
- } else if ($this->password1 != $this->password2) {
- // TRANS: Error text when trying to register without providing the same password twice.
- $this->error = _m('Passwords do not match.');
- }
-
- if (!empty($this->error)) {
- $nickname = $this->nicknameFromEmail($email);
- $this->form = new ConfirmRegistrationForm($this, $nickname, $email, $this->code);
- $this->showPage();
- return;
- }
-
- $nickname = $this->nicknameFromEmail($email);
-
- try {
- $fields = array('nickname' => $nickname,
- 'email' => $email,
- 'password' => $this->password1,
- 'email_confirmed' => true);
-
- if (!empty($this->invitation)) {
- $fields['code'] = $this->invitation->code;
- }
- $this->user = User::register($fields);
- } catch (ClientException $e) {
- $this->error = $e->getMessage();
- $nickname = $this->nicknameFromEmail($email);
- $this->form = new ConfirmRegistrationForm($this, $nickname, $email, $this->code);
- $this->showPage();
- return;
- }
-
- if (empty($this->user)) {
- // TRANS: Exception trown when using an invitation multiple times.
- throw new Exception(_m('Failed to register user.'));
- }
-
- common_set_user($this->user);
- // this is a real login
- common_real_login(true);
-
- // Re-init language env in case it changed (not yet, but soon)
- common_init_language();
-
- if (!empty($this->confirmation)) {
- $this->confirmation->delete();
- }
-
- Event::handle('EndRegistrationTry', array($this));
- }
-
- if (Event::handle('StartRegisterSuccess', array($this))) {
- common_redirect(common_local_url('doc', array('title' => 'welcome')),
- 303);
- Event::handle('EndRegisterSuccess', array($this));
- }
- }
-
- function sendConfirmEmail($confirm)
- {
- $sitename = common_config('site', 'name');
-
- $recipients = array($confirm->address);
-
- $headers['From'] = mail_notify_from();
- $headers['To'] = trim($confirm->address);
- // TRANS: Subject for confirmation e-mail.
- // TRANS: %s is the StatusNet sitename.
- $headers['Subject'] = sprintf(_m('Confirm your registration on %s'), $sitename);
-
- $confirmUrl = common_local_url('register', array('code' => $confirm->code));
-
- // TRANS: Body for confirmation e-mail.
- // TRANS: %1$s is the StatusNet sitename, %2$s is the confirmation URL.
- $body = sprintf(_m('Someone (probably you) has requested an account on %1$s using this email address.'.
- "\n".
- 'To confirm the address, click the following URL or copy it into the address bar of your browser.'.
- "\n".
- '%2$s'.
- "\n".
- 'If it was not you, you can safely ignore this message.'),
- $sitename,
- $confirmUrl);
-
- mail_send($recipients, $headers, $body);
- }
-
- function showContent()
- {
- if ($this->complete) {
- $this->elementStart('p', 'success');
- $this->raw($this->complete);
- $this->elementEnd('p');
- } else {
- if ($this->error) {
- $this->elementStart('p', 'error');
- $this->raw($this->error);
- $this->elementEnd('p');
- }
-
- if (!empty($this->form)) {
- $this->form->show();
- }
- }
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return false;
- }
-
- function nicknameFromEmail($email)
- {
- return EmailRegistrationPlugin::nicknameFromEmail($email);
- }
-
- /**
- * A local menu
- *
- * Shows different login/register actions.
- *
- * @return void
- */
- function showLocalNav()
- {
- $nav = new LoginGroupNav($this);
- $nav->show();
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Email registration form
- *
- * PHP version 5
- *
- * 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 Email registration
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Email registration form
- *
- * @category Email registration
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class EmailRegistrationForm extends Form
-{
- protected $email;
-
- function __construct($out, $email)
- {
- parent::__construct($out);
- $this->email = $email;
- }
-
- function formData()
- {
- $this->out->element('p', 'instructions',
- // TRANS: Form instructions.
- _m('Enter your email address to register for an account.'));
-
- $this->out->elementStart('fieldset', array('id' => 'new_bookmark_data'));
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->out->input('email',
- // TRANS: Field label on form for registering an account.
- _m('LABEL','E-mail address'),
- $this->email);
- $this->unli();
-
- $this->out->elementEnd('ul');
- $this->out->elementEnd('fieldset');
- }
-
- function method()
- {
- return 'post';
- }
-
- /**
- * Buttons for form actions
- *
- * Submit and cancel buttons (or whatever)
- * Sub-classes should overload this to show their own buttons.
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text for registering an account.
- $this->out->submit('submit', _m('BUTTON', 'Register'));
- }
-
- /**
- * ID of the form
- *
- * Should be unique on the page. Sub-classes should overload this
- * to show their own IDs.
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'form_email_registration';
- }
-
- /**
- * Action of the form.
- *
- * URL to post to. Should be overloaded by subclasses to give
- * somewhere to post to.
- *
- * @return string URL to post to
- */
- function action()
- {
- return common_local_url('register');
- }
-
- function formClass()
- {
- return 'form_email_registration form_settings';
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Registration confirmation form
+ *
+ * PHP version 5
+ *
+ * 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 Email registration
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Registration confirmation form
+ *
+ * @category Email registration
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ConfirmRegistrationForm extends Form
+{
+ protected $code;
+ protected $nickname;
+ protected $email;
+
+ function __construct($out, $nickname, $email, $code)
+ {
+ parent::__construct($out);
+ $this->nickname = $nickname;
+ $this->email = $email;
+ $this->code = $code;
+ }
+
+ function formData()
+ {
+ $this->out->element('p', 'instructions',
+ // TRANS: Form instructions.
+ sprintf(_m('Enter a password to confirm your new account.')));
+
+ $this->hidden('code', $this->code);
+
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->elementStart('li');
+
+ // TRANS: Field label in e-mail registration form.
+ $this->element('label', array('for' => 'nickname-ignore'), _m('LABEL','User name'));
+
+ $this->element('input', array('name' => 'nickname-ignore',
+ 'type' => 'text',
+ 'id' => 'nickname-ignore',
+ 'disabled' => 'true',
+ 'value' => $this->nickname));
+
+ $this->elementEnd('li');
+
+ $this->elementStart('li');
+
+ // TRANS: Field label.
+ $this->element('label', array('for' => 'email-ignore'), _m('Email address'));
+
+ $this->element('input', array('name' => 'email-ignore',
+ 'type' => 'text',
+ 'id' => 'email-ignore',
+ 'disabled' => 'true',
+ 'value' => $this->email));
+
+ $this->elementEnd('li');
+
+ $this->elementStart('li');
+ // TRANS: Field label on account registration page.
+ $this->password('password1', _m('Password'),
+ // TRANS: Field title on account registration page.
+ _m('6 or more characters.'));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ // TRANS: Field label on account registration page. In this field the password has to be entered a second time.
+ $this->password('password2', _m('PASSWORD','Confirm'),
+ // TRANS: Field title on account registration page.
+ _m('Same as password above.'));
+ $this->elementEnd('li');
+
+ $this->elementStart('li');
+
+ $this->element('input', array('name' => 'tos',
+ 'type' => 'checkbox',
+ 'class' => 'checkbox',
+ 'id' => 'tos',
+ 'value' => 'true'));
+ $this->text(' ');
+
+ $this->elementStart('label', array('class' => 'checkbox',
+ 'for' => 'tos'));
+
+ // TRANS: Checkbox title for terms of service and privacy policy.
+ $this->raw(sprintf(_m('I agree to the <a href="%1$s">Terms of service</a> and '.
+ '<a href="%1$s">Privacy policy</a> of this site.'),
+ common_local_url('doc', array('title' => 'tos')),
+ common_local_url('doc', array('title' => 'privacy'))));
+
+ $this->elementEnd('label');
+
+ $this->elementEnd('li');
+
+ $this->out->elementEnd('ul');
+ }
+
+ function method()
+ {
+ return 'post';
+ }
+
+ /**
+ * Buttons for form actions
+ *
+ * Submit and cancel buttons (or whatever)
+ * Sub-classes should overload this to show their own buttons.
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ // TRANS: Button text for action to register.
+ $this->out->submit('submit', _m('BUTTON', 'Register'));
+ }
+
+ /**
+ * ID of the form
+ *
+ * Should be unique on the page. Sub-classes should overload this
+ * to show their own IDs.
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'form_email_registration';
+ }
+
+ /**
+ * Action of the form.
+ *
+ * URL to post to. Should be overloaded by subclasses to give
+ * somewhere to post to.
+ *
+ * @return string URL to post to
+ */
+
+ function action()
+ {
+ return common_local_url('register');
+ }
+
+ function formClass()
+ {
+ return 'form_confirm_registration form_settings';
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Email registration form
+ *
+ * PHP version 5
+ *
+ * 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 Email registration
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Email registration form
+ *
+ * @category Email registration
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class EmailRegistrationForm extends Form
+{
+ protected $email;
+
+ function __construct($out, $email)
+ {
+ parent::__construct($out);
+ $this->email = $email;
+ }
+
+ function formData()
+ {
+ $this->out->element('p', 'instructions',
+ // TRANS: Form instructions.
+ _m('Enter your email address to register for an account.'));
+
+ $this->out->elementStart('fieldset', array('id' => 'new_bookmark_data'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('email',
+ // TRANS: Field label on form for registering an account.
+ _m('LABEL','E-mail address'),
+ $this->email);
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('fieldset');
+ }
+
+ function method()
+ {
+ return 'post';
+ }
+
+ /**
+ * Buttons for form actions
+ *
+ * Submit and cancel buttons (or whatever)
+ * Sub-classes should overload this to show their own buttons.
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text for registering an account.
+ $this->out->submit('submit', _m('BUTTON', 'Register'));
+ }
+
+ /**
+ * ID of the form
+ *
+ * Should be unique on the page. Sub-classes should overload this
+ * to show their own IDs.
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'form_email_registration';
+ }
+
+ /**
+ * Action of the form.
+ *
+ * URL to post to. Should be overloaded by subclasses to give
+ * somewhere to post to.
+ *
+ * @return string URL to post to
+ */
+ function action()
+ {
+ return common_local_url('register');
+ }
+
+ function formClass()
+ {
+ return 'form_email_registration form_settings';
+ }
+}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false
- * means stop.
- */
- function onAutoload($cls) {
- $base = dirname(__FILE__);
- $lower = strtolower($cls);
-
- $files = array("$base/classes/$cls.php",
- "$base/lib/$lower.php");
- if (substr($lower, -6) == 'action') {
- $files[] = "$base/actions/" . substr($lower, 0, -6) . ".php";
- }
- foreach ($files as $file) {
- if (file_exists($file)) {
- include_once $file;
- return false;
- }
- }
- return true;
- }
-
/**
* Register our queue handlers
*
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- *
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'SiteEmailSummaryHandler':
- case 'UserEmailSummaryHandler':
- include_once $dir . '/'.strtolower($cls).'.php';
- return false;
- case 'Email_summary_status':
- include_once $dir . '/'.$cls.'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Version info for this plugin
*
+++ /dev/null
-<?php
-/**
- * Data class for email summary status
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for email summaries
- *
- * Email summary information for users
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Email_summary_status extends Managed_DataObject
-{
- public $__table = 'email_summary_status'; // table name
- public $user_id; // int(4) primary_key not_null
- public $send_summary; // tinyint not_null
- public $last_summary_id; // int(4) null
- public $created; // datetime not_null
- public $modified; // datetime not_null
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
- 'send_summary' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'not null' => true, 'description' => 'whether to send a summary or not'),
- 'last_summary_id' => array('type' => 'int', 'description' => 'last summary id'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('user_id'),
- 'foreign keys' => array(
- 'email_summary_status_user_id_fkey' => array('user', array('user_id' => 'id')),
- ),
- );
- }
-
- /**
- * Helper function
- *
- * @param integer $user_id ID of the user to get a count for
- *
- * @return int flag for whether to send this user a summary email
- */
- static function getSendSummary($user_id)
- {
- $ess = Email_summary_status::getKV('user_id', $user_id);
-
- if (!empty($ess)) {
- return $ess->send_summary;
- } else {
- return 1;
- }
- }
-
- /**
- * Get email summary status for a user
- *
- * @param integer $user_id ID of the user to get a count for
- *
- * @return Email_summary_status instance for this user, with count already incremented.
- */
- static function getLastSummaryID($user_id)
- {
- $ess = Email_summary_status::getKV('user_id', $user_id);
-
- if (!empty($ess)) {
- return $ess->last_summary_id;
- } else {
- return null;
- }
- }
-}
--- /dev/null
+<?php
+/**
+ * Data class for email summary status
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for email summaries
+ *
+ * Email summary information for users
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Email_summary_status extends Managed_DataObject
+{
+ public $__table = 'email_summary_status'; // table name
+ public $user_id; // int(4) primary_key not_null
+ public $send_summary; // tinyint not_null
+ public $last_summary_id; // int(4) null
+ public $created; // datetime not_null
+ public $modified; // datetime not_null
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
+ 'send_summary' => array('type' => 'int', 'size' => 'tiny', 'default' => 1, 'not null' => true, 'description' => 'whether to send a summary or not'),
+ 'last_summary_id' => array('type' => 'int', 'description' => 'last summary id'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('user_id'),
+ 'foreign keys' => array(
+ 'email_summary_status_user_id_fkey' => array('user', array('user_id' => 'id')),
+ ),
+ );
+ }
+
+ /**
+ * Helper function
+ *
+ * @param integer $user_id ID of the user to get a count for
+ *
+ * @return int flag for whether to send this user a summary email
+ */
+ static function getSendSummary($user_id)
+ {
+ $ess = Email_summary_status::getKV('user_id', $user_id);
+
+ if (!empty($ess)) {
+ return $ess->send_summary;
+ } else {
+ return 1;
+ }
+ }
+
+ /**
+ * Get email summary status for a user
+ *
+ * @param integer $user_id ID of the user to get a count for
+ *
+ * @return Email_summary_status instance for this user, with count already incremented.
+ */
+ static function getLastSummaryID($user_id)
+ {
+ $ess = Email_summary_status::getKV('user_id', $user_id);
+
+ if (!empty($ess)) {
+ return $ess->last_summary_id;
+ } else {
+ return null;
+ }
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ *
+ * Handler for queue items of type 'sitesum', sends email summaries
+ * to all users on the site.
+ *
+ * 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 Sample
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ *
+ * Handler for queue items of type 'sitesum', sends email summaries
+ * to all users on the site.
+ *
+ * @category Email
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class SiteEmailSummaryHandler extends QueueHandler
+{
+ /**
+ * Return transport keyword which identifies items this queue handler
+ * services; must be defined for all subclasses.
+ *
+ * Must be 8 characters or less to fit in the queue_item database.
+ * ex "email", "jabber", "sms", "irc", ...
+ *
+ * @return string
+ */
+ function transport()
+ {
+ return 'sitesum';
+ }
+
+ /**
+ * Handle the site
+ *
+ * @param mixed $object
+ * @return boolean true on success, false on failure
+ */
+ function handle($object)
+ {
+ $qm = QueueManager::get();
+
+ try {
+ // Enqueue a summary for all users
+
+ $user = new User();
+ $user->find();
+
+ while ($user->fetch()) {
+ try {
+ $qm->enqueue($user->id, 'usersum');
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $e->getMessage());
+ continue;
+ }
+ }
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $e->getMessage());
+ }
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ *
+ * Handler for queue items of type 'usersum', sends an email summaries
+ * to a particular user.
+ *
+ * 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 Sample
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Handler for queue items of type 'usersum', sends an email summaries
+ * to a particular user.
+ *
+ * @category Email
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class UserEmailSummaryHandler extends QueueHandler
+{
+ // Maximum number of notices to include by default. This is probably too much.
+ const MAX_NOTICES = 200;
+
+ /**
+ * Return transport keyword which identifies items this queue handler
+ * services; must be defined for all subclasses.
+ *
+ * Must be 8 characters or less to fit in the queue_item database.
+ * ex "email", "jabber", "sms", "irc", ...
+ *
+ * @return string
+ */
+ function transport()
+ {
+ return 'usersum';
+ }
+
+ /**
+ * Send a summary email to the user
+ *
+ * @param mixed $object
+ * @return boolean true on success, false on failure
+ */
+ function handle($user_id)
+ {
+ // Skip if they've asked not to get summaries
+
+ $ess = Email_summary_status::getKV('user_id', $user_id);
+
+ if (!empty($ess) && !$ess->send_summary) {
+ common_log(LOG_INFO, sprintf('Not sending email summary for user %s by request.', $user_id));
+ return true;
+ }
+
+ $since_id = null;
+
+ if (!empty($ess)) {
+ $since_id = $ess->last_summary_id;
+ }
+
+ $user = User::getKV('id', $user_id);
+
+ if (empty($user)) {
+ common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no such user.', $user_id));
+ return true;
+ }
+
+ if (empty($user->email)) {
+ common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no email address.', $user_id));
+ return true;
+ }
+
+ $profile = $user->getProfile();
+
+ if (empty($profile)) {
+ common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no profile.', $user_id));
+ return true;
+ }
+
+ $stream = new InboxNoticeStream($user, $user->getProfile());
+
+ $notice = $stream->getNotices(0, self::MAX_NOTICES, $since_id);
+
+ if (empty($notice) || $notice->N == 0) {
+ common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no notices.', $user_id));
+ return true;
+ }
+
+ // XXX: This is risky fingerpoken in der objektvars, but I didn't feel like
+ // figuring out a better way. -ESP
+
+ $new_top = null;
+
+ if ($notice instanceof ArrayWrapper) {
+ $new_top = $notice->_items[0]->id;
+ }
+
+ // TRANS: Subject for e-mail.
+ $subject = sprintf(_m('Your latest updates from %s'), common_config('site', 'name'));
+
+ $out = new XMLStringer(true);
+
+ $out->elementStart('html');
+ $out->elementStart('head');
+ $out->element('title', null, $subject);
+ $out->elementEnd('head');
+ $out->elementStart('body');
+ $out->elementStart('div', array('width' => '100%',
+ 'style' => 'background-color: #ffffff; border: 4px solid #4c609a; padding: 10px;'));
+
+ $out->elementStart('div', array('style' => 'color: #ffffff; background-color: #4c609a; font-weight: bold; margin-bottom: 10px; padding: 4px;'));
+ // TRANS: Text in e-mail summary.
+ // TRANS: %1$s is the StatusNet sitename, %2$s is the recipient's profile name.
+ $out->raw(sprintf(_m('Recent updates from %1$s for %2$s:'),
+ common_config('site', 'name'),
+ $profile->getBestName()));
+ $out->elementEnd('div');
+
+ $out->elementStart('table', array('width' => '550px',
+ 'style' => 'border: none; border-collapse: collapse;', 'cellpadding' => '6'));
+
+ while ($notice->fetch()) {
+ $profile = Profile::getKV('id', $notice->profile_id);
+
+ if (empty($profile)) {
+ continue;
+ }
+
+ $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
+
+ $out->elementStart('tr');
+ $out->elementStart('td', array('width' => AVATAR_STREAM_SIZE,
+ 'height' => AVATAR_STREAM_SIZE,
+ 'align' => 'left',
+ 'valign' => 'top',
+ 'style' => 'border-bottom: 1px dotted #C5CEE3; padding: 10px 6px 10px 6px;'));
+ $out->element('img', array('src' => ($avatar) ?
+ $avatar->displayUrl() :
+ Avatar::defaultImage(AVATAR_STREAM_SIZE),
+ 'width' => AVATAR_STREAM_SIZE,
+ 'height' => AVATAR_STREAM_SIZE,
+ 'alt' => $profile->getBestName()));
+ $out->elementEnd('td');
+ $out->elementStart('td', array('align' => 'left',
+ 'valign' => 'top',
+ 'style' => 'border-bottom: 1px dotted #C5CEE3; padding: 10px 6px 10px 6px;'));
+ $out->element('a', array('href' => $profile->profileurl),
+ $profile->nickname);
+ $out->text(' ');
+ $out->raw($notice->rendered);
+ $out->elementStart('div', array('style' => 'font-size: 0.8em; padding-top: 4px;'));
+ $noticeurl = $notice->bestUrl();
+ // above should always return an URL
+ assert(!empty($noticeurl));
+ $out->elementStart('a', array('rel' => 'bookmark',
+ 'href' => $noticeurl));
+ $dt = common_date_iso8601($notice->created);
+ $out->element('abbr', array('style' => 'border-bottom: none;',
+ 'title' => $dt),
+ common_date_string($notice->created));
+ $out->elementEnd('a');
+ if ($notice->hasConversation()) {
+ $conv = Conversation::getKV('id', $notice->conversation);
+ $convurl = $conv->uri;
+ if (!empty($convurl)) {
+ $out->text(' ');
+ $out->element('a',
+ array('href' => $convurl.'#notice-'.$notice->id),
+ // TRANS: Link text for link to conversation view.
+ _m('in context'));
+ }
+ }
+ $out->elementEnd('div');
+ $out->elementEnd('td');
+ $out->elementEnd('tr');
+ }
+
+ $out->elementEnd('table');
+
+ // TRANS: Link text for link to e-mail settings.
+ // TRANS: %1$s is a link to the e-mail settings, %2$s is the StatusNet sitename.
+ $out->raw("<p>" . sprintf(_m('<a href="%1$s">change your email settings for %2$s</a>'),
+ common_local_url('emailsettings'),
+ common_config('site', 'name'))."</p>");
+
+ $out->elementEnd('div');
+ $out->elementEnd('body');
+ $out->elementEnd('html');
+
+ $body = $out->getString();
+
+ // FIXME: do something for people who don't like HTML email
+
+ mail_to_user($user,
+ $subject,
+ $body,
+ array('Content-Type' => 'text/html; charset=utf-8',
+ 'Mime-Version' => '1.0'));
+
+ if (empty($ess)) {
+ $ess = new Email_summary_status();
+
+ $ess->user_id = $user_id;
+ $ess->created = common_sql_now();
+ $ess->last_summary_id = $new_top;
+ $ess->modified = common_sql_now();
+
+ $ess->insert();
+ } else {
+ $orig = clone($ess);
+
+ $ess->last_summary_id = $new_top;
+ $ess->modified = common_sql_now();
+
+ $ess->update($orig);
+ }
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
+
+$shortoptions = 'i:n:au';
+$longoptions = array('id=', 'nickname=', 'all', 'universe');
+
+$helptext = <<<END_OF_SENDEMAILSUMMARY_HELP
+sendemailsummary.php [options]
+Send an email summary of the inbox to users
+
+ -i --id ID of user to send summary to
+ -n --nickname nickname of the user to send summary to
+ -a --all send summary to all users
+ -u --universe send summary to all users on all sites
+
+END_OF_SENDEMAILSUMMARY_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+if (have_option('u', 'universe')) {
+ $sn = new Status_network();
+ if ($sn->find()) {
+ while ($sn->fetch()) {
+ $server = $sn->getServerName();
+ StatusNet::init($server);
+ // Different queue manager, maybe!
+ $qm = QueueManager::get();
+ $qm->enqueue(1, 'sitesum');
+ }
+ }
+} else {
+ $qm = QueueManager::get();
+ // enqueue summary for user or all users
+ try {
+ $user = getUser();
+ $qm->enqueue($user->id, 'usersum');
+ } catch (NoUserArgumentException $nuae) {
+ $qm->enqueue(1, 'sitesum');
+ }
+}
+++ /dev/null
-<?php
-/*
- * StatusNet - a distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
-
-$shortoptions = 'i:n:au';
-$longoptions = array('id=', 'nickname=', 'all', 'universe');
-
-$helptext = <<<END_OF_SENDEMAILSUMMARY_HELP
-sendemailsummary.php [options]
-Send an email summary of the inbox to users
-
- -i --id ID of user to send summary to
- -n --nickname nickname of the user to send summary to
- -a --all send summary to all users
- -u --universe send summary to all users on all sites
-
-END_OF_SENDEMAILSUMMARY_HELP;
-
-require_once INSTALLDIR.'/scripts/commandline.inc';
-
-if (have_option('u', 'universe')) {
- $sn = new Status_network();
- if ($sn->find()) {
- while ($sn->fetch()) {
- $server = $sn->getServerName();
- StatusNet::init($server);
- // Different queue manager, maybe!
- $qm = QueueManager::get();
- $qm->enqueue(1, 'sitesum');
- }
- }
-} else {
- $qm = QueueManager::get();
- // enqueue summary for user or all users
- try {
- $user = getUser();
- $qm->enqueue($user->id, 'usersum');
- } catch (NoUserArgumentException $nuae) {
- $qm->enqueue(1, 'sitesum');
- }
-}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- *
- * Handler for queue items of type 'sitesum', sends email summaries
- * to all users on the site.
- *
- * 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 Sample
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- *
- * Handler for queue items of type 'sitesum', sends email summaries
- * to all users on the site.
- *
- * @category Email
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class SiteEmailSummaryHandler extends QueueHandler
-{
- /**
- * Return transport keyword which identifies items this queue handler
- * services; must be defined for all subclasses.
- *
- * Must be 8 characters or less to fit in the queue_item database.
- * ex "email", "jabber", "sms", "irc", ...
- *
- * @return string
- */
- function transport()
- {
- return 'sitesum';
- }
-
- /**
- * Handle the site
- *
- * @param mixed $object
- * @return boolean true on success, false on failure
- */
- function handle($object)
- {
- $qm = QueueManager::get();
-
- try {
- // Enqueue a summary for all users
-
- $user = new User();
- $user->find();
-
- while ($user->fetch()) {
- try {
- $qm->enqueue($user->id, 'usersum');
- } catch (Exception $e) {
- common_log(LOG_WARNING, $e->getMessage());
- continue;
- }
- }
- } catch (Exception $e) {
- common_log(LOG_WARNING, $e->getMessage());
- }
-
- return true;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- *
- * Handler for queue items of type 'usersum', sends an email summaries
- * to a particular user.
- *
- * 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 Sample
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Handler for queue items of type 'usersum', sends an email summaries
- * to a particular user.
- *
- * @category Email
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class UserEmailSummaryHandler extends QueueHandler
-{
- // Maximum number of notices to include by default. This is probably too much.
- const MAX_NOTICES = 200;
-
- /**
- * Return transport keyword which identifies items this queue handler
- * services; must be defined for all subclasses.
- *
- * Must be 8 characters or less to fit in the queue_item database.
- * ex "email", "jabber", "sms", "irc", ...
- *
- * @return string
- */
- function transport()
- {
- return 'usersum';
- }
-
- /**
- * Send a summary email to the user
- *
- * @param mixed $object
- * @return boolean true on success, false on failure
- */
- function handle($user_id)
- {
- // Skip if they've asked not to get summaries
-
- $ess = Email_summary_status::getKV('user_id', $user_id);
-
- if (!empty($ess) && !$ess->send_summary) {
- common_log(LOG_INFO, sprintf('Not sending email summary for user %s by request.', $user_id));
- return true;
- }
-
- $since_id = null;
-
- if (!empty($ess)) {
- $since_id = $ess->last_summary_id;
- }
-
- $user = User::getKV('id', $user_id);
-
- if (empty($user)) {
- common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no such user.', $user_id));
- return true;
- }
-
- if (empty($user->email)) {
- common_log(LOG_INFO, sprintf('Not sending email summary for user %s; no email address.', $user_id));
- return true;
- }
-
- $profile = $user->getProfile();
-
- if (empty($profile)) {
- common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no profile.', $user_id));
- return true;
- }
-
- $stream = new InboxNoticeStream($user, $user->getProfile());
-
- $notice = $stream->getNotices(0, self::MAX_NOTICES, $since_id);
-
- if (empty($notice) || $notice->N == 0) {
- common_log(LOG_WARNING, sprintf('Not sending email summary for user %s; no notices.', $user_id));
- return true;
- }
-
- // XXX: This is risky fingerpoken in der objektvars, but I didn't feel like
- // figuring out a better way. -ESP
-
- $new_top = null;
-
- if ($notice instanceof ArrayWrapper) {
- $new_top = $notice->_items[0]->id;
- }
-
- // TRANS: Subject for e-mail.
- $subject = sprintf(_m('Your latest updates from %s'), common_config('site', 'name'));
-
- $out = new XMLStringer(true);
-
- $out->elementStart('html');
- $out->elementStart('head');
- $out->element('title', null, $subject);
- $out->elementEnd('head');
- $out->elementStart('body');
- $out->elementStart('div', array('width' => '100%',
- 'style' => 'background-color: #ffffff; border: 4px solid #4c609a; padding: 10px;'));
-
- $out->elementStart('div', array('style' => 'color: #ffffff; background-color: #4c609a; font-weight: bold; margin-bottom: 10px; padding: 4px;'));
- // TRANS: Text in e-mail summary.
- // TRANS: %1$s is the StatusNet sitename, %2$s is the recipient's profile name.
- $out->raw(sprintf(_m('Recent updates from %1$s for %2$s:'),
- common_config('site', 'name'),
- $profile->getBestName()));
- $out->elementEnd('div');
-
- $out->elementStart('table', array('width' => '550px',
- 'style' => 'border: none; border-collapse: collapse;', 'cellpadding' => '6'));
-
- while ($notice->fetch()) {
- $profile = Profile::getKV('id', $notice->profile_id);
-
- if (empty($profile)) {
- continue;
- }
-
- $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
-
- $out->elementStart('tr');
- $out->elementStart('td', array('width' => AVATAR_STREAM_SIZE,
- 'height' => AVATAR_STREAM_SIZE,
- 'align' => 'left',
- 'valign' => 'top',
- 'style' => 'border-bottom: 1px dotted #C5CEE3; padding: 10px 6px 10px 6px;'));
- $out->element('img', array('src' => ($avatar) ?
- $avatar->displayUrl() :
- Avatar::defaultImage(AVATAR_STREAM_SIZE),
- 'width' => AVATAR_STREAM_SIZE,
- 'height' => AVATAR_STREAM_SIZE,
- 'alt' => $profile->getBestName()));
- $out->elementEnd('td');
- $out->elementStart('td', array('align' => 'left',
- 'valign' => 'top',
- 'style' => 'border-bottom: 1px dotted #C5CEE3; padding: 10px 6px 10px 6px;'));
- $out->element('a', array('href' => $profile->profileurl),
- $profile->nickname);
- $out->text(' ');
- $out->raw($notice->rendered);
- $out->elementStart('div', array('style' => 'font-size: 0.8em; padding-top: 4px;'));
- $noticeurl = $notice->bestUrl();
- // above should always return an URL
- assert(!empty($noticeurl));
- $out->elementStart('a', array('rel' => 'bookmark',
- 'href' => $noticeurl));
- $dt = common_date_iso8601($notice->created);
- $out->element('abbr', array('style' => 'border-bottom: none;',
- 'title' => $dt),
- common_date_string($notice->created));
- $out->elementEnd('a');
- if ($notice->hasConversation()) {
- $conv = Conversation::getKV('id', $notice->conversation);
- $convurl = $conv->uri;
- if (!empty($convurl)) {
- $out->text(' ');
- $out->element('a',
- array('href' => $convurl.'#notice-'.$notice->id),
- // TRANS: Link text for link to conversation view.
- _m('in context'));
- }
- }
- $out->elementEnd('div');
- $out->elementEnd('td');
- $out->elementEnd('tr');
- }
-
- $out->elementEnd('table');
-
- // TRANS: Link text for link to e-mail settings.
- // TRANS: %1$s is a link to the e-mail settings, %2$s is the StatusNet sitename.
- $out->raw("<p>" . sprintf(_m('<a href="%1$s">change your email settings for %2$s</a>'),
- common_local_url('emailsettings'),
- common_config('site', 'name'))."</p>");
-
- $out->elementEnd('div');
- $out->elementEnd('body');
- $out->elementEnd('html');
-
- $body = $out->getString();
-
- // FIXME: do something for people who don't like HTML email
-
- mail_to_user($user,
- $subject,
- $body,
- array('Content-Type' => 'text/html; charset=utf-8',
- 'Mime-Version' => '1.0'));
-
- if (empty($ess)) {
- $ess = new Email_summary_status();
-
- $ess->user_id = $user_id;
- $ess->created = common_sql_now();
- $ess->last_summary_id = $new_top;
- $ess->modified = common_sql_now();
-
- $ess->insert();
- } else {
- $orig = clone($ess);
-
- $ess->last_summary_id = $new_top;
- $ess->modified = common_sql_now();
-
- $ess->update($orig);
- }
-
- return true;
- }
-}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'NeweventAction':
- case 'NewrsvpAction':
- case 'CancelrsvpAction':
- case 'ShoweventAction':
- case 'ShowrsvpAction':
- case 'TimelistAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'EventListItem':
- case 'RSVPListItem':
- case 'EventForm':
- case 'RSVPForm':
- case 'CancelRSVPForm':
- case 'EventTimeList':
- include_once $dir . '/'.strtolower($cls).'.php';
- break;
- case 'Happening':
- case 'RSVP':
- include_once $dir . '/'.$cls.'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Map URLs to actions
*
+++ /dev/null
-<?php
-/**
- * Data class for happenings
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Data class for happenings
- *
- * There's already an Event class in lib/event.php, so we couldn't
- * call this an Event without causing a hole in space-time.
- *
- * "Happening" seemed good enough.
- *
- * @category Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see Managed_DataObject
- */
-class Happening extends Managed_DataObject
-{
- const OBJECT_TYPE = 'http://activitystrea.ms/schema/1.0/event';
-
- public $__table = 'happening'; // table name
- public $id; // varchar(36) UUID
- public $uri; // varchar(255)
- public $profile_id; // int
- public $start_time; // datetime
- public $end_time; // datetime
- public $title; // varchar(255)
- public $location; // varchar(255)
- public $url; // varchar(255)
- public $description; // text
- public $created; // datetime
-
- /**
- * The One True Thingy that must be defined and declared.
- */
- public static function schemaDef()
- {
- return array(
- 'description' => 'A real-world happening',
- 'fields' => array(
- 'id' => array('type' => 'char',
- 'length' => 36,
- 'not null' => true,
- 'description' => 'UUID'),
- 'uri' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true),
- 'profile_id' => array('type' => 'int', 'not null' => true),
- 'start_time' => array('type' => 'datetime', 'not null' => true),
- 'end_time' => array('type' => 'datetime', 'not null' => true),
- 'title' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true),
- 'location' => array('type' => 'varchar',
- 'length' => 255),
- 'url' => array('type' => 'varchar',
- 'length' => 255),
- 'description' => array('type' => 'text'),
- 'created' => array('type' => 'datetime',
- 'not null' => true),
- ),
- 'primary key' => array('id'),
- 'unique keys' => array(
- 'happening_uri_key' => array('uri'),
- ),
- 'foreign keys' => array('happening_profile_id__key' => array('profile', array('profile_id' => 'id'))),
- 'indexes' => array('happening_created_idx' => array('created'),
- 'happening_start_end_idx' => array('start_time', 'end_time')),
- );
- }
-
- static function saveNew($profile, $start_time, $end_time, $title, $location, $description, $url, $options=array())
- {
- if (array_key_exists('uri', $options)) {
- $other = Happening::getKV('uri', $options['uri']);
- if (!empty($other)) {
- // TRANS: Client exception thrown when trying to create an event that already exists.
- throw new ClientException(_m('Event already exists.'));
- }
- }
-
- $ev = new Happening();
-
- $ev->id = UUID::gen();
- $ev->profile_id = $profile->id;
- $ev->start_time = common_sql_date($start_time);
- $ev->end_time = common_sql_date($end_time);
- $ev->title = $title;
- $ev->location = $location;
- $ev->description = $description;
- $ev->url = $url;
-
- if (array_key_exists('created', $options)) {
- $ev->created = $options['created'];
- } else {
- $ev->created = common_sql_now();
- }
-
- if (array_key_exists('uri', $options)) {
- $ev->uri = $options['uri'];
- } else {
- $ev->uri = common_local_url('showevent',
- array('id' => $ev->id));
- }
-
- $ev->insert();
-
- // XXX: does this get truncated?
-
- // TRANS: Event description. %1$s is a title, %2$s is start time, %3$s is end time,
- // TRANS: %4$s is location, %5$s is a description.
- $content = sprintf(_m('"%1$s" %2$s - %3$s (%4$s): %5$s'),
- $title,
- common_exact_date($ev->start_time),
- common_exact_date($ev->end_time),
- $location,
- $description);
-
- // TRANS: Rendered event description. %1$s is a title, %2$s is start time, %3$s is start time,
- // TRANS: %4$s is end time, %5$s is end time, %6$s is location, %7$s is description.
- // TRANS: Class names should not be translated.
- $rendered = sprintf(_m('<span class="vevent">'.
- '<span class="summary">%1$s</span> '.
- '<abbr class="dtstart" title="%2$s">%3$s</a> - '.
- '<abbr class="dtend" title="%4$s">%5$s</a> '.
- '(<span class="location">%6$s</span>): '.
- '<span class="description">%7$s</span> '.
- '</span>'),
- htmlspecialchars($title),
- htmlspecialchars(common_date_iso8601($ev->start_time)),
- htmlspecialchars(common_exact_date($ev->start_time)),
- htmlspecialchars(common_date_iso8601($ev->end_time)),
- htmlspecialchars(common_exact_date($ev->end_time)),
- htmlspecialchars($location),
- htmlspecialchars($description));
-
- $options = array_merge(array('object_type' => Happening::OBJECT_TYPE),
- $options);
-
- if (!array_key_exists('uri', $options)) {
- $options['uri'] = $ev->uri;
- }
-
- if (!empty($url)) {
- $options['urls'] = array($url);
- }
-
- $saved = Notice::saveNew($profile->id,
- $content,
- array_key_exists('source', $options) ?
- $options['source'] : 'web',
- $options);
-
- return $saved;
- }
-
- function getNotice()
- {
- return Notice::getKV('uri', $this->uri);
- }
-
- static function fromNotice($notice)
- {
- return Happening::getKV('uri', $notice->uri);
- }
-
- function getRSVPs()
- {
- return RSVP::forEvent($this);
- }
-
- function getRSVP($profile)
- {
- return RSVP::pkeyGet(array('profile_id' => $profile->id,
- 'event_id' => $this->id));
- }
-}
+++ /dev/null
-<?php
-/**
- * Data class for event RSVPs
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Data class for event RSVPs
- *
- * @category Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see Managed_DataObject
- */
-class RSVP extends Managed_DataObject
-{
- const POSITIVE = 'http://activitystrea.ms/schema/1.0/rsvp-yes';
- const POSSIBLE = 'http://activitystrea.ms/schema/1.0/rsvp-maybe';
- const NEGATIVE = 'http://activitystrea.ms/schema/1.0/rsvp-no';
-
- public $__table = 'rsvp'; // table name
- public $id; // varchar(36) UUID
- public $uri; // varchar(255)
- public $profile_id; // int
- public $event_id; // varchar(36) UUID
- public $response; // tinyint
- public $created; // datetime
-
- /**
- * Add the compound profile_id/event_id index to our cache keys
- * since the DB_DataObject stuff doesn't understand compound keys
- * except for the primary.
- *
- * @return array
- */
- function _allCacheKeys() {
- $keys = parent::_allCacheKeys();
- $keys[] = self::multicacheKey('RSVP', array('profile_id' => $this->profile_id,
- 'event_id' => $this->event_id));
- return $keys;
- }
-
- /**
- * The One True Thingy that must be defined and declared.
- */
- public static function schemaDef()
- {
- return array(
- 'description' => 'Plan to attend event',
- 'fields' => array(
- 'id' => array('type' => 'char',
- 'length' => 36,
- 'not null' => true,
- 'description' => 'UUID'),
- 'uri' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true),
- 'profile_id' => array('type' => 'int'),
- 'event_id' => array('type' => 'char',
- 'length' => 36,
- 'not null' => true,
- 'description' => 'UUID'),
- 'response' => array('type' => 'char',
- 'length' => '1',
- 'description' => 'Y, N, or ? for three-state yes, no, maybe'),
- 'created' => array('type' => 'datetime',
- 'not null' => true),
- ),
- 'primary key' => array('id'),
- 'unique keys' => array(
- 'rsvp_uri_key' => array('uri'),
- 'rsvp_profile_event_key' => array('profile_id', 'event_id'),
- ),
- 'foreign keys' => array('rsvp_event_id_key' => array('event', array('event_id' => 'id')),
- 'rsvp_profile_id__key' => array('profile', array('profile_id' => 'id'))),
- 'indexes' => array('rsvp_created_idx' => array('created')),
- );
- }
-
- function saveNew($profile, $event, $verb, $options=array())
- {
- if (array_key_exists('uri', $options)) {
- $other = RSVP::getKV('uri', $options['uri']);
- if (!empty($other)) {
- // TRANS: Client exception thrown when trying to save an already existing RSVP ("please respond").
- throw new ClientException(_m('RSVP already exists.'));
- }
- }
-
- $other = RSVP::pkeyGet(array('profile_id' => $profile->id,
- 'event_id' => $event->id));
-
- if (!empty($other)) {
- // TRANS: Client exception thrown when trying to save an already existing RSVP ("please respond").
- throw new ClientException(_m('RSVP already exists.'));
- }
-
- $rsvp = new RSVP();
-
- $rsvp->id = UUID::gen();
- $rsvp->profile_id = $profile->id;
- $rsvp->event_id = $event->id;
- $rsvp->response = self::codeFor($verb);
-
- if (array_key_exists('created', $options)) {
- $rsvp->created = $options['created'];
- } else {
- $rsvp->created = common_sql_now();
- }
-
- if (array_key_exists('uri', $options)) {
- $rsvp->uri = $options['uri'];
- } else {
- $rsvp->uri = common_local_url('showrsvp',
- array('id' => $rsvp->id));
- }
-
- $rsvp->insert();
-
- self::blow('rsvp:for-event:%s', $event->id);
-
- // XXX: come up with something sexier
-
- $content = $rsvp->asString();
-
- $rendered = $rsvp->asHTML();
-
- $options = array_merge(array('object_type' => $verb),
- $options);
-
- if (!array_key_exists('uri', $options)) {
- $options['uri'] = $rsvp->uri;
- }
-
- $eventNotice = $event->getNotice();
-
- if (!empty($eventNotice)) {
- $options['reply_to'] = $eventNotice->id;
- }
-
- $saved = Notice::saveNew($profile->id,
- $content,
- array_key_exists('source', $options) ?
- $options['source'] : 'web',
- $options);
-
- return $saved;
- }
-
- function codeFor($verb)
- {
- switch ($verb) {
- case RSVP::POSITIVE:
- return 'Y';
- break;
- case RSVP::NEGATIVE:
- return 'N';
- break;
- case RSVP::POSSIBLE:
- return '?';
- break;
- default:
- // TRANS: Exception thrown when requesting an undefined verb for RSVP.
- throw new Exception(sprintf(_m('Unknown verb "%s".'),$verb));
- }
- }
-
- static function verbFor($code)
- {
- switch ($code) {
- case 'Y':
- return RSVP::POSITIVE;
- break;
- case 'N':
- return RSVP::NEGATIVE;
- break;
- case '?':
- return RSVP::POSSIBLE;
- break;
- default:
- // TRANS: Exception thrown when requesting an undefined code for RSVP.
- throw new Exception(sprintf(_m('Unknown code "%s".'),$code));
- }
- }
-
- function getNotice()
- {
- $notice = Notice::getKV('uri', $this->uri);
- if (empty($notice)) {
- // TRANS: Server exception thrown when requesting a non-exsting notice for an RSVP ("please respond").
- // TRANS: %s is the RSVP with the missing notice.
- throw new ServerException(sprintf(_m('RSVP %s does not correspond to a notice in the database.'),$this->id));
- }
- return $notice;
- }
-
- static function fromNotice($notice)
- {
- return RSVP::getKV('uri', $notice->uri);
- }
-
- static function forEvent($event)
- {
- $keypart = sprintf('rsvp:for-event:%s', $event->id);
-
- $idstr = self::cacheGet($keypart);
-
- if ($idstr !== false) {
- $ids = explode(',', $idstr);
- } else {
- $ids = array();
-
- $rsvp = new RSVP();
-
- $rsvp->selectAdd();
- $rsvp->selectAdd('id');
-
- $rsvp->event_id = $event->id;
-
- if ($rsvp->find()) {
- while ($rsvp->fetch()) {
- $ids[] = $rsvp->id;
- }
- }
- self::cacheSet($keypart, implode(',', $ids));
- }
-
- $rsvps = array(RSVP::POSITIVE => array(),
- RSVP::NEGATIVE => array(),
- RSVP::POSSIBLE => array());
-
- foreach ($ids as $id) {
- $rsvp = RSVP::getKV('id', $id);
- if (!empty($rsvp)) {
- $verb = self::verbFor($rsvp->response);
- $rsvps[$verb][] = $rsvp;
- }
- }
-
- return $rsvps;
- }
-
- function getProfile()
- {
- $profile = Profile::getKV('id', $this->profile_id);
- if (empty($profile)) {
- // TRANS: Exception thrown when requesting a non-existing profile.
- // TRANS: %s is the ID of the non-existing profile.
- throw new Exception(sprintf(_m('No profile with ID %s.'),$this->profile_id));
- }
- return $profile;
- }
-
- function getEvent()
- {
- $event = Happening::getKV('id', $this->event_id);
- if (empty($event)) {
- // TRANS: Exception thrown when requesting a non-existing event.
- // TRANS: %s is the ID of the non-existing event.
- throw new Exception(sprintf(_m('No event with ID %s.'),$this->event_id));
- }
- return $event;
- }
-
- function asHTML()
- {
- $event = Happening::getKV('id', $this->event_id);
-
- return self::toHTML($this->getProfile(),
- $event,
- $this->response);
- }
-
- function asString()
- {
- $event = Happening::getKV('id', $this->event_id);
-
- return self::toString($this->getProfile(),
- $event,
- $this->response);
- }
-
- static function toHTML($profile, $event, $response)
- {
- $fmt = null;
-
- switch ($response) {
- case 'Y':
- // TRANS: HTML version of an RSVP ("please respond") status for a user.
- // TRANS: %1$s is a profile URL, %2$s a profile name,
- // TRANS: %3$s is an event URL, %4$s an event title.
- $fmt = _m("<span class='automatic event-rsvp'><a href='%1\$s'>%2\$s</a> is attending <a href='%3\$s'>%4\$s</a>.</span>");
- break;
- case 'N':
- // TRANS: HTML version of an RSVP ("please respond") status for a user.
- // TRANS: %1$s is a profile URL, %2$s a profile name,
- // TRANS: %3$s is an event URL, %4$s an event title.
- $fmt = _m("<span class='automatic event-rsvp'><a href='%1\$s'>%2\$s</a> is not attending <a href='%3\$s'>%4\$s</a>.</span>");
- break;
- case '?':
- // TRANS: HTML version of an RSVP ("please respond") status for a user.
- // TRANS: %1$s is a profile URL, %2$s a profile name,
- // TRANS: %3$s is an event URL, %4$s an event title.
- $fmt = _m("<span class='automatic event-rsvp'><a href='%1\$s'>%2\$s</a> might attend <a href='%3\$s'>%4\$s</a>.</span>");
- break;
- default:
- // TRANS: Exception thrown when requesting a user's RSVP status for a non-existing response code.
- // TRANS: %s is the non-existing response code.
- throw new Exception(sprintf(_m('Unknown response code %s.'),$response));
- break;
- }
-
- if (empty($event)) {
- $eventUrl = '#';
- // TRANS: Used as event title when not event title is available.
- // TRANS: Used as: Username [is [not ] attending|might attend] an unknown event.
- $eventTitle = _m('an unknown event');
- } else {
- $notice = $event->getNotice();
- $eventUrl = $notice->bestUrl();
- $eventTitle = $event->title;
- }
-
- return sprintf($fmt,
- htmlspecialchars($profile->profileurl),
- htmlspecialchars($profile->getBestName()),
- htmlspecialchars($eventUrl),
- htmlspecialchars($eventTitle));
- }
-
- static function toString($profile, $event, $response)
- {
- $fmt = null;
-
- switch ($response) {
- case 'Y':
- // TRANS: Plain text version of an RSVP ("please respond") status for a user.
- // TRANS: %1$s is a profile name, %2$s is an event title.
- $fmt = _m('%1$s is attending %2$s.');
- break;
- case 'N':
- // TRANS: Plain text version of an RSVP ("please respond") status for a user.
- // TRANS: %1$s is a profile name, %2$s is an event title.
- $fmt = _m('%1$s is not attending %2$s.');
- break;
- case '?':
- // TRANS: Plain text version of an RSVP ("please respond") status for a user.
- // TRANS: %1$s is a profile name, %2$s is an event title.
- $fmt = _m('%1$s might attend %2$s.');
- break;
- default:
- // TRANS: Exception thrown when requesting a user's RSVP status for a non-existing response code.
- // TRANS: %s is the non-existing response code.
- throw new Exception(sprintf(_m('Unknown response code %s.'),$response));
- break;
- }
-
- if (empty($event)) {
- // TRANS: Used as event title when not event title is available.
- // TRANS: Used as: Username [is [not ] attending|might attend] an unknown event.
- $eventTitle = _m('an unknown event');
- } else {
- $notice = $event->getNotice();
- $eventTitle = $event->title;
- }
-
- return sprintf($fmt,
- $profile->getBestName(),
- $eventTitle);
- }
-
- function delete()
- {
- self::blow('rsvp:for-event:%s', $event->id);
- parent::delete();
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Cancel the RSVP for an event
+ *
+ * PHP version 5
+ *
+ * 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 Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * RSVP for an event
+ *
+ * @category Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class CancelrsvpAction extends Action
+{
+ protected $user = null;
+ protected $rsvp = null;
+ protected $event = null;
+
+ /**
+ * Returns the title of the action
+ *
+ * @return string Action title
+ */
+ function title()
+ {
+ // TRANS: Title for RSVP ("please respond") action.
+ return _m('TITLE','Cancel RSVP');
+ }
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+ if ($this->boolean('ajax')) {
+ StatusNet::setApi(true); // short error results!
+ }
+
+ $rsvpId = $this->trimmed('rsvp');
+
+ if (empty($rsvpId)) {
+ // TRANS: Client exception thrown when referring to a non-existing RSVP ("please respond") item.
+ throw new ClientException(_m('No such RSVP.'));
+ }
+
+ $this->rsvp = RSVP::getKV('id', $rsvpId);
+
+ if (empty($this->rsvp)) {
+ // TRANS: Client exception thrown when referring to a non-existing RSVP ("please respond") item.
+ throw new ClientException(_m('No such RSVP.'));
+ }
+
+ $this->event = Happening::getKV('id', $this->rsvp->event_id);
+
+ if (empty($this->event)) {
+ // TRANS: Client exception thrown when referring to a non-existing event.
+ throw new ClientException(_m('No such event.'));
+ }
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown when trying tp RSVP ("please respond") while not logged in.
+ throw new ClientException(_m('You must be logged in to RSVP for an event.'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ parent::handle($argarray);
+
+ if ($this->isPost()) {
+ $this->cancelRSVP();
+ } else {
+ $this->showPage();
+ }
+
+ return;
+ }
+
+ /**
+ * Add a new event
+ *
+ * @return void
+ */
+ function cancelRSVP()
+ {
+ try {
+ $notice = $this->rsvp->getNotice();
+ // NB: this will delete the rsvp, too
+ if (!empty($notice)) {
+ common_log(LOG_DEBUG, "Deleting notice...");
+ $notice->delete();
+ } else {
+ common_log(LOG_DEBUG, "Deleting RSVP alone...");
+ $this->rsvp->delete();
+ }
+ } catch (ClientException $ce) {
+ $this->error = $ce->getMessage();
+ $this->showPage();
+ return;
+ }
+
+ if ($this->boolean('ajax')) {
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Page title after sending a notice.
+ $this->element('title', null, _m('Event saved'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->elementStart('body');
+ $form = new RSVPForm($this->event, $this);
+ $form->show();
+ $this->elementEnd('body');
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ }
+ }
+
+ /**
+ * Show the event form
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ if (!empty($this->error)) {
+ $this->element('p', 'error', $this->error);
+ }
+
+ $form = new CancelRSVPForm($this->rsvp, $this);
+
+ $form->show();
+
+ return;
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
+ $_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Add a new event
+ *
+ * PHP version 5
+ *
+ * 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 Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Add a new event
+ *
+ * @category Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class NeweventAction extends Action
+{
+ protected $user = null;
+ protected $error = null;
+ protected $complete = null;
+ protected $title = null;
+ protected $location = null;
+ protected $description = null;
+ protected $startTime = null;
+ protected $endTime = null;
+
+ /**
+ * Returns the title of the action
+ *
+ * @return string Action title
+ */
+ function title()
+ {
+ // TRANS: Title for new event form.
+ return _m('TITLE','New event');
+ }
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown when trying to post an event while not logged in.
+ throw new ClientException(_m('Must be logged in to post a event.'),
+ 403);
+ }
+
+ if ($this->isPost()) {
+ $this->checkSessionToken();
+ }
+
+ try {
+
+ $this->title = $this->trimmed('title');
+
+ if (empty($this->title)) {
+ // TRANS: Client exception thrown when trying to post an event without providing a title.
+ throw new ClientException(_m('Title required.'));
+ }
+
+ $this->location = $this->trimmed('location');
+ $this->url = $this->trimmed('url');
+ $this->description = $this->trimmed('description');
+ $tz = $this->trimmed('tz');
+
+ $startDate = $this->trimmed('startdate');
+
+ if (empty($startDate)) {
+ // TRANS: Client exception thrown when trying to post an event without providing a start date.
+ throw new ClientException(_m('Start date required.'));
+ }
+
+ $startTime = $this->trimmed('event-starttime');
+
+ if (empty($startTime)) {
+ $startTime = '00:00';
+ }
+
+ $endDate = $this->trimmed('enddate');
+
+ if (empty($endDate)) {
+ // TRANS: Client exception thrown when trying to post an event without providing an end date.
+ throw new ClientException(_m('End date required.'));
+ }
+
+ $endTime = $this->trimmed('event-endtime');
+
+ if (empty($endTime)) {
+ $endTime = '00:00';
+ }
+
+ $start = $startDate . ' ' . $startTime . ' ' . $tz;
+ $end = $endDate . ' ' . $endTime . ' ' . $tz;
+
+ $this->startTime = strtotime($start);
+ $this->endTime = strtotime($end);
+
+ if ($this->startTime == 0) {
+ // TRANS: Client exception thrown when trying to post an event with a date that cannot be processed.
+ // TRANS: %s is the data that could not be processed.
+ throw new ClientException(sprintf(_m('Could not parse date "%s".'),
+ $start));
+ }
+
+ if ($this->endTime == 0) {
+ // TRANS: Client exception thrown when trying to post an event with a date that cannot be processed.
+ // TRANS: %s is the data that could not be processed.
+ throw new ClientException(sprintf(_m('Could not parse date "%s".'),
+ $end));
+ }
+ } catch (ClientException $ce) {
+ if ($this->boolean('ajax')) {
+ $this->outputAjaxError($ce->getMessage());
+ return false;
+ } else {
+ $this->error = $ce->getMessage();
+ $this->showPage();
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ parent::handle($argarray);
+
+ if ($this->isPost()) {
+ $this->newEvent();
+ } else {
+ $this->showPage();
+ }
+
+ return;
+ }
+
+ /**
+ * Add a new event
+ *
+ * @return void
+ */
+ function newEvent()
+ {
+ try {
+
+ if (empty($this->title)) {
+ // TRANS: Client exception thrown when trying to post an event without providing a title.
+ throw new ClientException(_m('Event must have a title.'));
+ }
+
+ if (empty($this->startTime)) {
+ // TRANS: Client exception thrown when trying to post an event without providing a start time.
+ throw new ClientException(_m('Event must have a start time.'));
+ }
+
+ if (empty($this->endTime)) {
+ // TRANS: Client exception thrown when trying to post an event without providing an end time.
+ throw new ClientException(_m('Event must have an end time.'));
+ }
+
+ if (!empty($this->url) && Validate::uri($this->url) === false) {
+ // TRANS: Client exception thrown when trying to post an event with an invalid URL.
+ throw new ClientException(_m('URL must be valid.'));
+ }
+
+ $options = array();
+
+ // Does the heavy-lifting for getting "To:" information
+
+ ToSelector::fillOptions($this, $options);
+
+ $profile = $this->user->getProfile();
+
+ $saved = Happening::saveNew($profile,
+ $this->startTime,
+ $this->endTime,
+ $this->title,
+ $this->location,
+ $this->description,
+ $this->url,
+ $options);
+
+ $event = Happening::fromNotice($saved);
+
+ RSVP::saveNew($profile, $event, RSVP::POSITIVE);
+
+ } catch (ClientException $ce) {
+ if ($this->boolean('ajax')) {
+ $this->outputAjaxError($ce->getMessage());
+ return;
+ } else {
+ $this->error = $ce->getMessage();
+ $this->showPage();
+ return;
+ }
+ }
+
+ if ($this->boolean('ajax')) {
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Page title after sending a notice.
+ $this->element('title', null, _m('Event saved'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->showNotice($saved);
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect($saved->bestUrl(), 303);
+ }
+ }
+
+ // @todo factor this out into a base class
+ function outputAjaxError($msg)
+ {
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Page title after an AJAX error occurs
+ $this->element('title', null, _('Ajax Error'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->element('p', array('id' => 'error'), $msg);
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ return;
+ }
+
+ /**
+ * Show the event form
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ if (!empty($this->error)) {
+ $this->element('p', 'error', $this->error);
+ }
+
+ $form = new EventForm($this);
+
+ $form->show();
+
+ return;
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
+ $_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ /**
+ * Output a notice
+ *
+ * Used to generate the notice code for Ajax results.
+ *
+ * @param Notice $notice Notice that was saved
+ *
+ * @return void
+ */
+ function showNotice($notice)
+ {
+ $nli = new NoticeListItem($notice, $this);
+ $nli->show();
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * RSVP for an event
+ *
+ * PHP version 5
+ *
+ * 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 Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * RSVP for an event
+ *
+ * @category Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class NewrsvpAction extends Action
+{
+ protected $user = null;
+ protected $event = null;
+ protected $verb = null;
+
+ /**
+ * Returns the title of the action
+ *
+ * @return string Action title
+ */
+ function title()
+ {
+ // TRANS: Title for RSVP ("please respond") action.
+ return _m('TITLE','New RSVP');
+ }
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+ if ($this->boolean('ajax')) {
+ StatusNet::setApi(true); // short error results!
+ }
+
+ $eventId = $this->trimmed('event');
+
+ if (empty($eventId)) {
+ // TRANS: Client exception thrown when referring to a non-existing event.
+ throw new ClientException(_m('No such event.'));
+ }
+
+ $this->event = Happening::getKV('id', $eventId);
+
+ if (empty($this->event)) {
+ // TRANS: Client exception thrown when referring to a non-existing event.
+ throw new ClientException(_m('No such event.'));
+ }
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown when trying to RSVP ("please respond") while not logged in.
+ throw new ClientException(_m('You must be logged in to RSVP for an event.'));
+ }
+
+ common_debug(print_r($this->args, true));
+
+ switch (strtolower($this->trimmed('submitvalue'))) {
+ case 'yes':
+ $this->verb = RSVP::POSITIVE;
+ break;
+ case 'no':
+ $this->verb = RSVP::NEGATIVE;
+ break;
+ case 'maybe':
+ $this->verb = RSVP::POSSIBLE;
+ break;
+ default:
+ // TRANS: Client exception thrown when using an invalid value for RSVP ("please respond").
+ throw new ClientException(_m('Unknown submit value.'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ parent::handle($argarray);
+
+ if ($this->isPost()) {
+ $this->newRSVP();
+ } else {
+ $this->showPage();
+ }
+
+ return;
+ }
+
+ /**
+ * Add a new event
+ *
+ * @return void
+ */
+ function newRSVP()
+ {
+ try {
+ $saved = RSVP::saveNew($this->user->getProfile(),
+ $this->event,
+ $this->verb);
+ } catch (ClientException $ce) {
+ $this->error = $ce->getMessage();
+ $this->showPage();
+ return;
+ }
+
+ if ($this->boolean('ajax')) {
+ $rsvp = RSVP::fromNotice($saved);
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Page title after creating an event.
+ $this->element('title', null, _m('Event saved'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->elementStart('body');
+ $cancel = new CancelRSVPForm($rsvp, $this);
+ $cancel->show();
+ $this->elementEnd('body');
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect($saved->bestUrl(), 303);
+ }
+ }
+
+ /**
+ * Show the event form
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ if (!empty($this->error)) {
+ $this->element('p', 'error', $this->error);
+ }
+
+ $form = new RSVPForm($this->event, $this);
+
+ $form->show();
+
+ return;
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
+ $_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Show a single event
+ *
+ * PHP version 5
+ *
+ * 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 Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Show a single event, with associated information
+ *
+ * @category Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ShoweventAction extends ShownoticeAction
+{
+ protected $id = null;
+ protected $event = null;
+
+ function getNotice()
+ {
+ $this->id = $this->trimmed('id');
+
+ $this->event = Happening::getKV('id', $this->id);
+
+ if (empty($this->event)) {
+ // TRANS: Client exception thrown when referring to a non-existing event.
+ throw new ClientException(_m('No such event.'), 404);
+ }
+
+ $notice = $this->event->getNotice();
+
+ if (empty($notice)) {
+ // Did we used to have it, and it got deleted?
+ // TRANS: Client exception thrown when referring to a non-existing event.
+ throw new ClientException(_m('No such event.'), 404);
+ }
+
+ return $notice;
+ }
+
+ /**
+ * Title of the page
+ *
+ * Used by Action class for layout.
+ *
+ * @return string page tile
+ */
+ function title()
+ {
+ return $this->event->title;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * Show a single RSVP
+ *
+ * PHP version 5
+ *
+ * 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 RSVP
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Show a single RSVP, with associated information
+ *
+ * @category RSVP
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ShowrsvpAction extends ShownoticeAction
+{
+ protected $rsvp = null;
+ protected $event = null;
+
+ function getNotice()
+ {
+ $this->id = $this->trimmed('id');
+
+ $this->rsvp = RSVP::getKV('id', $this->id);
+
+ if (empty($this->rsvp)) {
+ // TRANS: Client exception thrown when referring to a non-existing RSVP.
+ // TRANS: RSVP stands for "Please reply".
+ throw new ClientException(_m('No such RSVP.'), 404);
+ }
+
+ $this->event = $this->rsvp->getEvent();
+
+ if (empty($this->event)) {
+ // TRANS: Client exception thrown when referring to a non-existing event.
+ throw new ClientException(_m('No such event.'), 404);
+ }
+
+ $notice = $this->rsvp->getNotice();
+
+ if (empty($notice)) {
+ // Did we used to have it, and it got deleted?
+ // TRANS: Client exception thrown when referring to a non-existing RSVP.
+ // TRANS: RSVP stands for "Please reply".
+ throw new ClientException(_m('No such RSVP.'), 404);
+ }
+
+ return $notice;
+ }
+
+ /**
+ * Title of the page
+ *
+ * Used by Action class for layout.
+ *
+ * @return string page tile
+ */
+ function title()
+ {
+ // TRANS: Title for event.
+ // TRANS: %1$s is a user nickname, %2$s is an event title.
+ return sprintf(_m('%1$s\'s RSVP for "%2$s"'),
+ $this->user->nickname,
+ $this->event->title);
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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 Event
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Callback handler to populate end time dropdown
+ */
+class TimelistAction extends Action {
+ private $start;
+ private $duration;
+
+ /**
+ * Get ready
+ *
+ * @param array $args misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($args) {
+ parent::prepare($args);
+ $this->start = $this->arg('start');
+ $this->duration = $this->boolean('duration', false);
+ return true;
+ }
+
+ /**
+ * Handle input and ouput something
+ *
+ * @param array $args $_REQUEST arguments
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (!common_logged_in()) {
+ // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
+ $this->clientError(_m('Not logged in.'));
+ return;
+ }
+
+ if (!empty($this->start)) {
+ $times = EventTimeList::getTimes($this->start, $this->duration);
+ } else {
+ // TRANS: Client error when submitting a form with unexpected information.
+ $this->clientError(_m('Unexpected form submission.'));
+ return;
+ }
+
+ if ($this->boolean('ajax')) {
+ header('Content-Type: application/json; charset=utf-8');
+ print json_encode($times);
+ } else {
+ // TRANS: Client error displayed when using an action in a non-AJAX way.
+ $this->clientError(_m('This action is AJAX only.'));
+ }
+ }
+
+ /**
+ * Override the regular error handler to show something more
+ * ajaxy
+ *
+ * @param string $msg error message
+ * @param int $code error code
+ */
+ function clientError($msg, $code = 400) {
+ if ($this->boolean('ajax')) {
+ header('Content-Type: application/json; charset=utf-8');
+ print json_encode(
+ array(
+ 'success' => false,
+ 'code' => $code,
+ 'message' => $msg
+ )
+ );
+ } else {
+ parent::clientError($msg, $code);
+ }
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Cancel the RSVP for an event
- *
- * PHP version 5
- *
- * 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 Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * RSVP for an event
- *
- * @category Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class CancelrsvpAction extends Action
-{
- protected $user = null;
- protected $rsvp = null;
- protected $event = null;
-
- /**
- * Returns the title of the action
- *
- * @return string Action title
- */
- function title()
- {
- // TRANS: Title for RSVP ("please respond") action.
- return _m('TITLE','Cancel RSVP');
- }
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
- if ($this->boolean('ajax')) {
- StatusNet::setApi(true); // short error results!
- }
-
- $rsvpId = $this->trimmed('rsvp');
-
- if (empty($rsvpId)) {
- // TRANS: Client exception thrown when referring to a non-existing RSVP ("please respond") item.
- throw new ClientException(_m('No such RSVP.'));
- }
-
- $this->rsvp = RSVP::getKV('id', $rsvpId);
-
- if (empty($this->rsvp)) {
- // TRANS: Client exception thrown when referring to a non-existing RSVP ("please respond") item.
- throw new ClientException(_m('No such RSVP.'));
- }
-
- $this->event = Happening::getKV('id', $this->rsvp->event_id);
-
- if (empty($this->event)) {
- // TRANS: Client exception thrown when referring to a non-existing event.
- throw new ClientException(_m('No such event.'));
- }
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Client exception thrown when trying tp RSVP ("please respond") while not logged in.
- throw new ClientException(_m('You must be logged in to RSVP for an event.'));
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- parent::handle($argarray);
-
- if ($this->isPost()) {
- $this->cancelRSVP();
- } else {
- $this->showPage();
- }
-
- return;
- }
-
- /**
- * Add a new event
- *
- * @return void
- */
- function cancelRSVP()
- {
- try {
- $notice = $this->rsvp->getNotice();
- // NB: this will delete the rsvp, too
- if (!empty($notice)) {
- common_log(LOG_DEBUG, "Deleting notice...");
- $notice->delete();
- } else {
- common_log(LOG_DEBUG, "Deleting RSVP alone...");
- $this->rsvp->delete();
- }
- } catch (ClientException $ce) {
- $this->error = $ce->getMessage();
- $this->showPage();
- return;
- }
-
- if ($this->boolean('ajax')) {
- header('Content-Type: text/xml;charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: Page title after sending a notice.
- $this->element('title', null, _m('Event saved'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $this->elementStart('body');
- $form = new RSVPForm($this->event, $this);
- $form->show();
- $this->elementEnd('body');
- $this->elementEnd('body');
- $this->elementEnd('html');
- }
- }
-
- /**
- * Show the event form
- *
- * @return void
- */
- function showContent()
- {
- if (!empty($this->error)) {
- $this->element('p', 'error', $this->error);
- }
-
- $form = new CancelRSVPForm($this->rsvp, $this);
-
- $form->show();
-
- return;
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
- $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- return true;
- } else {
- return false;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form to RSVP for an event
- *
- * PHP version 5
- *
- * 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 Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * A form to RSVP for an event
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class CancelRSVPForm extends Form
-{
- protected $rsvp = null;
-
- function __construct($rsvp, $out=null)
- {
- parent::__construct($out);
- $this->rsvp = $rsvp;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'form_event_rsvp';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'ajax';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('cancelrsvp');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'new_rsvp_data'));
-
- $this->out->hidden('rsvp-id', $this->rsvp->id, 'rsvp');
-
- switch (RSVP::verbFor($this->rsvp->response)) {
- case RSVP::POSITIVE:
- // TRANS: Possible status for RSVP ("please respond") item.
- $this->out->text(_m('You will attend this event.'));
- break;
- case RSVP::NEGATIVE:
- // TRANS: Possible status for RSVP ("please respond") item.
- $this->out->text(_m('You will not attend this event.'));
- break;
- case RSVP::POSSIBLE:
- // TRANS: Possible status for RSVP ("please respond") item.
- $this->out->text(_m('You might attend this event.'));
- break;
- }
-
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text to cancel responding to an RSVP ("please respond") item.
- $this->out->submit('rsvp-cancel', _m('BUTTON', 'Cancel'));
- }
-}
--- /dev/null
+<?php
+/**
+ * Data class for happenings
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Data class for happenings
+ *
+ * There's already an Event class in lib/event.php, so we couldn't
+ * call this an Event without causing a hole in space-time.
+ *
+ * "Happening" seemed good enough.
+ *
+ * @category Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see Managed_DataObject
+ */
+class Happening extends Managed_DataObject
+{
+ const OBJECT_TYPE = 'http://activitystrea.ms/schema/1.0/event';
+
+ public $__table = 'happening'; // table name
+ public $id; // varchar(36) UUID
+ public $uri; // varchar(255)
+ public $profile_id; // int
+ public $start_time; // datetime
+ public $end_time; // datetime
+ public $title; // varchar(255)
+ public $location; // varchar(255)
+ public $url; // varchar(255)
+ public $description; // text
+ public $created; // datetime
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'A real-world happening',
+ 'fields' => array(
+ 'id' => array('type' => 'char',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'UUID'),
+ 'uri' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'profile_id' => array('type' => 'int', 'not null' => true),
+ 'start_time' => array('type' => 'datetime', 'not null' => true),
+ 'end_time' => array('type' => 'datetime', 'not null' => true),
+ 'title' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'location' => array('type' => 'varchar',
+ 'length' => 255),
+ 'url' => array('type' => 'varchar',
+ 'length' => 255),
+ 'description' => array('type' => 'text'),
+ 'created' => array('type' => 'datetime',
+ 'not null' => true),
+ ),
+ 'primary key' => array('id'),
+ 'unique keys' => array(
+ 'happening_uri_key' => array('uri'),
+ ),
+ 'foreign keys' => array('happening_profile_id__key' => array('profile', array('profile_id' => 'id'))),
+ 'indexes' => array('happening_created_idx' => array('created'),
+ 'happening_start_end_idx' => array('start_time', 'end_time')),
+ );
+ }
+
+ static function saveNew($profile, $start_time, $end_time, $title, $location, $description, $url, $options=array())
+ {
+ if (array_key_exists('uri', $options)) {
+ $other = Happening::getKV('uri', $options['uri']);
+ if (!empty($other)) {
+ // TRANS: Client exception thrown when trying to create an event that already exists.
+ throw new ClientException(_m('Event already exists.'));
+ }
+ }
+
+ $ev = new Happening();
+
+ $ev->id = UUID::gen();
+ $ev->profile_id = $profile->id;
+ $ev->start_time = common_sql_date($start_time);
+ $ev->end_time = common_sql_date($end_time);
+ $ev->title = $title;
+ $ev->location = $location;
+ $ev->description = $description;
+ $ev->url = $url;
+
+ if (array_key_exists('created', $options)) {
+ $ev->created = $options['created'];
+ } else {
+ $ev->created = common_sql_now();
+ }
+
+ if (array_key_exists('uri', $options)) {
+ $ev->uri = $options['uri'];
+ } else {
+ $ev->uri = common_local_url('showevent',
+ array('id' => $ev->id));
+ }
+
+ $ev->insert();
+
+ // XXX: does this get truncated?
+
+ // TRANS: Event description. %1$s is a title, %2$s is start time, %3$s is end time,
+ // TRANS: %4$s is location, %5$s is a description.
+ $content = sprintf(_m('"%1$s" %2$s - %3$s (%4$s): %5$s'),
+ $title,
+ common_exact_date($ev->start_time),
+ common_exact_date($ev->end_time),
+ $location,
+ $description);
+
+ // TRANS: Rendered event description. %1$s is a title, %2$s is start time, %3$s is start time,
+ // TRANS: %4$s is end time, %5$s is end time, %6$s is location, %7$s is description.
+ // TRANS: Class names should not be translated.
+ $rendered = sprintf(_m('<span class="vevent">'.
+ '<span class="summary">%1$s</span> '.
+ '<abbr class="dtstart" title="%2$s">%3$s</a> - '.
+ '<abbr class="dtend" title="%4$s">%5$s</a> '.
+ '(<span class="location">%6$s</span>): '.
+ '<span class="description">%7$s</span> '.
+ '</span>'),
+ htmlspecialchars($title),
+ htmlspecialchars(common_date_iso8601($ev->start_time)),
+ htmlspecialchars(common_exact_date($ev->start_time)),
+ htmlspecialchars(common_date_iso8601($ev->end_time)),
+ htmlspecialchars(common_exact_date($ev->end_time)),
+ htmlspecialchars($location),
+ htmlspecialchars($description));
+
+ $options = array_merge(array('object_type' => Happening::OBJECT_TYPE),
+ $options);
+
+ if (!array_key_exists('uri', $options)) {
+ $options['uri'] = $ev->uri;
+ }
+
+ if (!empty($url)) {
+ $options['urls'] = array($url);
+ }
+
+ $saved = Notice::saveNew($profile->id,
+ $content,
+ array_key_exists('source', $options) ?
+ $options['source'] : 'web',
+ $options);
+
+ return $saved;
+ }
+
+ function getNotice()
+ {
+ return Notice::getKV('uri', $this->uri);
+ }
+
+ static function fromNotice($notice)
+ {
+ return Happening::getKV('uri', $notice->uri);
+ }
+
+ function getRSVPs()
+ {
+ return RSVP::forEvent($this);
+ }
+
+ function getRSVP($profile)
+ {
+ return RSVP::pkeyGet(array('profile_id' => $profile->id,
+ 'event_id' => $this->id));
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class for event RSVPs
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Data class for event RSVPs
+ *
+ * @category Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see Managed_DataObject
+ */
+class RSVP extends Managed_DataObject
+{
+ const POSITIVE = 'http://activitystrea.ms/schema/1.0/rsvp-yes';
+ const POSSIBLE = 'http://activitystrea.ms/schema/1.0/rsvp-maybe';
+ const NEGATIVE = 'http://activitystrea.ms/schema/1.0/rsvp-no';
+
+ public $__table = 'rsvp'; // table name
+ public $id; // varchar(36) UUID
+ public $uri; // varchar(255)
+ public $profile_id; // int
+ public $event_id; // varchar(36) UUID
+ public $response; // tinyint
+ public $created; // datetime
+
+ /**
+ * Add the compound profile_id/event_id index to our cache keys
+ * since the DB_DataObject stuff doesn't understand compound keys
+ * except for the primary.
+ *
+ * @return array
+ */
+ function _allCacheKeys() {
+ $keys = parent::_allCacheKeys();
+ $keys[] = self::multicacheKey('RSVP', array('profile_id' => $this->profile_id,
+ 'event_id' => $this->event_id));
+ return $keys;
+ }
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'Plan to attend event',
+ 'fields' => array(
+ 'id' => array('type' => 'char',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'UUID'),
+ 'uri' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'profile_id' => array('type' => 'int'),
+ 'event_id' => array('type' => 'char',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'UUID'),
+ 'response' => array('type' => 'char',
+ 'length' => '1',
+ 'description' => 'Y, N, or ? for three-state yes, no, maybe'),
+ 'created' => array('type' => 'datetime',
+ 'not null' => true),
+ ),
+ 'primary key' => array('id'),
+ 'unique keys' => array(
+ 'rsvp_uri_key' => array('uri'),
+ 'rsvp_profile_event_key' => array('profile_id', 'event_id'),
+ ),
+ 'foreign keys' => array('rsvp_event_id_key' => array('event', array('event_id' => 'id')),
+ 'rsvp_profile_id__key' => array('profile', array('profile_id' => 'id'))),
+ 'indexes' => array('rsvp_created_idx' => array('created')),
+ );
+ }
+
+ function saveNew($profile, $event, $verb, $options=array())
+ {
+ if (array_key_exists('uri', $options)) {
+ $other = RSVP::getKV('uri', $options['uri']);
+ if (!empty($other)) {
+ // TRANS: Client exception thrown when trying to save an already existing RSVP ("please respond").
+ throw new ClientException(_m('RSVP already exists.'));
+ }
+ }
+
+ $other = RSVP::pkeyGet(array('profile_id' => $profile->id,
+ 'event_id' => $event->id));
+
+ if (!empty($other)) {
+ // TRANS: Client exception thrown when trying to save an already existing RSVP ("please respond").
+ throw new ClientException(_m('RSVP already exists.'));
+ }
+
+ $rsvp = new RSVP();
+
+ $rsvp->id = UUID::gen();
+ $rsvp->profile_id = $profile->id;
+ $rsvp->event_id = $event->id;
+ $rsvp->response = self::codeFor($verb);
+
+ if (array_key_exists('created', $options)) {
+ $rsvp->created = $options['created'];
+ } else {
+ $rsvp->created = common_sql_now();
+ }
+
+ if (array_key_exists('uri', $options)) {
+ $rsvp->uri = $options['uri'];
+ } else {
+ $rsvp->uri = common_local_url('showrsvp',
+ array('id' => $rsvp->id));
+ }
+
+ $rsvp->insert();
+
+ self::blow('rsvp:for-event:%s', $event->id);
+
+ // XXX: come up with something sexier
+
+ $content = $rsvp->asString();
+
+ $rendered = $rsvp->asHTML();
+
+ $options = array_merge(array('object_type' => $verb),
+ $options);
+
+ if (!array_key_exists('uri', $options)) {
+ $options['uri'] = $rsvp->uri;
+ }
+
+ $eventNotice = $event->getNotice();
+
+ if (!empty($eventNotice)) {
+ $options['reply_to'] = $eventNotice->id;
+ }
+
+ $saved = Notice::saveNew($profile->id,
+ $content,
+ array_key_exists('source', $options) ?
+ $options['source'] : 'web',
+ $options);
+
+ return $saved;
+ }
+
+ function codeFor($verb)
+ {
+ switch ($verb) {
+ case RSVP::POSITIVE:
+ return 'Y';
+ break;
+ case RSVP::NEGATIVE:
+ return 'N';
+ break;
+ case RSVP::POSSIBLE:
+ return '?';
+ break;
+ default:
+ // TRANS: Exception thrown when requesting an undefined verb for RSVP.
+ throw new Exception(sprintf(_m('Unknown verb "%s".'),$verb));
+ }
+ }
+
+ static function verbFor($code)
+ {
+ switch ($code) {
+ case 'Y':
+ return RSVP::POSITIVE;
+ break;
+ case 'N':
+ return RSVP::NEGATIVE;
+ break;
+ case '?':
+ return RSVP::POSSIBLE;
+ break;
+ default:
+ // TRANS: Exception thrown when requesting an undefined code for RSVP.
+ throw new Exception(sprintf(_m('Unknown code "%s".'),$code));
+ }
+ }
+
+ function getNotice()
+ {
+ $notice = Notice::getKV('uri', $this->uri);
+ if (empty($notice)) {
+ // TRANS: Server exception thrown when requesting a non-exsting notice for an RSVP ("please respond").
+ // TRANS: %s is the RSVP with the missing notice.
+ throw new ServerException(sprintf(_m('RSVP %s does not correspond to a notice in the database.'),$this->id));
+ }
+ return $notice;
+ }
+
+ static function fromNotice($notice)
+ {
+ return RSVP::getKV('uri', $notice->uri);
+ }
+
+ static function forEvent($event)
+ {
+ $keypart = sprintf('rsvp:for-event:%s', $event->id);
+
+ $idstr = self::cacheGet($keypart);
+
+ if ($idstr !== false) {
+ $ids = explode(',', $idstr);
+ } else {
+ $ids = array();
+
+ $rsvp = new RSVP();
+
+ $rsvp->selectAdd();
+ $rsvp->selectAdd('id');
+
+ $rsvp->event_id = $event->id;
+
+ if ($rsvp->find()) {
+ while ($rsvp->fetch()) {
+ $ids[] = $rsvp->id;
+ }
+ }
+ self::cacheSet($keypart, implode(',', $ids));
+ }
+
+ $rsvps = array(RSVP::POSITIVE => array(),
+ RSVP::NEGATIVE => array(),
+ RSVP::POSSIBLE => array());
+
+ foreach ($ids as $id) {
+ $rsvp = RSVP::getKV('id', $id);
+ if (!empty($rsvp)) {
+ $verb = self::verbFor($rsvp->response);
+ $rsvps[$verb][] = $rsvp;
+ }
+ }
+
+ return $rsvps;
+ }
+
+ function getProfile()
+ {
+ $profile = Profile::getKV('id', $this->profile_id);
+ if (empty($profile)) {
+ // TRANS: Exception thrown when requesting a non-existing profile.
+ // TRANS: %s is the ID of the non-existing profile.
+ throw new Exception(sprintf(_m('No profile with ID %s.'),$this->profile_id));
+ }
+ return $profile;
+ }
+
+ function getEvent()
+ {
+ $event = Happening::getKV('id', $this->event_id);
+ if (empty($event)) {
+ // TRANS: Exception thrown when requesting a non-existing event.
+ // TRANS: %s is the ID of the non-existing event.
+ throw new Exception(sprintf(_m('No event with ID %s.'),$this->event_id));
+ }
+ return $event;
+ }
+
+ function asHTML()
+ {
+ $event = Happening::getKV('id', $this->event_id);
+
+ return self::toHTML($this->getProfile(),
+ $event,
+ $this->response);
+ }
+
+ function asString()
+ {
+ $event = Happening::getKV('id', $this->event_id);
+
+ return self::toString($this->getProfile(),
+ $event,
+ $this->response);
+ }
+
+ static function toHTML($profile, $event, $response)
+ {
+ $fmt = null;
+
+ switch ($response) {
+ case 'Y':
+ // TRANS: HTML version of an RSVP ("please respond") status for a user.
+ // TRANS: %1$s is a profile URL, %2$s a profile name,
+ // TRANS: %3$s is an event URL, %4$s an event title.
+ $fmt = _m("<span class='automatic event-rsvp'><a href='%1\$s'>%2\$s</a> is attending <a href='%3\$s'>%4\$s</a>.</span>");
+ break;
+ case 'N':
+ // TRANS: HTML version of an RSVP ("please respond") status for a user.
+ // TRANS: %1$s is a profile URL, %2$s a profile name,
+ // TRANS: %3$s is an event URL, %4$s an event title.
+ $fmt = _m("<span class='automatic event-rsvp'><a href='%1\$s'>%2\$s</a> is not attending <a href='%3\$s'>%4\$s</a>.</span>");
+ break;
+ case '?':
+ // TRANS: HTML version of an RSVP ("please respond") status for a user.
+ // TRANS: %1$s is a profile URL, %2$s a profile name,
+ // TRANS: %3$s is an event URL, %4$s an event title.
+ $fmt = _m("<span class='automatic event-rsvp'><a href='%1\$s'>%2\$s</a> might attend <a href='%3\$s'>%4\$s</a>.</span>");
+ break;
+ default:
+ // TRANS: Exception thrown when requesting a user's RSVP status for a non-existing response code.
+ // TRANS: %s is the non-existing response code.
+ throw new Exception(sprintf(_m('Unknown response code %s.'),$response));
+ break;
+ }
+
+ if (empty($event)) {
+ $eventUrl = '#';
+ // TRANS: Used as event title when not event title is available.
+ // TRANS: Used as: Username [is [not ] attending|might attend] an unknown event.
+ $eventTitle = _m('an unknown event');
+ } else {
+ $notice = $event->getNotice();
+ $eventUrl = $notice->bestUrl();
+ $eventTitle = $event->title;
+ }
+
+ return sprintf($fmt,
+ htmlspecialchars($profile->profileurl),
+ htmlspecialchars($profile->getBestName()),
+ htmlspecialchars($eventUrl),
+ htmlspecialchars($eventTitle));
+ }
+
+ static function toString($profile, $event, $response)
+ {
+ $fmt = null;
+
+ switch ($response) {
+ case 'Y':
+ // TRANS: Plain text version of an RSVP ("please respond") status for a user.
+ // TRANS: %1$s is a profile name, %2$s is an event title.
+ $fmt = _m('%1$s is attending %2$s.');
+ break;
+ case 'N':
+ // TRANS: Plain text version of an RSVP ("please respond") status for a user.
+ // TRANS: %1$s is a profile name, %2$s is an event title.
+ $fmt = _m('%1$s is not attending %2$s.');
+ break;
+ case '?':
+ // TRANS: Plain text version of an RSVP ("please respond") status for a user.
+ // TRANS: %1$s is a profile name, %2$s is an event title.
+ $fmt = _m('%1$s might attend %2$s.');
+ break;
+ default:
+ // TRANS: Exception thrown when requesting a user's RSVP status for a non-existing response code.
+ // TRANS: %s is the non-existing response code.
+ throw new Exception(sprintf(_m('Unknown response code %s.'),$response));
+ break;
+ }
+
+ if (empty($event)) {
+ // TRANS: Used as event title when not event title is available.
+ // TRANS: Used as: Username [is [not ] attending|might attend] an unknown event.
+ $eventTitle = _m('an unknown event');
+ } else {
+ $notice = $event->getNotice();
+ $eventTitle = $event->title;
+ }
+
+ return sprintf($fmt,
+ $profile->getBestName(),
+ $eventTitle);
+ }
+
+ function delete()
+ {
+ self::blow('rsvp:for-event:%s', $event->id);
+ parent::delete();
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form for entering an event
- *
- * PHP version 5
- *
- * 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 Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form for adding an event
- *
- * @category Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class EventForm extends Form
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'form_new_event';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings ajax-notice';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('newevent');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'new_event_data'));
-
- // Passing in the URL of the Ajax action that the .js for this form hits
- // when selecting event start and end times. JavaScript will try to
- // use a relative path, unless explicitely told where an action is,
- // and that's a bit difficult to calculate since the event form is on
- // so many pages with different paths. It might be worth solving this
- // globally by putting the base site path in the Identifier-URL meta tag
- // or something similar, so it would be easy to calculate the exact path
- // for actions and other things in JavaScripts. -z
- $this->out->hidden('timelist_action_url', common_local_url('timelist'));
-
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->out->input('event-title',
- // TRANS: Field label on event form.
- _m('LABEL','Title'),
- null,
- // TRANS: Field title on event form.
- _m('Title of the event.'),
- 'title');
- $this->unli();
-
- $this->li();
-
- $today = new DateTime('now');
- $today->setTimezone(new DateTimeZone(common_timezone()));
-
- $this->out->input('event-startdate',
- // TRANS: Field label on event form.
- _m('LABEL','Start date'),
- $today->format('m/d/Y'),
- // TRANS: Field title on event form.
- _m('Date the event starts.'),
- 'startdate');
- $this->unli();
-
- $this->li();
-
- $times = EventTimeList::getTimes($today->format('m/d/Y 12:00') . ' am ' . $today->format('T'));
- $start = EventTimeList::nearestHalfHour($today->format('c'));
- $start->setTimezone(new DateTimeZone(common_timezone()));
-
- $this->out->dropdown(
- 'event-starttime',
- // TRANS: Field label on event form.
- _m('LABEL','Start time'),
- $times,
- // TRANS: Field title on event form. %s is the abbreviated timezone
- sprintf(_m("Time the event starts (%s)."), $today->format('T')),
- false,
- $start->format('g:ia')
- );
-
- // Need to keep JavaScript TZ in sync with PHP TZ
- $this->out->hidden('tz', $today->format('T'));
- $this->out->hidden('now', $today->format('F d, Y H:i:s T'));
-
- $this->unli();
-
- $this->li();
- $this->out->input('event-enddate',
- // TRANS: Field label on event form.
- _m('LABEL','End date'),
- $today->format('m/d/Y'),
- // TRANS: Field title on event form.
- _m('Date the event ends.'),
- 'enddate');
- $this->unli();
-
- $this->li();
-
- $this->out->dropdown(
- 'event-endtime',
- // TRANS: Field label on event form.
- _m('LABEL','End time'),
- EventTimeList::getTimes($start->format('c'), true),
- // TRANS: Field title on event form.
- _m('Time the event ends.'),
- false,
- null
- );
- $this->unli();
-
- $this->li();
- $this->out->input('event-location',
- // TRANS: Field label on event form.
- _m('LABEL','Where?'),
- null,
- // TRANS: Field title on event form.
- _m('Event location.'),
- 'location');
- $this->unli();
-
- $this->li();
- $this->out->input('event-url',
- // TRANS: Field label on event form.
- _m('LABEL','URL'),
- null,
- // TRANS: Field title on event form.
- _m('URL for more information.'),
- 'url');
- $this->unli();
-
- $this->li();
- $this->out->input('event-description',
- // TRANS: Field label on event form.
- _m('LABEL','Description'),
- null,
- // TRANS: Field title on event form.
- _m('Description of the event.'),
- 'description');
- $this->unli();
-
- $this->out->elementEnd('ul');
-
- $toWidget = new ToSelector($this->out,
- common_current_user(),
- null);
- $toWidget->show();
-
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text to save an event..
- $this->out->submit('event-submit', _m('BUTTON', 'Save'), 'submit', 'submit');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Notice-list representation of an event
- *
- * PHP version 5
- *
- * 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 Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Notice-list representation of an event
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class EventListItem extends NoticeListItemAdapter
-{
- function showNotice()
- {
- $this->nli->out->elementStart('div', 'entry-title');
- $this->nli->showAuthor();
- $this->showContent();
- $this->nli->out->elementEnd('div');
- }
-
- function showContent()
- {
- $notice = $this->nli->notice;
- $out = $this->nli->out;
-
- $profile = $notice->getProfile();
- $event = Happening::fromNotice($notice);
-
- if (empty($event)) {
- // TRANS: Content for a deleted RSVP list item (RSVP stands for "please respond").
- $out->element('p', null, _m('Deleted.'));
- return;
- }
-
- $out->elementStart('div', 'vevent event'); // VEVENT IN
-
- $out->elementStart('h3'); // VEVENT/H3 IN
-
- if (!empty($event->url)) {
- $out->element('a',
- array('href' => $event->url,
- 'class' => 'event-title entry-title summary'),
- $event->title);
- } else {
- $out->text($event->title);
- }
-
- $out->elementEnd('h3'); // VEVENT/H3 OUT
-
- $now = new DateTime();
- $startDate = new DateTime($event->start_time);
- $endDate = new DateTime($event->end_time);
- $userTz = new DateTimeZone(common_timezone());
-
- // Localize the time for the observer
- $now->setTimeZone($userTz);
- $startDate->setTimezone($userTz);
- $endDate->setTimezone($userTz);
-
- $thisYear = $now->format('Y');
- $startYear = $startDate->format('Y');
- $endYear = $endDate->format('Y');
-
- $dateFmt = 'D, F j, '; // e.g.: Mon, Aug 31
-
- if ($startYear != $thisYear || $endYear != $thisYear) {
- $dateFmt .= 'Y,'; // append year if we need to think about years
- }
-
- $startDateStr = $startDate->format($dateFmt);
- $endDateStr = $endDate->format($dateFmt);
-
- $timeFmt = 'g:ia';
-
- $startTimeStr = $startDate->format($timeFmt);
- $endTimeStr = $endDate->format("{$timeFmt} (T)");
-
- $out->elementStart('div', 'event-times'); // VEVENT/EVENT-TIMES IN
-
- // TRANS: Field label for event description.
- $out->element('strong', null, _m('Time:'));
-
- $out->element('abbr', array('class' => 'dtstart',
- 'title' => common_date_iso8601($event->start_time)),
- $startDateStr . ' ' . $startTimeStr);
- $out->text(' – ');
- if ($startDateStr == $endDateStr) {
- $out->element('span', array('class' => 'dtend',
- 'title' => common_date_iso8601($event->end_time)),
- $endTimeStr);
- } else {
- $out->element('span', array('class' => 'dtend',
- 'title' => common_date_iso8601($event->end_time)),
- $endDateStr . ' ' . $endTimeStr);
- }
-
- $out->elementEnd('div'); // VEVENT/EVENT-TIMES OUT
-
- if (!empty($event->location)) {
- $out->elementStart('div', 'event-location');
- // TRANS: Field label for event description.
- $out->element('strong', null, _m('Location:'));
- $out->element('span', 'location', $event->location);
- $out->elementEnd('div');
- }
-
- if (!empty($event->description)) {
- $out->elementStart('div', 'event-description');
- // TRANS: Field label for event description.
- $out->element('strong', null, _m('Description:'));
- $out->element('span', 'description', $event->description);
- $out->elementEnd('div');
- }
-
- $rsvps = $event->getRSVPs();
-
- $out->elementStart('div', 'event-rsvps');
- // TRANS: Field label for event description.
-
- $out->text(_('Attending:'));
- $out->elementStart('ul', 'attending-list');
-
- foreach ($rsvps as $verb => $responses) {
- $out->elementStart('li', 'rsvp-list');
- switch ($verb)
- {
- case RSVP::POSITIVE:
- $out->text(_('Yes:'));
- break;
- case RSVP::NEGATIVE:
- $out->text(_('No:'));
- break;
- case RSVP::POSSIBLE:
- $out->text(_('Maybe:'));
- break;
- }
- $ids = array();
- foreach ($responses as $response) {
- $ids[] = $response->profile_id;
- }
- $ids = array_slice($ids, 0, ProfileMiniList::MAX_PROFILES + 1);
- $profiles = Profile::pivotGet('id', $ids);
- $profile = new ArrayWrapper(array_values($profiles));
- $minilist = new ProfileMiniList($profile, $out);
- $minilist->show();
-
- $out->elementEnd('li');
- }
-
- $out->elementEnd('ul');
- $out->elementEnd('div');
-
- $user = common_current_user();
-
- if (!empty($user)) {
- $rsvp = $event->getRSVP($user->getProfile());
-
- if (empty($rsvp)) {
- $form = new RSVPForm($event, $out);
- } else {
- $form = new CancelRSVPForm($rsvp, $out);
- }
-
- $form->show();
- }
-
- $out->elementEnd('div'); // vevent out
- }
-}
+++ /dev/null
-<?php
-/**
- * Helper class for calculating and displaying event times
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * 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/>.
- */
-
-/**
- * Class to get fancy times for the dropdowns on the new event form
- */
-class EventTimeList {
- /**
- * Round up to the nearest half hour
- *
- * @param string $time the time to round (date/time string)
- * @return DateTime the rounded time
- */
- public static function nearestHalfHour($time)
- {
- $startd = new DateTime($time);
-
- $minutes = $startd->format('i');
- $hour = $startd->format('H');
-
- if ($minutes >= 30) {
- $minutes = '00';
- $hour++;
- } else {
- $minutes = '30';
- }
-
- $startd->setTime($hour, $minutes, 0);
-
- return $startd;
- }
-
- /**
- * Output a list of times in half-hour intervals
- *
- * @param string $start Time to start with (date string, usually a ts)
- * @param boolean $duration Whether to include the duration of the event
- * (from the start)
- * @return array $times (localized 24 hour time string => fancy time string)
- */
- public static function getTimes($start = 'now', $duration = false)
- {
- $newTime = new DateTime($start);
- $times = array();
- $len = 0;
-
- $newTime->setTimezone(new DateTimeZone(common_timezone()));
-
- for ($i = 0; $i < 47; $i++) {
-
- $localTime = $newTime->format("g:ia");
-
- // pretty up the end-time option list a bit
- if ($duration) {
- $hours = $len / 60;
- switch ($hours) {
- case 0:
- // TRANS: 0 minutes abbreviated. Used in a list.
- $total = ' ' . _m('(0 min)');
- break;
- case .5:
- // TRANS: 30 minutes abbreviated. Used in a list.
- $total = ' ' . _m('(30 min)');
- break;
- case 1:
- // TRANS: 1 hour. Used in a list.
- $total = ' ' . _m('(1 hour)');
- break;
- default:
- // TRANS: Number of hours (%.1f and %d). Used in a list.
- $format = is_float($hours)
- ? _m('(%.1f hours)')
- : _m('(%d hours)');
- $total = ' ' . sprintf($format, $hours);
- break;
- }
- $localTime .= $total;
- $len += 30;
- }
-
- $times[$newTime->format('g:ia')] = $localTime;
- $newTime->modify('+30min'); // 30 min intervals
- }
-
- return $times;
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form to RSVP for an event
+ *
+ * PHP version 5
+ *
+ * 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 Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * A form to RSVP for an event
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class CancelRSVPForm extends Form
+{
+ protected $rsvp = null;
+
+ function __construct($rsvp, $out=null)
+ {
+ parent::__construct($out);
+ $this->rsvp = $rsvp;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'form_event_rsvp';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('cancelrsvp');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'new_rsvp_data'));
+
+ $this->out->hidden('rsvp-id', $this->rsvp->id, 'rsvp');
+
+ switch (RSVP::verbFor($this->rsvp->response)) {
+ case RSVP::POSITIVE:
+ // TRANS: Possible status for RSVP ("please respond") item.
+ $this->out->text(_m('You will attend this event.'));
+ break;
+ case RSVP::NEGATIVE:
+ // TRANS: Possible status for RSVP ("please respond") item.
+ $this->out->text(_m('You will not attend this event.'));
+ break;
+ case RSVP::POSSIBLE:
+ // TRANS: Possible status for RSVP ("please respond") item.
+ $this->out->text(_m('You might attend this event.'));
+ break;
+ }
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text to cancel responding to an RSVP ("please respond") item.
+ $this->out->submit('rsvp-cancel', _m('BUTTON', 'Cancel'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for entering an event
+ *
+ * PHP version 5
+ *
+ * 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 Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form for adding an event
+ *
+ * @category Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class EventForm extends Form
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'form_new_event';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings ajax-notice';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('newevent');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'new_event_data'));
+
+ // Passing in the URL of the Ajax action that the .js for this form hits
+ // when selecting event start and end times. JavaScript will try to
+ // use a relative path, unless explicitely told where an action is,
+ // and that's a bit difficult to calculate since the event form is on
+ // so many pages with different paths. It might be worth solving this
+ // globally by putting the base site path in the Identifier-URL meta tag
+ // or something similar, so it would be easy to calculate the exact path
+ // for actions and other things in JavaScripts. -z
+ $this->out->hidden('timelist_action_url', common_local_url('timelist'));
+
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('event-title',
+ // TRANS: Field label on event form.
+ _m('LABEL','Title'),
+ null,
+ // TRANS: Field title on event form.
+ _m('Title of the event.'),
+ 'title');
+ $this->unli();
+
+ $this->li();
+
+ $today = new DateTime('now');
+ $today->setTimezone(new DateTimeZone(common_timezone()));
+
+ $this->out->input('event-startdate',
+ // TRANS: Field label on event form.
+ _m('LABEL','Start date'),
+ $today->format('m/d/Y'),
+ // TRANS: Field title on event form.
+ _m('Date the event starts.'),
+ 'startdate');
+ $this->unli();
+
+ $this->li();
+
+ $times = EventTimeList::getTimes($today->format('m/d/Y 12:00') . ' am ' . $today->format('T'));
+ $start = EventTimeList::nearestHalfHour($today->format('c'));
+ $start->setTimezone(new DateTimeZone(common_timezone()));
+
+ $this->out->dropdown(
+ 'event-starttime',
+ // TRANS: Field label on event form.
+ _m('LABEL','Start time'),
+ $times,
+ // TRANS: Field title on event form. %s is the abbreviated timezone
+ sprintf(_m("Time the event starts (%s)."), $today->format('T')),
+ false,
+ $start->format('g:ia')
+ );
+
+ // Need to keep JavaScript TZ in sync with PHP TZ
+ $this->out->hidden('tz', $today->format('T'));
+ $this->out->hidden('now', $today->format('F d, Y H:i:s T'));
+
+ $this->unli();
+
+ $this->li();
+ $this->out->input('event-enddate',
+ // TRANS: Field label on event form.
+ _m('LABEL','End date'),
+ $today->format('m/d/Y'),
+ // TRANS: Field title on event form.
+ _m('Date the event ends.'),
+ 'enddate');
+ $this->unli();
+
+ $this->li();
+
+ $this->out->dropdown(
+ 'event-endtime',
+ // TRANS: Field label on event form.
+ _m('LABEL','End time'),
+ EventTimeList::getTimes($start->format('c'), true),
+ // TRANS: Field title on event form.
+ _m('Time the event ends.'),
+ false,
+ null
+ );
+ $this->unli();
+
+ $this->li();
+ $this->out->input('event-location',
+ // TRANS: Field label on event form.
+ _m('LABEL','Where?'),
+ null,
+ // TRANS: Field title on event form.
+ _m('Event location.'),
+ 'location');
+ $this->unli();
+
+ $this->li();
+ $this->out->input('event-url',
+ // TRANS: Field label on event form.
+ _m('LABEL','URL'),
+ null,
+ // TRANS: Field title on event form.
+ _m('URL for more information.'),
+ 'url');
+ $this->unli();
+
+ $this->li();
+ $this->out->input('event-description',
+ // TRANS: Field label on event form.
+ _m('LABEL','Description'),
+ null,
+ // TRANS: Field title on event form.
+ _m('Description of the event.'),
+ 'description');
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+
+ $toWidget = new ToSelector($this->out,
+ common_current_user(),
+ null);
+ $toWidget->show();
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text to save an event..
+ $this->out->submit('event-submit', _m('BUTTON', 'Save'), 'submit', 'submit');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form to RSVP for an event
+ *
+ * PHP version 5
+ *
+ * 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 Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * A form to RSVP for an event
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class RSVPForm extends Form
+{
+ protected $event = null;
+
+ function __construct($event, $out=null)
+ {
+ parent::__construct($out);
+ $this->event = $event;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'form_event_rsvp';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('newrsvp');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'new_rsvp_data'));
+
+ // TRANS: Field label on form to RSVP ("please respond") for an event.
+ $this->out->text(_m('RSVP:'));
+
+ $this->out->hidden('event-id', $this->event->id, 'event');
+ $this->out->hidden('submitvalue', '');
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text for RSVP ("please respond") reply to confirm attendence.
+ $this->submitButton('yes', _m('BUTTON', 'Yes'));
+ // TRANS: Button text for RSVP ("please respond") reply to deny attendence.
+ $this->submitButton('no', _m('BUTTON', 'No'));
+ // TRANS: Button text for RSVP ("please respond") reply to indicate one might attend.
+ $this->submitButton('maybe', _m('BUTTON', 'Maybe'));
+ }
+
+ function submitButton($id, $label)
+ {
+ $this->out->element(
+ 'input',
+ array(
+ 'type' => 'submit',
+ 'id' => 'rsvp-submit',
+ 'name' => $id,
+ 'class' => 'submit',
+ 'value' => $label,
+ 'title' => $label,
+ 'onClick' => 'this.form.submitvalue.value = this.name; return true;'
+ )
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Notice-list representation of an event
+ *
+ * PHP version 5
+ *
+ * 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 Event
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Notice-list representation of an event
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class EventListItem extends NoticeListItemAdapter
+{
+ function showNotice()
+ {
+ $this->nli->out->elementStart('div', 'entry-title');
+ $this->nli->showAuthor();
+ $this->showContent();
+ $this->nli->out->elementEnd('div');
+ }
+
+ function showContent()
+ {
+ $notice = $this->nli->notice;
+ $out = $this->nli->out;
+
+ $profile = $notice->getProfile();
+ $event = Happening::fromNotice($notice);
+
+ if (empty($event)) {
+ // TRANS: Content for a deleted RSVP list item (RSVP stands for "please respond").
+ $out->element('p', null, _m('Deleted.'));
+ return;
+ }
+
+ $out->elementStart('div', 'vevent event'); // VEVENT IN
+
+ $out->elementStart('h3'); // VEVENT/H3 IN
+
+ if (!empty($event->url)) {
+ $out->element('a',
+ array('href' => $event->url,
+ 'class' => 'event-title entry-title summary'),
+ $event->title);
+ } else {
+ $out->text($event->title);
+ }
+
+ $out->elementEnd('h3'); // VEVENT/H3 OUT
+
+ $now = new DateTime();
+ $startDate = new DateTime($event->start_time);
+ $endDate = new DateTime($event->end_time);
+ $userTz = new DateTimeZone(common_timezone());
+
+ // Localize the time for the observer
+ $now->setTimeZone($userTz);
+ $startDate->setTimezone($userTz);
+ $endDate->setTimezone($userTz);
+
+ $thisYear = $now->format('Y');
+ $startYear = $startDate->format('Y');
+ $endYear = $endDate->format('Y');
+
+ $dateFmt = 'D, F j, '; // e.g.: Mon, Aug 31
+
+ if ($startYear != $thisYear || $endYear != $thisYear) {
+ $dateFmt .= 'Y,'; // append year if we need to think about years
+ }
+
+ $startDateStr = $startDate->format($dateFmt);
+ $endDateStr = $endDate->format($dateFmt);
+
+ $timeFmt = 'g:ia';
+
+ $startTimeStr = $startDate->format($timeFmt);
+ $endTimeStr = $endDate->format("{$timeFmt} (T)");
+
+ $out->elementStart('div', 'event-times'); // VEVENT/EVENT-TIMES IN
+
+ // TRANS: Field label for event description.
+ $out->element('strong', null, _m('Time:'));
+
+ $out->element('abbr', array('class' => 'dtstart',
+ 'title' => common_date_iso8601($event->start_time)),
+ $startDateStr . ' ' . $startTimeStr);
+ $out->text(' – ');
+ if ($startDateStr == $endDateStr) {
+ $out->element('span', array('class' => 'dtend',
+ 'title' => common_date_iso8601($event->end_time)),
+ $endTimeStr);
+ } else {
+ $out->element('span', array('class' => 'dtend',
+ 'title' => common_date_iso8601($event->end_time)),
+ $endDateStr . ' ' . $endTimeStr);
+ }
+
+ $out->elementEnd('div'); // VEVENT/EVENT-TIMES OUT
+
+ if (!empty($event->location)) {
+ $out->elementStart('div', 'event-location');
+ // TRANS: Field label for event description.
+ $out->element('strong', null, _m('Location:'));
+ $out->element('span', 'location', $event->location);
+ $out->elementEnd('div');
+ }
+
+ if (!empty($event->description)) {
+ $out->elementStart('div', 'event-description');
+ // TRANS: Field label for event description.
+ $out->element('strong', null, _m('Description:'));
+ $out->element('span', 'description', $event->description);
+ $out->elementEnd('div');
+ }
+
+ $rsvps = $event->getRSVPs();
+
+ $out->elementStart('div', 'event-rsvps');
+ // TRANS: Field label for event description.
+
+ $out->text(_('Attending:'));
+ $out->elementStart('ul', 'attending-list');
+
+ foreach ($rsvps as $verb => $responses) {
+ $out->elementStart('li', 'rsvp-list');
+ switch ($verb)
+ {
+ case RSVP::POSITIVE:
+ $out->text(_('Yes:'));
+ break;
+ case RSVP::NEGATIVE:
+ $out->text(_('No:'));
+ break;
+ case RSVP::POSSIBLE:
+ $out->text(_('Maybe:'));
+ break;
+ }
+ $ids = array();
+ foreach ($responses as $response) {
+ $ids[] = $response->profile_id;
+ }
+ $ids = array_slice($ids, 0, ProfileMiniList::MAX_PROFILES + 1);
+ $profiles = Profile::pivotGet('id', $ids);
+ $profile = new ArrayWrapper(array_values($profiles));
+ $minilist = new ProfileMiniList($profile, $out);
+ $minilist->show();
+
+ $out->elementEnd('li');
+ }
+
+ $out->elementEnd('ul');
+ $out->elementEnd('div');
+
+ $user = common_current_user();
+
+ if (!empty($user)) {
+ $rsvp = $event->getRSVP($user->getProfile());
+
+ if (empty($rsvp)) {
+ $form = new RSVPForm($event, $out);
+ } else {
+ $form = new CancelRSVPForm($rsvp, $out);
+ }
+
+ $form->show();
+ }
+
+ $out->elementEnd('div'); // vevent out
+ }
+}
--- /dev/null
+<?php
+/**
+ * Helper class for calculating and displaying event times
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+/**
+ * Class to get fancy times for the dropdowns on the new event form
+ */
+class EventTimeList {
+ /**
+ * Round up to the nearest half hour
+ *
+ * @param string $time the time to round (date/time string)
+ * @return DateTime the rounded time
+ */
+ public static function nearestHalfHour($time)
+ {
+ $startd = new DateTime($time);
+
+ $minutes = $startd->format('i');
+ $hour = $startd->format('H');
+
+ if ($minutes >= 30) {
+ $minutes = '00';
+ $hour++;
+ } else {
+ $minutes = '30';
+ }
+
+ $startd->setTime($hour, $minutes, 0);
+
+ return $startd;
+ }
+
+ /**
+ * Output a list of times in half-hour intervals
+ *
+ * @param string $start Time to start with (date string, usually a ts)
+ * @param boolean $duration Whether to include the duration of the event
+ * (from the start)
+ * @return array $times (localized 24 hour time string => fancy time string)
+ */
+ public static function getTimes($start = 'now', $duration = false)
+ {
+ $newTime = new DateTime($start);
+ $times = array();
+ $len = 0;
+
+ $newTime->setTimezone(new DateTimeZone(common_timezone()));
+
+ for ($i = 0; $i < 47; $i++) {
+
+ $localTime = $newTime->format("g:ia");
+
+ // pretty up the end-time option list a bit
+ if ($duration) {
+ $hours = $len / 60;
+ switch ($hours) {
+ case 0:
+ // TRANS: 0 minutes abbreviated. Used in a list.
+ $total = ' ' . _m('(0 min)');
+ break;
+ case .5:
+ // TRANS: 30 minutes abbreviated. Used in a list.
+ $total = ' ' . _m('(30 min)');
+ break;
+ case 1:
+ // TRANS: 1 hour. Used in a list.
+ $total = ' ' . _m('(1 hour)');
+ break;
+ default:
+ // TRANS: Number of hours (%.1f and %d). Used in a list.
+ $format = is_float($hours)
+ ? _m('(%.1f hours)')
+ : _m('(%d hours)');
+ $total = ' ' . sprintf($format, $hours);
+ break;
+ }
+ $localTime .= $total;
+ $len += 30;
+ }
+
+ $times[$newTime->format('g:ia')] = $localTime;
+ $newTime->modify('+30min'); // 30 min intervals
+ }
+
+ return $times;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Title of module
+ *
+ * PHP version 5
+ *
+ * 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 Cache
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Class comment
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class RSVPListItem extends NoticeListItemAdapter
+{
+ function showNotice()
+ {
+ $this->nli->out->elementStart('div', 'entry-title');
+ $this->nli->showAuthor();
+ $this->showContent();
+ $this->nli->out->elementEnd('div');
+ }
+
+ function showContent()
+ {
+ $notice = $this->nli->notice;
+ $out = $this->nli->out;
+
+ $rsvp = RSVP::fromNotice($notice);
+
+ if (empty($rsvp)) {
+ // TRANS: Content for a deleted RSVP list item (RSVP stands for "please respond").
+ $out->element('p', null, _m('Deleted.'));
+ return;
+ }
+
+ $out->elementStart('div', 'rsvp');
+ $out->raw($rsvp->asHTML());
+ $out->elementEnd('div');
+ return;
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Add a new event
- *
- * PHP version 5
- *
- * 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 Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Add a new event
- *
- * @category Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class NeweventAction extends Action
-{
- protected $user = null;
- protected $error = null;
- protected $complete = null;
- protected $title = null;
- protected $location = null;
- protected $description = null;
- protected $startTime = null;
- protected $endTime = null;
-
- /**
- * Returns the title of the action
- *
- * @return string Action title
- */
- function title()
- {
- // TRANS: Title for new event form.
- return _m('TITLE','New event');
- }
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Client exception thrown when trying to post an event while not logged in.
- throw new ClientException(_m('Must be logged in to post a event.'),
- 403);
- }
-
- if ($this->isPost()) {
- $this->checkSessionToken();
- }
-
- try {
-
- $this->title = $this->trimmed('title');
-
- if (empty($this->title)) {
- // TRANS: Client exception thrown when trying to post an event without providing a title.
- throw new ClientException(_m('Title required.'));
- }
-
- $this->location = $this->trimmed('location');
- $this->url = $this->trimmed('url');
- $this->description = $this->trimmed('description');
- $tz = $this->trimmed('tz');
-
- $startDate = $this->trimmed('startdate');
-
- if (empty($startDate)) {
- // TRANS: Client exception thrown when trying to post an event without providing a start date.
- throw new ClientException(_m('Start date required.'));
- }
-
- $startTime = $this->trimmed('event-starttime');
-
- if (empty($startTime)) {
- $startTime = '00:00';
- }
-
- $endDate = $this->trimmed('enddate');
-
- if (empty($endDate)) {
- // TRANS: Client exception thrown when trying to post an event without providing an end date.
- throw new ClientException(_m('End date required.'));
- }
-
- $endTime = $this->trimmed('event-endtime');
-
- if (empty($endTime)) {
- $endTime = '00:00';
- }
-
- $start = $startDate . ' ' . $startTime . ' ' . $tz;
- $end = $endDate . ' ' . $endTime . ' ' . $tz;
-
- $this->startTime = strtotime($start);
- $this->endTime = strtotime($end);
-
- if ($this->startTime == 0) {
- // TRANS: Client exception thrown when trying to post an event with a date that cannot be processed.
- // TRANS: %s is the data that could not be processed.
- throw new ClientException(sprintf(_m('Could not parse date "%s".'),
- $start));
- }
-
- if ($this->endTime == 0) {
- // TRANS: Client exception thrown when trying to post an event with a date that cannot be processed.
- // TRANS: %s is the data that could not be processed.
- throw new ClientException(sprintf(_m('Could not parse date "%s".'),
- $end));
- }
- } catch (ClientException $ce) {
- if ($this->boolean('ajax')) {
- $this->outputAjaxError($ce->getMessage());
- return false;
- } else {
- $this->error = $ce->getMessage();
- $this->showPage();
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- parent::handle($argarray);
-
- if ($this->isPost()) {
- $this->newEvent();
- } else {
- $this->showPage();
- }
-
- return;
- }
-
- /**
- * Add a new event
- *
- * @return void
- */
- function newEvent()
- {
- try {
-
- if (empty($this->title)) {
- // TRANS: Client exception thrown when trying to post an event without providing a title.
- throw new ClientException(_m('Event must have a title.'));
- }
-
- if (empty($this->startTime)) {
- // TRANS: Client exception thrown when trying to post an event without providing a start time.
- throw new ClientException(_m('Event must have a start time.'));
- }
-
- if (empty($this->endTime)) {
- // TRANS: Client exception thrown when trying to post an event without providing an end time.
- throw new ClientException(_m('Event must have an end time.'));
- }
-
- if (!empty($this->url) && Validate::uri($this->url) === false) {
- // TRANS: Client exception thrown when trying to post an event with an invalid URL.
- throw new ClientException(_m('URL must be valid.'));
- }
-
- $options = array();
-
- // Does the heavy-lifting for getting "To:" information
-
- ToSelector::fillOptions($this, $options);
-
- $profile = $this->user->getProfile();
-
- $saved = Happening::saveNew($profile,
- $this->startTime,
- $this->endTime,
- $this->title,
- $this->location,
- $this->description,
- $this->url,
- $options);
-
- $event = Happening::fromNotice($saved);
-
- RSVP::saveNew($profile, $event, RSVP::POSITIVE);
-
- } catch (ClientException $ce) {
- if ($this->boolean('ajax')) {
- $this->outputAjaxError($ce->getMessage());
- return;
- } else {
- $this->error = $ce->getMessage();
- $this->showPage();
- return;
- }
- }
-
- if ($this->boolean('ajax')) {
- header('Content-Type: text/xml;charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: Page title after sending a notice.
- $this->element('title', null, _m('Event saved'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $this->showNotice($saved);
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- common_redirect($saved->bestUrl(), 303);
- }
- }
-
- // @todo factor this out into a base class
- function outputAjaxError($msg)
- {
- header('Content-Type: text/xml;charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: Page title after an AJAX error occurs
- $this->element('title', null, _('Ajax Error'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $this->element('p', array('id' => 'error'), $msg);
- $this->elementEnd('body');
- $this->elementEnd('html');
- return;
- }
-
- /**
- * Show the event form
- *
- * @return void
- */
- function showContent()
- {
- if (!empty($this->error)) {
- $this->element('p', 'error', $this->error);
- }
-
- $form = new EventForm($this);
-
- $form->show();
-
- return;
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
- $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- return true;
- } else {
- return false;
- }
- }
-
-
- /**
- * Output a notice
- *
- * Used to generate the notice code for Ajax results.
- *
- * @param Notice $notice Notice that was saved
- *
- * @return void
- */
- function showNotice($notice)
- {
- $nli = new NoticeListItem($notice, $this);
- $nli->show();
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * RSVP for an event
- *
- * PHP version 5
- *
- * 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 Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * RSVP for an event
- *
- * @category Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class NewrsvpAction extends Action
-{
- protected $user = null;
- protected $event = null;
- protected $verb = null;
-
- /**
- * Returns the title of the action
- *
- * @return string Action title
- */
- function title()
- {
- // TRANS: Title for RSVP ("please respond") action.
- return _m('TITLE','New RSVP');
- }
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
- if ($this->boolean('ajax')) {
- StatusNet::setApi(true); // short error results!
- }
-
- $eventId = $this->trimmed('event');
-
- if (empty($eventId)) {
- // TRANS: Client exception thrown when referring to a non-existing event.
- throw new ClientException(_m('No such event.'));
- }
-
- $this->event = Happening::getKV('id', $eventId);
-
- if (empty($this->event)) {
- // TRANS: Client exception thrown when referring to a non-existing event.
- throw new ClientException(_m('No such event.'));
- }
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Client exception thrown when trying to RSVP ("please respond") while not logged in.
- throw new ClientException(_m('You must be logged in to RSVP for an event.'));
- }
-
- common_debug(print_r($this->args, true));
-
- switch (strtolower($this->trimmed('submitvalue'))) {
- case 'yes':
- $this->verb = RSVP::POSITIVE;
- break;
- case 'no':
- $this->verb = RSVP::NEGATIVE;
- break;
- case 'maybe':
- $this->verb = RSVP::POSSIBLE;
- break;
- default:
- // TRANS: Client exception thrown when using an invalid value for RSVP ("please respond").
- throw new ClientException(_m('Unknown submit value.'));
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- parent::handle($argarray);
-
- if ($this->isPost()) {
- $this->newRSVP();
- } else {
- $this->showPage();
- }
-
- return;
- }
-
- /**
- * Add a new event
- *
- * @return void
- */
- function newRSVP()
- {
- try {
- $saved = RSVP::saveNew($this->user->getProfile(),
- $this->event,
- $this->verb);
- } catch (ClientException $ce) {
- $this->error = $ce->getMessage();
- $this->showPage();
- return;
- }
-
- if ($this->boolean('ajax')) {
- $rsvp = RSVP::fromNotice($saved);
- header('Content-Type: text/xml;charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: Page title after creating an event.
- $this->element('title', null, _m('Event saved'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $this->elementStart('body');
- $cancel = new CancelRSVPForm($rsvp, $this);
- $cancel->show();
- $this->elementEnd('body');
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- common_redirect($saved->bestUrl(), 303);
- }
- }
-
- /**
- * Show the event form
- *
- * @return void
- */
- function showContent()
- {
- if (!empty($this->error)) {
- $this->element('p', 'error', $this->error);
- }
-
- $form = new RSVPForm($this->event, $this);
-
- $form->show();
-
- return;
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
- $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- return true;
- } else {
- return false;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form to RSVP for an event
- *
- * PHP version 5
- *
- * 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 Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * A form to RSVP for an event
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class RSVPForm extends Form
-{
- protected $event = null;
-
- function __construct($event, $out=null)
- {
- parent::__construct($out);
- $this->event = $event;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'form_event_rsvp';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'ajax';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('newrsvp');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'new_rsvp_data'));
-
- // TRANS: Field label on form to RSVP ("please respond") for an event.
- $this->out->text(_m('RSVP:'));
-
- $this->out->hidden('event-id', $this->event->id, 'event');
- $this->out->hidden('submitvalue', '');
-
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text for RSVP ("please respond") reply to confirm attendence.
- $this->submitButton('yes', _m('BUTTON', 'Yes'));
- // TRANS: Button text for RSVP ("please respond") reply to deny attendence.
- $this->submitButton('no', _m('BUTTON', 'No'));
- // TRANS: Button text for RSVP ("please respond") reply to indicate one might attend.
- $this->submitButton('maybe', _m('BUTTON', 'Maybe'));
- }
-
- function submitButton($id, $label)
- {
- $this->out->element(
- 'input',
- array(
- 'type' => 'submit',
- 'id' => 'rsvp-submit',
- 'name' => $id,
- 'class' => 'submit',
- 'value' => $label,
- 'title' => $label,
- 'onClick' => 'this.form.submitvalue.value = this.name; return true;'
- )
- );
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Title of module
- *
- * PHP version 5
- *
- * 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 Cache
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Class comment
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class RSVPListItem extends NoticeListItemAdapter
-{
- function showNotice()
- {
- $this->nli->out->elementStart('div', 'entry-title');
- $this->nli->showAuthor();
- $this->showContent();
- $this->nli->out->elementEnd('div');
- }
-
- function showContent()
- {
- $notice = $this->nli->notice;
- $out = $this->nli->out;
-
- $rsvp = RSVP::fromNotice($notice);
-
- if (empty($rsvp)) {
- // TRANS: Content for a deleted RSVP list item (RSVP stands for "please respond").
- $out->element('p', null, _m('Deleted.'));
- return;
- }
-
- $out->elementStart('div', 'rsvp');
- $out->raw($rsvp->asHTML());
- $out->elementEnd('div');
- return;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Show a single event
- *
- * PHP version 5
- *
- * 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 Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Show a single event, with associated information
- *
- * @category Event
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ShoweventAction extends ShownoticeAction
-{
- protected $id = null;
- protected $event = null;
-
- function getNotice()
- {
- $this->id = $this->trimmed('id');
-
- $this->event = Happening::getKV('id', $this->id);
-
- if (empty($this->event)) {
- // TRANS: Client exception thrown when referring to a non-existing event.
- throw new ClientException(_m('No such event.'), 404);
- }
-
- $notice = $this->event->getNotice();
-
- if (empty($notice)) {
- // Did we used to have it, and it got deleted?
- // TRANS: Client exception thrown when referring to a non-existing event.
- throw new ClientException(_m('No such event.'), 404);
- }
-
- return $notice;
- }
-
- /**
- * Title of the page
- *
- * Used by Action class for layout.
- *
- * @return string page tile
- */
- function title()
- {
- return $this->event->title;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * Show a single RSVP
- *
- * PHP version 5
- *
- * 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 RSVP
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Show a single RSVP, with associated information
- *
- * @category RSVP
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ShowrsvpAction extends ShownoticeAction
-{
- protected $rsvp = null;
- protected $event = null;
-
- function getNotice()
- {
- $this->id = $this->trimmed('id');
-
- $this->rsvp = RSVP::getKV('id', $this->id);
-
- if (empty($this->rsvp)) {
- // TRANS: Client exception thrown when referring to a non-existing RSVP.
- // TRANS: RSVP stands for "Please reply".
- throw new ClientException(_m('No such RSVP.'), 404);
- }
-
- $this->event = $this->rsvp->getEvent();
-
- if (empty($this->event)) {
- // TRANS: Client exception thrown when referring to a non-existing event.
- throw new ClientException(_m('No such event.'), 404);
- }
-
- $notice = $this->rsvp->getNotice();
-
- if (empty($notice)) {
- // Did we used to have it, and it got deleted?
- // TRANS: Client exception thrown when referring to a non-existing RSVP.
- // TRANS: RSVP stands for "Please reply".
- throw new ClientException(_m('No such RSVP.'), 404);
- }
-
- return $notice;
- }
-
- /**
- * Title of the page
- *
- * Used by Action class for layout.
- *
- * @return string page tile
- */
- function title()
- {
- // TRANS: Title for event.
- // TRANS: %1$s is a user nickname, %2$s is an event title.
- return sprintf(_m('%1$s\'s RSVP for "%2$s"'),
- $this->user->nickname,
- $this->event->title);
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * 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 Event
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Callback handler to populate end time dropdown
- */
-class TimelistAction extends Action {
- private $start;
- private $duration;
-
- /**
- * Get ready
- *
- * @param array $args misc. arguments
- *
- * @return boolean true
- */
- function prepare($args) {
- parent::prepare($args);
- $this->start = $this->arg('start');
- $this->duration = $this->boolean('duration', false);
- return true;
- }
-
- /**
- * Handle input and ouput something
- *
- * @param array $args $_REQUEST arguments
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- if (!common_logged_in()) {
- // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
- $this->clientError(_m('Not logged in.'));
- return;
- }
-
- if (!empty($this->start)) {
- $times = EventTimeList::getTimes($this->start, $this->duration);
- } else {
- // TRANS: Client error when submitting a form with unexpected information.
- $this->clientError(_m('Unexpected form submission.'));
- return;
- }
-
- if ($this->boolean('ajax')) {
- header('Content-Type: application/json; charset=utf-8');
- print json_encode($times);
- } else {
- // TRANS: Client error displayed when using an action in a non-AJAX way.
- $this->clientError(_m('This action is AJAX only.'));
- }
- }
-
- /**
- * Override the regular error handler to show something more
- * ajaxy
- *
- * @param string $msg error message
- * @param int $code error code
- */
- function clientError($msg, $code = 400) {
- if ($this->boolean('ajax')) {
- header('Content-Type: application/json; charset=utf-8');
- print json_encode(
- array(
- 'success' => false,
- 'code' => $code,
- 'message' => $msg
- )
- );
- } else {
- parent::clientError($msg, $code);
- }
- }
-}
return true;
}
- /**
- * Autoloader
- *
- * Loads our classes if they're requested.
- *
- * @param string $cls Class requested
- *
- * @return boolean hook return
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch (strtolower($cls))
- {
- case 'profiledetailaction':
- case 'profiledetailsettingsaction':
- case 'userautocompleteaction':
- include_once $dir . '/actions/'
- . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- break; // Safety first!
- case 'extendedprofile':
- case 'extendedprofilewidget':
- include_once $dir . '/lib/' . strtolower($cls) . '.php';
- return false;
- break;
- case 'profile_detail':
- include_once $dir . '/classes/' . ucfirst($cls) . '.php';
- return false;
- break;
- default:
- return true;
- }
- }
-
/**
* Add paths to the router table
*
include_once $dir . '/extlib/base_facebook.php';
include_once $dir . '/extlib/facebook.php';
return false;
- case 'FacebookloginAction':
- case 'FacebookfinishloginAction':
- case 'FacebookadminpanelAction':
- case 'FacebooksettingsAction':
- case 'FacebookdeauthorizeAction':
- include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'Facebookclient':
- case 'FacebookQueueHandler':
- include_once $dir . '/lib/' . strtolower($cls) . '.php';
- return false;
- case 'Notice_to_item':
- include_once $dir . '/classes/' . $cls . '.php';
- return false;
- default:
- return true;
}
+
+ return parent::onAutoload($cls);
}
/**
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'User_followeveryone_prefs':
- include_once $dir . '/'.$cls.'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Show a checkbox on the profile form to ask whether to follow everyone
*
+++ /dev/null
-<?php
-/**
- * Data class for counting greetings
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for counting greetings
- *
- * We use the DB_DataObject framework for data classes in StatusNet. Each
- * table maps to a particular data class, making it easier to manipulate
- * data.
- *
- * Data classes should extend Memcached_DataObject, the (slightly misnamed)
- * extension of DB_DataObject that provides caching, internationalization,
- * and other bits of good functionality to StatusNet-specific data classes.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class User_followeveryone_prefs extends Managed_DataObject
-{
- public $__table = 'user_followeveryone_prefs'; // table name
- public $user_id; // int(4) primary_key not_null
- public $followeveryone; // tinyint(1)
- public $created; // datetime() not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
- 'followeveryone' => array('type' => 'int', 'default' => 1, 'size' => 'tiny', 'description' => 'whether to follow everyone'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('user_id'),
- 'foreign keys' => array(
- 'user_followeveryone_prefs_user_id_fkey' => array('user', array('user_id' => 'id')),
- ),
- );
- }
-
- static function followEveryone($user_id)
- {
- $ufep = self::getKV('user_id', $user_id);
-
- if (empty($ufep)) {
- return true;
- } else {
- return (bool)$ufep->followeveryone;
- }
- }
-
- static function savePref($user_id, $followEveryone)
- {
- $ufep = self::getKV('user_id', $user_id);
-
- if (empty($ufep)) {
- $ufep = new User_followeveryone_prefs();
- $ufep->user_id = $user_id;
- $ufep->followeveryone = $followEveryone;
- $ufep->insert();
- } else {
- $orig = clone($ufep);
- $ufep->followeveryone = $followEveryone;
- $ufep->update();
- }
-
- return true;
- }
-}
--- /dev/null
+<?php
+/**
+ * Data class for counting greetings
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for counting greetings
+ *
+ * We use the DB_DataObject framework for data classes in StatusNet. Each
+ * table maps to a particular data class, making it easier to manipulate
+ * data.
+ *
+ * Data classes should extend Memcached_DataObject, the (slightly misnamed)
+ * extension of DB_DataObject that provides caching, internationalization,
+ * and other bits of good functionality to StatusNet-specific data classes.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class User_followeveryone_prefs extends Managed_DataObject
+{
+ public $__table = 'user_followeveryone_prefs'; // table name
+ public $user_id; // int(4) primary_key not_null
+ public $followeveryone; // tinyint(1)
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
+ 'followeveryone' => array('type' => 'int', 'default' => 1, 'size' => 'tiny', 'description' => 'whether to follow everyone'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('user_id'),
+ 'foreign keys' => array(
+ 'user_followeveryone_prefs_user_id_fkey' => array('user', array('user_id' => 'id')),
+ ),
+ );
+ }
+
+ static function followEveryone($user_id)
+ {
+ $ufep = self::getKV('user_id', $user_id);
+
+ if (empty($ufep)) {
+ return true;
+ } else {
+ return (bool)$ufep->followeveryone;
+ }
+ }
+
+ static function savePref($user_id, $followEveryone)
+ {
+ $ufep = self::getKV('user_id', $user_id);
+
+ if (empty($ufep)) {
+ $ufep = new User_followeveryone_prefs();
+ $ufep->user_id = $user_id;
+ $ufep->followeveryone = $followEveryone;
+ $ufep->insert();
+ } else {
+ $orig = clone($ufep);
+ $ufep->followeveryone = $followEveryone;
+ $ufep->update();
+ }
+
+ return true;
+ }
+}
return true;
}
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
- switch($cls)
- {
- case 'Photo':
- include_once $dir . '/Photo.php';
- break;
- case 'NewPhotoForm':
- include_once $dir . '/newphotoform.php';
- break;
- case 'NewphotoAction':
- include_once $dir . '/newphoto.php';
- break;
- default:
- break;
- }
- return true;
- }
-
function onRouterInitialized($m)
{
$m->connect('main/photo/new', array('action' => 'newphoto'));
+++ /dev/null
-<?php
-/**
- * GNU Social
- * Copyright (C) 2011, Free Software Foundation, Inc.
- *
- * 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/>.
- *
- * @package GNU Social
- * @author Ian Denhardt <ian@zenhack.net>
- * @copyright 2011 Free Software Foundation, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- */
-
-if(!defined('STATUSNET')){
- exit(1);
-}
-
-/**
- * Data class for photos.
- */
-
-class Photo extends Managed_DataObject
-{
- const OBJECT_TYPE = 'http://activitystrea.ms/schema/1.0/photo';
-
- public $__table = 'photo'; // table name
- public $id; // char (36) // UUID
- public $uri; // varchar (255) // This is the corresponding notice's uri.
- public $photo_uri; // varchar (255)
- public $thumb_uri; // varchar (255)
- public $title; // varchar (255)
- public $description; // text
- public $profile_id; // int
-
- public static function getByNotice($notice)
- {
- return self::getKV('uri', $notice->uri);
- }
-
- public function getNotice()
- {
- return Notice::getKV('uri', $this->uri);
- }
-
- public static function schemaDef()
- {
- return array(
- 'description' => 'A photograph',
- 'fields' => array(
- 'id' => array('type' => 'char',
- 'length' => 36,
- 'not null' => true,
- 'description' => 'UUID'),
- 'uri' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true),
- 'photo_uri' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true),
- 'photo_uri' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true),
- 'profile_id' => array('type' => 'int', 'not null' => true),
- ),
- 'primary key' => array('id'),
- 'foreign keys' => array('photo_profile_id__key' => array('profile' => array('profile_id' => 'id'))),
- );
- }
-
- function saveNew($profile, $photo_uri, $thumb_uri, $title, $description, $options=array())
- {
- $photo = new Photo();
-
- $photo->id = UUID::gen();
- $photo->profile_id = $profile->id;
- $photo->photo_uri = $photo_uri;
- $photo->thumb_uri = $thumb_uri;
-
-
- $options['object_type'] = Photo::OBJECT_TYPE;
-
- if (!array_key_exists('uri', $options)) {
- $options['uri'] = common_local_url('showphoto', array('id' => $photo->id));
- }
-
- if (!array_key_exists('rendered', $options)) {
- $options['rendered'] = sprintf("<img src=\"%s\" alt=\"%s\"></img>", $photo_uri,
- $title);
- }
-
- $photo->uri = $options['uri'];
-
- $photo->insert();
-
- return Notice::saveNew($profile->id,
- '',
- 'web',
- $options);
-
- }
-}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2011, Free Software Foundation, Inc.
+ *
+ * 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/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')){
+ exit(1);
+}
+
+class NewphotoAction extends Action
+{
+ var $user = null;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $this->user = common_current_user();
+
+ if(empty($this->user)){
+ throw new ClientException(_('Must be logged in to post a photo'),
+ 403);
+ }
+
+ if($this->isPost()){
+ $this->checkSessionToken();
+ }
+
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($this->isPost()) {
+ $this->handlePost($args);
+ } else {
+ $this->showPage();
+ }
+ }
+
+ function handlePost($args)
+ {
+
+ /*
+ // Workaround for PHP returning empty $_POST and $_FILES when POST
+ // length > post_max_size in php.ini
+ if (empty($_FILES)
+ && empty($_POST)
+ && ($_SERVER['CONTENT_LENGTH'] > 0)
+ ) {
+ $msg = _('The server was unable to handle that much POST ' .
+ 'data (%s bytes) due to its current configuration.');
+ $this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
+ return;
+ } */
+
+ $profile = $this->user->getProfile();
+
+ $options = array();
+
+ ToSelector::fillOptions($this, $options);
+
+ try {
+ $this->handleUpload();
+ } catch (Exception $e) {
+ $this->showForm($e->getMessage());
+ return;
+ }
+
+
+ common_redirect($photo->uri, 303);
+ }
+
+ function getUpload()
+ {
+ $imagefile = ImageFile::fromUpload('photo_upload');
+
+ if($imagefile === null) {
+ throw new Exception(_('No file uploaded'));
+ }
+
+ $title = $this->trimmed('title');
+ $description = $this->trimmed('description');
+
+ $new_filename = UUID::gen() . image_type_to_extension($imagefile->type);
+ move_uploaded_file($imagefile->filepath, INSTALLDIR . '/file/' . $new_filename);
+
+ // XXX: we should be using https where we can. TODO: detect whether the server
+ // supports this.
+ $photo_uri = 'http://' . common_config('site', 'server') . '/file/'
+ . $new_filename;
+ $thumb_uri = $photo_uri;
+
+
+ $photo = Photo::saveNew($profile, $photo_uri, $thumb_uri, $title,
+ $description, $options);
+
+ }
+
+ function showContent()
+ {
+ $form = new NewPhotoForm();
+ $form->show();
+ }
+}
+
+
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2011, Free Software Foundation, Inc.
+ *
+ * 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/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')){
+ exit(1);
+}
+
+
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2011, Free Software Foundation, Inc.
+ *
+ * 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/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')){
+ exit(1);
+}
+
+/**
+ * Data class for photos.
+ */
+
+class Photo extends Managed_DataObject
+{
+ const OBJECT_TYPE = 'http://activitystrea.ms/schema/1.0/photo';
+
+ public $__table = 'photo'; // table name
+ public $id; // char (36) // UUID
+ public $uri; // varchar (255) // This is the corresponding notice's uri.
+ public $photo_uri; // varchar (255)
+ public $thumb_uri; // varchar (255)
+ public $title; // varchar (255)
+ public $description; // text
+ public $profile_id; // int
+
+ public static function getByNotice($notice)
+ {
+ return self::getKV('uri', $notice->uri);
+ }
+
+ public function getNotice()
+ {
+ return Notice::getKV('uri', $this->uri);
+ }
+
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'A photograph',
+ 'fields' => array(
+ 'id' => array('type' => 'char',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'UUID'),
+ 'uri' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'photo_uri' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'photo_uri' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'profile_id' => array('type' => 'int', 'not null' => true),
+ ),
+ 'primary key' => array('id'),
+ 'foreign keys' => array('photo_profile_id__key' => array('profile' => array('profile_id' => 'id'))),
+ );
+ }
+
+ function saveNew($profile, $photo_uri, $thumb_uri, $title, $description, $options=array())
+ {
+ $photo = new Photo();
+
+ $photo->id = UUID::gen();
+ $photo->profile_id = $profile->id;
+ $photo->photo_uri = $photo_uri;
+ $photo->thumb_uri = $thumb_uri;
+
+
+ $options['object_type'] = Photo::OBJECT_TYPE;
+
+ if (!array_key_exists('uri', $options)) {
+ $options['uri'] = common_local_url('showphoto', array('id' => $photo->id));
+ }
+
+ if (!array_key_exists('rendered', $options)) {
+ $options['rendered'] = sprintf("<img src=\"%s\" alt=\"%s\"></img>", $photo_uri,
+ $title);
+ }
+
+ $photo->uri = $options['uri'];
+
+ $photo->insert();
+
+ return Notice::saveNew($profile->id,
+ '',
+ 'web',
+ $options);
+
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2011, Free Software Foundation, Inc.
+ *
+ * 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/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')){
+ exit(1);
+}
+
+class NewPhotoForm extends Form
+{
+ function id()
+ {
+ return "form_new_photo";
+ }
+
+ function action()
+ {
+ return common_local_url('newphoto');
+ }
+
+ function formClass()
+ {
+ return 'form_settings ajax-notice';
+ }
+
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'new_photo_data'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('title', _('Title'), null, _('Photo title (optional).'));
+ $this->unli();
+
+ $this->li();
+ $this->out->element('input', array('name' => 'photo_upload',
+ 'type' => 'file',
+ 'id' => 'photo_upload'));
+ $this->unli();
+
+ $this->li();
+ $this->textarea('description', _('Description'), null, _('Description of the photo (optional).'));
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+
+ $toWidget = new ToSelector($this->out,
+ common_current_user(),
+ null);
+ $toWidget->show();
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ function formActions()
+ {
+ $this->out->submit('photo-submit', _m('BUTTON', 'Save'));
+ }
+}
+++ /dev/null
-<?php
-/**
- * GNU Social
- * Copyright (C) 2011, Free Software Foundation, Inc.
- *
- * 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/>.
- *
- * @package GNU Social
- * @author Ian Denhardt <ian@zenhack.net>
- * @copyright 2011 Free Software Foundation, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- */
-
-if(!defined('STATUSNET')){
- exit(1);
-}
-
-class NewphotoAction extends Action
-{
- var $user = null;
-
- function prepare($args)
- {
- parent::prepare($args);
- $this->user = common_current_user();
-
- if(empty($this->user)){
- throw new ClientException(_('Must be logged in to post a photo'),
- 403);
- }
-
- if($this->isPost()){
- $this->checkSessionToken();
- }
-
- return true;
- }
-
- function handle($args)
- {
- parent::handle($args);
-
- if ($this->isPost()) {
- $this->handlePost($args);
- } else {
- $this->showPage();
- }
- }
-
- function handlePost($args)
- {
-
- /*
- // Workaround for PHP returning empty $_POST and $_FILES when POST
- // length > post_max_size in php.ini
- if (empty($_FILES)
- && empty($_POST)
- && ($_SERVER['CONTENT_LENGTH'] > 0)
- ) {
- $msg = _('The server was unable to handle that much POST ' .
- 'data (%s bytes) due to its current configuration.');
- $this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
- return;
- } */
-
- $profile = $this->user->getProfile();
-
- $options = array();
-
- ToSelector::fillOptions($this, $options);
-
- try {
- $this->handleUpload();
- } catch (Exception $e) {
- $this->showForm($e->getMessage());
- return;
- }
-
-
- common_redirect($photo->uri, 303);
- }
-
- function getUpload()
- {
- $imagefile = ImageFile::fromUpload('photo_upload');
-
- if($imagefile === null) {
- throw new Exception(_('No file uploaded'));
- }
-
- $title = $this->trimmed('title');
- $description = $this->trimmed('description');
-
- $new_filename = UUID::gen() . image_type_to_extension($imagefile->type);
- move_uploaded_file($imagefile->filepath, INSTALLDIR . '/file/' . $new_filename);
-
- // XXX: we should be using https where we can. TODO: detect whether the server
- // supports this.
- $photo_uri = 'http://' . common_config('site', 'server') . '/file/'
- . $new_filename;
- $thumb_uri = $photo_uri;
-
-
- $photo = Photo::saveNew($profile, $photo_uri, $thumb_uri, $title,
- $description, $options);
-
- }
-
- function showContent()
- {
- $form = new NewPhotoForm();
- $form->show();
- }
-}
-
-
+++ /dev/null
-<?php
-/**
- * GNU Social
- * Copyright (C) 2011, Free Software Foundation, Inc.
- *
- * 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/>.
- *
- * @package GNU Social
- * @author Ian Denhardt <ian@zenhack.net>
- * @copyright 2011 Free Software Foundation, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- */
-
-if(!defined('STATUSNET')){
- exit(1);
-}
-
-class NewPhotoForm extends Form
-{
- function id()
- {
- return "form_new_photo";
- }
-
- function action()
- {
- return common_local_url('newphoto');
- }
-
- function formClass()
- {
- return 'form_settings ajax-notice';
- }
-
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'new_photo_data'));
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->out->input('title', _('Title'), null, _('Photo title (optional).'));
- $this->unli();
-
- $this->li();
- $this->out->element('input', array('name' => 'photo_upload',
- 'type' => 'file',
- 'id' => 'photo_upload'));
- $this->unli();
-
- $this->li();
- $this->textarea('description', _('Description'), null, _('Description of the photo (optional).'));
- $this->unli();
-
- $this->out->elementEnd('ul');
-
- $toWidget = new ToSelector($this->out,
- common_current_user(),
- null);
- $toWidget->show();
-
- $this->out->elementEnd('fieldset');
- }
-
- function formActions()
- {
- $this->out->submit('photo-submit', _m('BUTTON', 'Save'));
- }
-}
+++ /dev/null
-<?php
-/**
- * GNU Social
- * Copyright (C) 2011, Free Software Foundation, Inc.
- *
- * 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/>.
- *
- * @package GNU Social
- * @author Ian Denhardt <ian@zenhack.net>
- * @copyright 2011 Free Software Foundation, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- */
-
-if(!defined('STATUSNET')){
- exit(1);
-}
-
-
exit(1);
}
+include_once $dir . '/lib/photolib.php';
+
class GNUsocialPhotosPlugin extends Plugin
{
-
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- include_once $dir . '/lib/tempphoto.php';
- include_once $dir . '/lib/photonav.php';
- switch ($cls)
- {
- case 'PhotosAction':
- include_once $dir . '/lib/photolib.php';
- include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- break;
- case 'PhotouploadAction':
- include_once $dir . '/lib/photolib.php';
- include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- break;
- case 'PhotoAction':
- include_once $dir . '/lib/photolib.php';
- include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- break;
- case 'EditphotoAction':
- include_once $dir . '/lib/photolib.php';
- include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- break;
- default:
- break;
- }
- include_once $dir . '/classes/gnusocialphoto.php';
- include_once $dir . '/classes/gnusocialphotoalbum.php';
- return true;
- }
-
function onCheckSchema()
{
$schema = Schema::get();
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * 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/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')) {
+ exit(1);
+}
+
+class GNUsocialPhotoNav extends Widget {
+ var $action = null;
+
+ function __construct($action = null, $nickname = null)
+ {
+ parent::__construct($action);
+ $this->action = $action;
+ $this->nickname = $nickname;
+ }
+
+ function show()
+ {
+ if (empty($this->nickname))
+ $this->nickname = $this->action->trimmed('nickname');
+
+ $this->out->elementStart('ul', array('class' => 'nav'));
+
+ $this->out->menuItem(common_local_url('showstream', array('nickname' => $this->nickname)), _('Profile'));
+
+ $this->out->menuItem(common_local_url('photos', array('nickname' => $this->nickname)),
+ _('Photos'));
+
+ $user = common_current_user();
+ if (!empty($user)) {
+ $this->out->menuItem(common_local_url('photoupload', array()),
+ _('Upload Photos'));
+ }
+
+ $this->out->elementEnd('ul');
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * 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/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+// XXX: This entire file is an ugly hack and needs to be replaced. It is essentially a global variable
+// used to store information about a photo we want to insert in onStartNoticeDistribute(), which we
+// can't actually pass to that function.
+class GNUsocialPhotoTemp {
+ public static $tmp = null;
+}
+++ /dev/null
-<?php
-/**
- * GNU Social
- * Copyright (C) 2010, Free Software Foundation, Inc.
- *
- * 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/>.
- *
- * @package GNU Social
- * @author Ian Denhardt <ian@zenhack.net>
- * @author Max Shinn <trombonechamp@gmail.com>
- * @copyright 2010 Free Software Foundation, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- */
-
-if(!defined('STATUSNET')) {
- exit(1);
-}
-
-class GNUsocialPhotoNav extends Widget {
- var $action = null;
-
- function __construct($action = null, $nickname = null)
- {
- parent::__construct($action);
- $this->action = $action;
- $this->nickname = $nickname;
- }
-
- function show()
- {
- if (empty($this->nickname))
- $this->nickname = $this->action->trimmed('nickname');
-
- $this->out->elementStart('ul', array('class' => 'nav'));
-
- $this->out->menuItem(common_local_url('showstream', array('nickname' => $this->nickname)), _('Profile'));
-
- $this->out->menuItem(common_local_url('photos', array('nickname' => $this->nickname)),
- _('Photos'));
-
- $user = common_current_user();
- if (!empty($user)) {
- $this->out->menuItem(common_local_url('photoupload', array()),
- _('Upload Photos'));
- }
-
- $this->out->elementEnd('ul');
- }
-}
+++ /dev/null
-<?php
-/**
- * GNU Social
- * Copyright (C) 2010, Free Software Foundation, Inc.
- *
- * 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/>.
- *
- * @package GNU Social
- * @author Ian Denhardt <ian@zenhack.net>
- * @copyright 2010 Free Software Foundation, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-// XXX: This entire file is an ugly hack and needs to be replaced. It is essentially a global variable
-// used to store information about a photo we want to insert in onStartNoticeDistribute(), which we
-// can't actually pass to that function.
-class GNUsocialPhotoTemp {
- public static $tmp = null;
-}
exit(1);
}
+include_once $dir . '/lib/profiletools.php';
+
class GNUsocialProfileExtensionsPlugin extends Plugin
{
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'BioAction':
- case 'NewresponseAction':
- include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- break;
- case 'ProfilefieldsAdminPanelAction':
- include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -16)) . '.php';
- break;
- default:
- break;
- }
- include_once $dir . '/classes/GNUsocialProfileExtensionField.php';
- include_once $dir . '/classes/GNUsocialProfileExtensionResponse.php';
- include_once $dir . '/lib/profiletools.php';
- include_once $dir . '/lib/noticetree.php';
- return true;
- }
-
function onCheckSchema()
{
$schema = Schema::get();
return true;
}
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
- switch($cls)
- {
- case 'PostvideoAction':
- include_once $dir . '/actions/postvideo.php';
- break;
- case 'Video':
- include_once $dir . '/Video.php';
- break;
- case 'VideoForm':
- include_once $dir . '/videoform.php';
- break;
- case 'ShowvideoAction':
- include_once $dir . '/showvideo.php';
- break;
- default:
- break;
- }
- return true;
- }
-
function onRouterInitialized($m)
{
$m->connect('main/postvideo', array('action' => 'postvideo'));
+++ /dev/null
-<?php
-/**
- * GNU Social
- * Copyright (C) 2011, Free Software Foundation, Inc.
- *
- * 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/>.
- *
- * @package GNU Social
- * @author Ian Denhardt <ian@zenhack.net>
- * @copyright 2011 Free Software Foundation, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- */
-
-if(!defined('STATUSNET')){
- exit(1);
-}
-
-/**
- * Data class for videos.
- */
-
-class Video extends Managed_DataObject
-{
- const OBJECT_TYPE = 'http://activitystrea.ms/schema/1.0/video';
-
- public $__table = 'video'; // table name
- public $id; // char (36) // UUID
- public $uri; // varchar (255) // This is the corresponding notice's uri.
- public $url; // varchar (255)
- public $profile_id; // int
-
- public static function getByNotice($notice)
- {
- return self::getKV('uri', $notice->uri);
- }
-
- public function getNotice()
- {
- return Notice::getKV('uri', $this->uri);
- }
-
- public static function schemaDef()
- {
- return array(
- 'description' => 'A video clip',
- 'fields' => array(
- 'id' => array('type' => 'char',
- 'length' => 36,
- 'not null' => true,
- 'description' => 'UUID'),
- 'uri' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true),
- 'url' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true),
- 'profile_id' => array('type' => 'int', 'not null' => true),
- ),
- 'primary key' => array('id'),
- 'foreign keys' => array('video_profile_id__key' => array('profile' => array('profile_id' => 'id'))),
- );
- }
-
- function saveNew($profile, $url, $options=array())
- {
- $vid = new Video();
-
- $vid->id = UUID::gen();
- $vid->profile_id = $profile->id;
- $vid->url = $url;
-
-
- $options['object_type'] = Video::OBJECT_TYPE;
-
- if (!array_key_exists('uri', $options)) {
- $options['uri'] = common_local_url('showvideo', array('id' => $vid->id));
- }
-
- if (!array_key_exists('rendered', $options)) {
- $options['rendered'] = sprintf("<video src=\"%s\">Sorry, your browser doesn't support the video tag.</video>", $url);
- }
-
- $vid->uri = $options['uri'];
-
- $vid->insert();
-
- return Notice::saveNew($profile->id,
- '',
- 'web',
- $options);
-
- }
-}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2011, Free Software Foundation, Inc.
+ *
+ * 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/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')){
+ exit(1);
+}
+
+class ShowvideoAction extends ShownoticeAction
+{
+ protected $id = null;
+ protected $vid = null;
+
+ function prepare($args)
+ {
+ OwnerDesignAction::prepare($args);
+ $this->id = $this->trimmed('id');
+ $this->vid = Video::getKV('id', $this->id);
+
+ if (empty($this->vid)) {
+ throw new ClientException(_('No such video.'), 404);
+ }
+
+ $this->notice = $this->vid->getNotice();
+
+ if (empty($this->notice)) {
+ throw new ClientException(_('No such video'), 404);
+ }
+
+ $this->user = User::getKV('id', $this->vid->profile_id);
+
+ if (empty($this->user)) {
+ throw new ClientException(_('No such user.'), 404);
+ }
+
+ $this->profile = $this->user->getProfile();
+
+ if (empty($this->profile)) {
+ throw new ServerException(_('User without a profile.'));
+ }
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2011, Free Software Foundation, Inc.
+ *
+ * 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/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')){
+ exit(1);
+}
+
+/**
+ * Data class for videos.
+ */
+
+class Video extends Managed_DataObject
+{
+ const OBJECT_TYPE = 'http://activitystrea.ms/schema/1.0/video';
+
+ public $__table = 'video'; // table name
+ public $id; // char (36) // UUID
+ public $uri; // varchar (255) // This is the corresponding notice's uri.
+ public $url; // varchar (255)
+ public $profile_id; // int
+
+ public static function getByNotice($notice)
+ {
+ return self::getKV('uri', $notice->uri);
+ }
+
+ public function getNotice()
+ {
+ return Notice::getKV('uri', $this->uri);
+ }
+
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'A video clip',
+ 'fields' => array(
+ 'id' => array('type' => 'char',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'UUID'),
+ 'uri' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'url' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'profile_id' => array('type' => 'int', 'not null' => true),
+ ),
+ 'primary key' => array('id'),
+ 'foreign keys' => array('video_profile_id__key' => array('profile' => array('profile_id' => 'id'))),
+ );
+ }
+
+ function saveNew($profile, $url, $options=array())
+ {
+ $vid = new Video();
+
+ $vid->id = UUID::gen();
+ $vid->profile_id = $profile->id;
+ $vid->url = $url;
+
+
+ $options['object_type'] = Video::OBJECT_TYPE;
+
+ if (!array_key_exists('uri', $options)) {
+ $options['uri'] = common_local_url('showvideo', array('id' => $vid->id));
+ }
+
+ if (!array_key_exists('rendered', $options)) {
+ $options['rendered'] = sprintf("<video src=\"%s\">Sorry, your browser doesn't support the video tag.</video>", $url);
+ }
+
+ $vid->uri = $options['uri'];
+
+ $vid->insert();
+
+ return Notice::saveNew($profile->id,
+ '',
+ 'web',
+ $options);
+
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2011, Free Software Foundation, Inc.
+ *
+ * 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/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')){
+ exit(1);
+}
+
+class VideoForm extends Form
+{
+ function id()
+ {
+ return "form_new_video";
+ }
+
+ function action()
+ {
+ return common_local_url('postvideo');
+ }
+
+ function formClass()
+ {
+ return 'form_settings ajax-notice';
+ }
+
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'new_video_data'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('url', _('URL'), null, _('URL of the video'));
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+
+ $toWidget = new ToSelector($this->out,
+ common_current_user(),
+ null);
+ $toWidget->show();
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ function formActions()
+ {
+ $this->out->submit('submit', _m('BUTTON', 'Save'));
+ }
+}
+++ /dev/null
-<?php
-/**
- * GNU Social
- * Copyright (C) 2011, Free Software Foundation, Inc.
- *
- * 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/>.
- *
- * @package GNU Social
- * @author Ian Denhardt <ian@zenhack.net>
- * @copyright 2011 Free Software Foundation, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- */
-
-if(!defined('STATUSNET')){
- exit(1);
-}
-
-class ShowvideoAction extends ShownoticeAction
-{
- protected $id = null;
- protected $vid = null;
-
- function prepare($args)
- {
- OwnerDesignAction::prepare($args);
- $this->id = $this->trimmed('id');
- $this->vid = Video::getKV('id', $this->id);
-
- if (empty($this->vid)) {
- throw new ClientException(_('No such video.'), 404);
- }
-
- $this->notice = $this->vid->getNotice();
-
- if (empty($this->notice)) {
- throw new ClientException(_('No such video'), 404);
- }
-
- $this->user = User::getKV('id', $this->vid->profile_id);
-
- if (empty($this->user)) {
- throw new ClientException(_('No such user.'), 404);
- }
-
- $this->profile = $this->user->getProfile();
-
- if (empty($this->profile)) {
- throw new ServerException(_('User without a profile.'));
- }
-
- return true;
- }
-}
+++ /dev/null
-<?php
-/**
- * GNU Social
- * Copyright (C) 2011, Free Software Foundation, Inc.
- *
- * 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/>.
- *
- * @package GNU Social
- * @author Ian Denhardt <ian@zenhack.net>
- * @copyright 2011 Free Software Foundation, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- */
-
-if(!defined('STATUSNET')){
- exit(1);
-}
-
-class VideoForm extends Form
-{
- function id()
- {
- return "form_new_video";
- }
-
- function action()
- {
- return common_local_url('postvideo');
- }
-
- function formClass()
- {
- return 'form_settings ajax-notice';
- }
-
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'new_video_data'));
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->out->input('url', _('URL'), null, _('URL of the video'));
- $this->unli();
-
- $this->out->elementEnd('ul');
-
- $toWidget = new ToSelector($this->out,
- common_current_user(),
- null);
- $toWidget->show();
-
- $this->out->elementEnd('fieldset');
- }
-
- function formActions()
- {
- $this->out->submit('submit', _m('BUTTON', 'Save'));
- }
-}
return true;
}
- /**
- * Automatically load the actions and libraries used by the plugin
- *
- * @param Class $cls the class
- *
- * @return boolean hook return
- *
- */
- function onAutoload($cls)
- {
- $base = dirname(__FILE__);
- $lower = strtolower($cls);
- switch ($lower) {
- case 'groupfavoritedaction':
- require_once "$base/$lower.php";
- return false;
- default:
- return true;
- }
- }
-
function onEndGroupGroupNav(GroupNav $nav)
{
$action_name = $nav->action->trimmed('action');
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List of popular notices
+ *
+ * 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 Public
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class GroupFavoritedAction extends ShowgroupAction
+{
+ /**
+ * Title of the page
+ *
+ * @return string page title, with page number
+ */
+ function title()
+ {
+ $base = $this->group->getFancyName();
+
+ if ($this->page == 1) {
+ // TRANS: %s is a group name.
+ return sprintf(_m('Popular posts in %s group'), $base);
+ } else {
+ // TRANS: %1$s is a group name, %2$s is a group number.
+ return sprintf(_m('Popular posts in %1$s group, page %2$d'),
+ $base,
+ $this->page);
+ }
+ }
+
+ /**
+ * Content area
+ *
+ * Shows the list of popular notices
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $groupId = intval($this->group->id);
+ $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
+ $cutoff = sprintf("fave.modified > '%s'",
+ common_sql_date(time() - common_config('popular', 'cutoff')));
+
+ $qry = 'SELECT notice.*, '.
+ $weightexpr . ' as weight ' .
+ 'FROM notice ' .
+ "JOIN group_inbox ON notice.id = group_inbox.notice_id " .
+ 'JOIN fave ON notice.id = fave.notice_id ' .
+ "WHERE $cutoff AND group_id = $groupId " .
+ 'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' .
+ 'ORDER BY weight DESC';
+
+ $offset = ($this->page - 1) * NOTICES_PER_PAGE;
+ $limit = NOTICES_PER_PAGE + 1;
+
+ if (common_config('db', 'type') == 'pgsql') {
+ $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
+ } else {
+ $qry .= ' LIMIT ' . $offset . ', ' . $limit;
+ }
+
+ $notice = Memcached_DataObject::cachedQuery('Notice',
+ $qry,
+ 600);
+
+ $nl = new NoticeList($notice, $this);
+
+ $cnt = $nl->show();
+
+ if ($cnt == 0) {
+ //$this->showEmptyList();
+ }
+
+ $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
+ $this->page, 'groupfavorited',
+ array('nickname' => $this->group->nickname));
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * List of popular notices
- *
- * 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 Public
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-class GroupFavoritedAction extends ShowgroupAction
-{
- /**
- * Title of the page
- *
- * @return string page title, with page number
- */
- function title()
- {
- $base = $this->group->getFancyName();
-
- if ($this->page == 1) {
- // TRANS: %s is a group name.
- return sprintf(_m('Popular posts in %s group'), $base);
- } else {
- // TRANS: %1$s is a group name, %2$s is a group number.
- return sprintf(_m('Popular posts in %1$s group, page %2$d'),
- $base,
- $this->page);
- }
- }
-
- /**
- * Content area
- *
- * Shows the list of popular notices
- *
- * @return void
- */
- function showContent()
- {
- $groupId = intval($this->group->id);
- $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
- $cutoff = sprintf("fave.modified > '%s'",
- common_sql_date(time() - common_config('popular', 'cutoff')));
-
- $qry = 'SELECT notice.*, '.
- $weightexpr . ' as weight ' .
- 'FROM notice ' .
- "JOIN group_inbox ON notice.id = group_inbox.notice_id " .
- 'JOIN fave ON notice.id = fave.notice_id ' .
- "WHERE $cutoff AND group_id = $groupId " .
- 'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' .
- 'ORDER BY weight DESC';
-
- $offset = ($this->page - 1) * NOTICES_PER_PAGE;
- $limit = NOTICES_PER_PAGE + 1;
-
- if (common_config('db', 'type') == 'pgsql') {
- $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
- } else {
- $qry .= ' LIMIT ' . $offset . ', ' . $limit;
- }
-
- $notice = Memcached_DataObject::cachedQuery('Notice',
- $qry,
- 600);
-
- $nl = new NoticeList($notice, $this);
-
- $cnt = $nl->show();
-
- if ($cnt == 0) {
- //$this->showEmptyList();
- }
-
- $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
- $this->page, 'groupfavorited',
- array('nickname' => $this->group->nickname));
- }
-}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'GroupinboxAction':
- case 'ShowgroupmessageAction':
- case 'NewgroupmessageAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'Group_privacy_settings':
- case 'Group_message':
- case 'Group_message_profile':
- include_once $dir . '/'.$cls.'.php';
- return false;
- case 'GroupMessageCommand':
- case 'GroupMessageList':
- case 'GroupMessageListItem':
- case 'GroupMessageForm':
- include_once $dir . '/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Map URLs to actions
*
+++ /dev/null
-<?php
-/**
- * Data class for group direct messages
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for group direct messages
- *
- * @category GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Group_message extends Managed_DataObject
-{
- public $__table = 'group_message'; // table name
- public $id; // char(36) primary_key not_null
- public $uri; // varchar(255)
- public $from_profile; // int
- public $to_group; // int
- public $content;
- public $rendered;
- public $url;
- public $created; // datetime() not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'id' => array('type' => 'char', 'not null' => true, 'length' => 36, 'description' => 'message uuid'),
- 'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'message uri'),
- 'url' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'representation url'),
- 'from_profile' => array('type' => 'int', 'not null' => true, 'description' => 'sending profile ID'),
- 'to_group' => array('type' => 'int', 'not null' => true, 'description' => 'receiving group ID'),
- 'content' => array('type' => 'text', 'not null' => true, 'description' => 'message content'),
- 'rendered' => array('type' => 'text', 'not null' => true, 'description' => 'rendered message'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('id'),
- 'unique keys' => array(
- 'group_message_uri_key' => array('uri'),
- ),
- 'foreign keys' => array(
- 'group_message_from_profile_fkey' => array('profile', array('from_profile' => 'id')),
- 'group_message_to_group_fkey' => array('user_group', array('to_group' => 'id')),
- ),
- 'indexes' => array(
- 'group_message_from_profile_idx' => array('from_profile'),
- 'group_message_to_group_idx' => array('to_group'),
- 'group_message_url_idx' => array('url'),
- ),
- );
- }
-
- static function send($user, $group, $text)
- {
- if (!$user->hasRight(Right::NEWMESSAGE)) {
- // XXX: maybe break this out into a separate right
- // TRANS: Exception thrown when trying to send group private message without having the right to do that.
- // TRANS: %s is a user nickname.
- throw new Exception(sprintf(_m('User %s is not allowed to send private messages.'),
- $user->nickname));
- }
-
- Group_privacy_settings::ensurePost($user, $group);
-
- $text = $user->shortenLinks($text);
-
- // We use the same limits as for 'regular' private messages.
-
- if (Message::contentTooLong($text)) {
- // TRANS: Exception thrown when trying to send group private message that is too long.
- // TRANS: %d is the maximum meggage length.
- throw new Exception(sprintf(_m('That\'s too long. Maximum message size is %d character.',
- 'That\'s too long. Maximum message size is %d characters.',
- Message::maxContent()),
- Message::maxContent()));
- }
-
- // Valid! Let's do this thing!
-
- $gm = new Group_message();
-
- $gm->id = UUID::gen();
- $gm->uri = common_local_url('showgroupmessage', array('id' => $gm->id));
- $gm->from_profile = $user->id;
- $gm->to_group = $group->id;
- $gm->content = $text; // XXX: is this cool?!
- $gm->rendered = common_render_text($text);
- $gm->url = $gm->uri;
- $gm->created = common_sql_now();
-
- // This throws a conniption if there's a problem
-
- $gm->insert();
-
- $gm->distribute();
-
- return $gm;
- }
-
- function distribute()
- {
- $group = User_group::getKV('id', $this->to_group);
-
- $member = $group->getMembers();
-
- while ($member->fetch()) {
- Group_message_profile::send($this, $member);
- }
- }
-
- function getGroup()
- {
- $group = User_group::getKV('id', $this->to_group);
- if (empty($group)) {
- // TRANS: Exception thrown when trying to send group private message to a non-existing group.
- throw new ServerException(_m('No group for group message.'));
- }
- return $group;
- }
-
- function getSender()
- {
- $sender = Profile::getKV('id', $this->from_profile);
- if (empty($sender)) {
- // TRANS: Exception thrown when trying to send group private message without having a sender.
- throw new ServerException(_m('No sender for group message.'));
- }
- return $sender;
- }
-
- static function forGroup($group, $offset, $limit)
- {
- // XXX: cache
- $gm = new Group_message();
-
- $gm->to_group = $group->id;
- $gm->orderBy('created DESC');
- $gm->limit($offset, $limit);
-
- $gm->find();
-
- return $gm;
- }
-}
+++ /dev/null
-<?php
-/**
- * Who received a group message
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for group direct messages for users
- *
- * @category GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Group_message_profile extends Managed_DataObject
-{
- public $__table = 'group_message_profile'; // table name
- public $to_profile; // int
- public $group_message_id; // varchar(36) primary_key not_null
- public $created; // datetime() not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'to_profile' => array('type' => 'int', 'not null' => true, 'description' => 'id of group direct message'),
- 'group_message_id' => array('type' => 'char', 'not null' => true, 'length' => 36, 'description' => 'related group message uuid'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('to_profile', 'group_message_id'),
- 'foreign keys' => array(
- 'group_message_profile_to_profile_fkey' => array('profile', array('to_profile' => 'id')),
- 'group_message_profile_group_message_id_fkey' => array('group_message', array('group_message_id' => 'id')),
- ),
- );
- }
-
- function send($gm, $profile)
- {
- $gmp = new Group_message_profile();
-
- $gmp->group_message_id = $gm->id;
- $gmp->to_profile = $profile->id;
- $gmp->created = common_sql_now();
-
- $gmp->insert();
-
- // If it's not for the author, send email notification
- if ($gm->from_profile != $profile->id) {
- $gmp->notify();
- }
-
- return $gmp;
- }
-
- function notify()
- {
- // XXX: add more here
- $this->notifyByMail();
- }
-
- function notifyByMail()
- {
- $to = User::getKV('id', $this->to_profile);
-
- if (empty($to) || is_null($to->email) || !$to->emailnotifymsg) {
- return true;
- }
-
- $gm = Group_message::getKV('id', $this->group_message_id);
-
- $from_profile = Profile::getKV('id', $gm->from_profile);
-
- $group = $gm->getGroup();
-
- common_switch_locale($to->language);
-
- // TRANS: Subject for direct-message notification email.
- // TRANS: %1$s is the sending user's nickname, %2$s is the group nickname.
- $subject = sprintf(_m('New private message from %1$s to group %2$s'), $from_profile->nickname, $group->nickname);
-
- // TRANS: Body for direct-message notification email.
- // TRANS: %1$s is the sending user's long name, %2$s is the sending user's nickname,
- // TRANS: %3$s is the message content, %4$s a URL to the message,
- // TRANS: %5$s is the StatusNet sitename.
- $body = sprintf(_m("%1\$s (%2\$s) sent a private message to group %3\$s:\n\n".
- "------------------------------------------------------\n".
- "%4\$s\n".
- "------------------------------------------------------\n\n".
- "You can reply to their message here:\n\n".
- "%5\$s\n\n".
- "Do not reply to this email; it will not get to them.\n\n".
- "With kind regards,\n".
- "%6\$s"),
- $from_profile->getBestName(),
- $from_profile->nickname,
- $group->nickname,
- $gm->content,
- common_local_url('newmessage', array('to' => $from_profile->id)),
- common_config('site', 'name')) . "\n";
-
- $headers = _mail_prepare_headers('message', $to->nickname, $from_profile->nickname);
-
- common_switch_locale();
-
- return mail_to_user($to, $subject, $body, $headers);
- }
-}
+++ /dev/null
-<?php
-/**
- * Data class for group privacy settings
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Data class for group privacy
- *
- * Stores admin preferences about the group.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Group_privacy_settings extends Managed_DataObject
-{
- public $__table = 'group_privacy_settings';
- /** ID of the group. */
- public $group_id;
- /** When to allow privacy: always, sometimes, or never. */
- public $allow_privacy;
- /** Who can send private messages: everyone, member, admin */
- public $allow_sender;
- /** row creation timestamp */
- public $created;
- /** Last-modified timestamp */
- public $modified;
-
- /** NEVER is */
-
- const SOMETIMES = -1;
- const NEVER = 0;
- const ALWAYS = 1;
-
- /** These are bit-mappy, as a hedge against the future. */
-
- const EVERYONE = 1;
- const MEMBER = 2;
- const ADMIN = 4;
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'group_id' => array('type' => 'int', 'not null' => true, 'description' => 'group_privacy_settings'),
- 'allow_privacy' => array('type' => 'int', 'not null' => true, 'description' => 'sometimes=-1, never=0, always=1'),
- 'allow_sender' => array('type' => 'int', 'not null' => true, 'description' => 'list of bit-mappy values in source code'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('group_id'),
- 'foreign keys' => array(
- 'group_privacy_settings_group_id_fkey' => array('user_group', array('group_id' => 'id')),
- ),
- );
- }
-
- function forGroup($group)
- {
- $gps = Group_privacy_settings::getKV('group_id', $group->id);
-
- if (empty($gps)) {
- // make a fake one with defaults
- $gps = new Group_privacy_settings();
- $gps->allow_privacy = Group_privacy_settings::SOMETIMES;
- $gps->allow_sender = Group_privacy_settings::MEMBER;
- }
-
- return $gps;
- }
-
- function ensurePost($user, $group)
- {
- $gps = self::forGroup($group);
-
- if ($gps->allow_privacy == Group_privacy_settings::NEVER) {
- // TRANS: Exception thrown when trying to set group privacy setting if group %s does not allow private messages.
- throw new Exception(sprintf(_m('Group %s does not allow private messages.'),
- $group->nickname));
- }
-
- switch ($gps->allow_sender) {
- case Group_privacy_settings::EVERYONE:
- $profile = $user->getProfile();
- if (Group_block::isBlocked($group, $profile)) {
- // TRANS: Exception thrown when trying to send group private message while blocked from that group.
- // TRANS: %1$s is a user nickname, %2$s is a group nickname.
- throw new Exception(sprintf(_m('User %1$s is blocked from group %2$s.'),
- $user->nickname,
- $group->nickname));
- }
- break;
- case Group_privacy_settings::MEMBER:
- if (!$user->isMember($group)) {
- // TRANS: Exception thrown when trying to send group private message while not a member.
- // TRANS: %1$s is a user nickname, %2$s is a group nickname.
- throw new Exception(sprintf(_m('User %1$s is not a member of group %2$s.'),
- $user->nickname,
- $group->nickname));
- }
- break;
- case Group_privacy_settings::ADMIN:
- if (!$user->isAdmin($group)) {
- // TRANS: Exception thrown when trying to send group private message while not a group administrator.
- // TRANS: %1$s is a user nickname, %2$s is a group nickname.
- throw new Exception(sprintf(_m('User %1$s is not an administrator of group %2$s.'),
- $user->nickname,
- $group->nickname));
- }
- break;
- default:
- // TRANS: Exception thrown when encountering undefined group privacy settings.
- // TRANS: %s is a group nickname.
- throw new Exception(sprintf(_m('Unknown privacy settings for group %s.'),
- $group->nickname));
- }
-
- return true;
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * List of private messages to this group
+ *
+ * PHP version 5
+ *
+ * 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 GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Show a list of private messages to this group
+ *
+ * @category GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class GroupinboxAction extends GroupAction
+{
+ var $gm;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $cur = common_current_user();
+
+ if (empty($cur)) {
+ // TRANS: Client exception thrown when trying to view group inbox while not logged in.
+ throw new ClientException(_m('Only for logged-in users.'), 403);
+ }
+
+ $nicknameArg = $this->trimmed('nickname');
+
+ $nickname = common_canonical_nickname($nicknameArg);
+
+ if ($nickname != $nicknameArg) {
+ $url = common_local_url('groupinbox', array('nickname' => $nickname));
+ common_redirect($url);
+ return false;
+ }
+
+ $localGroup = Local_group::getKV('nickname', $nickname);
+
+ if (empty($localGroup)) {
+ // TRANS: Client exception thrown when trying to view group inbox for non-existing group.
+ throw new ClientException(_m('No such group.'), 404);
+ }
+
+ $this->group = User_group::getKV('id', $localGroup->group_id);
+
+ if (empty($this->group)) {
+ // TRANS: Client exception thrown when trying to view group inbox for non-existing group.
+ throw new ClientException(_m('No such group.'), 404);
+ }
+
+ if (!$cur->isMember($this->group)) {
+ // TRANS: Client exception thrown when trying to view group inbox while not a member.
+ throw new ClientException(_m('Only for members.'), 403);
+ }
+
+ $this->page = $this->trimmed('page');
+
+ if (!$this->page) {
+ $this->page = 1;
+ }
+
+ $this->gm = Group_message::forGroup($this->group,
+ ($this->page - 1) * MESSAGES_PER_PAGE,
+ MESSAGES_PER_PAGE + 1);
+ return true;
+ }
+
+ function showLocalNav()
+ {
+ $nav = new GroupNav($this, $this->group);
+ $nav->show();
+ }
+
+ function showNoticeForm()
+ {
+ $form = new GroupMessageForm($this, $this->group);
+ $form->show();
+ }
+
+ function showContent()
+ {
+ $gml = new GroupMessageList($this, $this->gm);
+ $cnt = $gml->show();
+
+ if ($cnt == 0) {
+ // TRANS: Text of group inbox if no private messages were sent to it.
+ $this->element('p', 'guide', _m('This group has not received any private messages.'));
+ }
+ $this->pagination($this->page > 1,
+ $cnt > MESSAGES_PER_PAGE,
+ $this->page,
+ 'groupinbox',
+ array('nickname' => $this->group->nickname));
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ $this->showPage();
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * Title of the page
+ *
+ * @return string page title, with page number
+ */
+ function title()
+ {
+ $base = $this->group->getFancyName();
+
+ if ($this->page == 1) {
+ // TRANS: Title of inbox for group %s.
+ return sprintf(_m('%s group inbox'), $base);
+ } else {
+ // TRANS: Page title for any but first group page.
+ // TRANS: %1$s is a group name, $2$s is a page number.
+ return sprintf(_m('%1$s group inbox, page %2$d'),
+ $base,
+ $this->page);
+ }
+ }
+
+ /**
+ * Show the page notice
+ *
+ * Shows instructions for the page
+ *
+ * @return void
+ */
+ function showPageNotice()
+ {
+ $instr = $this->getInstructions();
+ $output = common_markup_to_html($instr);
+
+ $this->elementStart('div', 'instructions');
+ $this->raw($output);
+ $this->elementEnd('div');
+ }
+
+ /**
+ * Instructions for using this page
+ *
+ * @return string localised instructions for using the page
+ */
+ function getInstructions()
+ {
+ // TRANS: Instructions for user inbox page.
+ return _m('This is the group inbox, which lists all incoming private messages for this group.');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Action for adding a new group message
+ *
+ * PHP version 5
+ *
+ * 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 Cache
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Action for adding a new group message
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class NewgroupmessageAction extends Action
+{
+ var $group;
+ var $user;
+ var $text;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown when trying to send a private group message while not logged in.
+ throw new ClientException(_m('Must be logged in.'), 403);
+ }
+
+ if (!$this->user->hasRight(Right::NEWMESSAGE)) {
+ // TRANS: Exception thrown when user %s is not allowed to send a private group message.
+ throw new Exception(sprintf(_m('User %s is not allowed to send private messages.'),
+ $this->user->nickname));
+ }
+
+ $nicknameArg = $this->trimmed('nickname');
+
+ $nickname = common_canonical_nickname($nicknameArg);
+
+ if ($nickname != $nicknameArg) {
+ $url = common_local_url('newgroupmessage', array('nickname' => $nickname));
+ common_redirect($url, 301);
+ return false;
+ }
+
+ $localGroup = Local_group::getKV('nickname', $nickname);
+
+ if (empty($localGroup)) {
+ // TRANS: Client exception thrown when trying to send a private group message to a non-existing group.
+ throw new ClientException(_m('No such group.'), 404);
+ }
+
+ $this->group = User_group::getKV('id', $localGroup->group_id);
+
+ if (empty($this->group)) {
+ // TRANS: Client exception thrown when trying to send a private group message to a non-existing group.
+ throw new ClientException(_m('No such group.'), 404);
+ }
+
+ // This throws an exception on error
+ Group_privacy_settings::ensurePost($this->user, $this->group);
+
+ // If we're posted to, check session token and get text
+ if ($this->isPost()) {
+ $this->checkSessionToken();
+ $this->text = $this->trimmed('content');
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ if ($this->isPost()) {
+ $this->sendNewMessage();
+ } else {
+ $this->showPage();
+ }
+ }
+
+ function showNoticeForm()
+ {
+ $form = new GroupMessageForm($this, $this->group);
+ $form->show();
+ }
+
+ function sendNewMessage()
+ {
+ $gm = Group_message::send($this->user, $this->group, $this->text);
+
+ if ($this->boolean('ajax')) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Title after sending a private group message.
+ $this->element('title', null, _m('Message sent'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->element('p',
+ array('id' => 'command_result'),
+ // TRANS: Succes text after sending a direct message to group %s.
+ sprintf(_m('Direct message to %s sent.'),
+ $this->group->nickname));
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect($gm->url, 303);
+ }
+ }
+
+ function title()
+ {
+ // TRANS: Title of form for new private group message.
+ return sprintf(_m('New message to group %s'), $this->group->nickname);
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Show a single group message
+ *
+ * PHP version 5
+ *
+ * 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 GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Show a single private group message
+ *
+ * @category GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ShowgroupmessageAction extends Action
+{
+ var $gm;
+ var $group;
+ var $sender;
+ var $user;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown when trying to view group private messages without being logged in.
+ throw new ClientException(_m('Only logged-in users can view private messages.'),
+ 403);
+ }
+
+ $id = $this->trimmed('id');
+
+ $this->gm = Group_message::getKV('id', $id);
+
+ if (empty($this->gm)) {
+ // TRANS: Client exception thrown when trying to view a non-existing group private message.
+ throw new ClientException(_m('No such message.'), 404);
+ }
+
+ $this->group = User_group::getKV('id', $this->gm->to_group);
+
+ if (empty($this->group)) {
+ // TRANS: Server exception thrown when trying to view group private messages for a non-exsting group.
+ throw new ServerException(_m('Group not found.'));
+ }
+
+ if (!$this->user->isMember($this->group)) {
+ // TRANS: Client exception thrown when trying to view a group private message without being a group member.
+ throw new ClientException(_m('Cannot read message.'), 403);
+ }
+
+ $this->sender = Profile::getKV('id', $this->gm->from_profile);
+
+ if (empty($this->sender)) {
+ // TRANS: Server exception thrown when trying to view a group private message without a sender.
+ throw new ServerException(_m('No sender found.'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ $this->showPage();
+ }
+
+ /**
+ * Title of the page
+ */
+ function title()
+ {
+ // TRANS: Title for private group message.
+ // TRANS: %1$s is the sender name, %2$s is the group name, %3$s is a timestamp.
+ return sprintf(_m('Message from %1$s to group %2$s on %3$s'),
+ $this->sender->nickname,
+ $this->group->nickname,
+ common_exact_date($this->gm->created));
+ }
+
+ /**
+ * Show the content area.
+ */
+ function showContent()
+ {
+ $this->elementStart('ul', 'notices messages');
+ $gmli = new GroupMessageListItem($this, $this->gm);
+ $gmli->show();
+ $this->elementEnd('ul');
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * Return last modified, if applicable.
+ *
+ * MAY override
+ *
+ * @return string last modified http header
+ */
+ function lastModified()
+ {
+ return max(strtotime($this->group->modified),
+ strtotime($this->sender->modified),
+ strtotime($this->gm->modified));
+ }
+
+ /**
+ * Return etag, if applicable.
+ *
+ * MAY override
+ *
+ * @return string etag http header
+ */
+ function etag()
+ {
+ $avatar = $this->sender->getAvatar(AVATAR_STREAM_SIZE);
+
+ $avtime = ($avatar) ? strtotime($avatar->modified) : 0;
+
+ return 'W/"' . implode(':', array($this->arg('action'),
+ common_user_cache_hash(),
+ common_language(),
+ $this->gm->id,
+ strtotime($this->sender->modified),
+ strtotime($this->group->modified),
+ $avtime)) . '"';
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class for group direct messages
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for group direct messages
+ *
+ * @category GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Group_message extends Managed_DataObject
+{
+ public $__table = 'group_message'; // table name
+ public $id; // char(36) primary_key not_null
+ public $uri; // varchar(255)
+ public $from_profile; // int
+ public $to_group; // int
+ public $content;
+ public $rendered;
+ public $url;
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'id' => array('type' => 'char', 'not null' => true, 'length' => 36, 'description' => 'message uuid'),
+ 'uri' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'message uri'),
+ 'url' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'representation url'),
+ 'from_profile' => array('type' => 'int', 'not null' => true, 'description' => 'sending profile ID'),
+ 'to_group' => array('type' => 'int', 'not null' => true, 'description' => 'receiving group ID'),
+ 'content' => array('type' => 'text', 'not null' => true, 'description' => 'message content'),
+ 'rendered' => array('type' => 'text', 'not null' => true, 'description' => 'rendered message'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('id'),
+ 'unique keys' => array(
+ 'group_message_uri_key' => array('uri'),
+ ),
+ 'foreign keys' => array(
+ 'group_message_from_profile_fkey' => array('profile', array('from_profile' => 'id')),
+ 'group_message_to_group_fkey' => array('user_group', array('to_group' => 'id')),
+ ),
+ 'indexes' => array(
+ 'group_message_from_profile_idx' => array('from_profile'),
+ 'group_message_to_group_idx' => array('to_group'),
+ 'group_message_url_idx' => array('url'),
+ ),
+ );
+ }
+
+ static function send($user, $group, $text)
+ {
+ if (!$user->hasRight(Right::NEWMESSAGE)) {
+ // XXX: maybe break this out into a separate right
+ // TRANS: Exception thrown when trying to send group private message without having the right to do that.
+ // TRANS: %s is a user nickname.
+ throw new Exception(sprintf(_m('User %s is not allowed to send private messages.'),
+ $user->nickname));
+ }
+
+ Group_privacy_settings::ensurePost($user, $group);
+
+ $text = $user->shortenLinks($text);
+
+ // We use the same limits as for 'regular' private messages.
+
+ if (Message::contentTooLong($text)) {
+ // TRANS: Exception thrown when trying to send group private message that is too long.
+ // TRANS: %d is the maximum meggage length.
+ throw new Exception(sprintf(_m('That\'s too long. Maximum message size is %d character.',
+ 'That\'s too long. Maximum message size is %d characters.',
+ Message::maxContent()),
+ Message::maxContent()));
+ }
+
+ // Valid! Let's do this thing!
+
+ $gm = new Group_message();
+
+ $gm->id = UUID::gen();
+ $gm->uri = common_local_url('showgroupmessage', array('id' => $gm->id));
+ $gm->from_profile = $user->id;
+ $gm->to_group = $group->id;
+ $gm->content = $text; // XXX: is this cool?!
+ $gm->rendered = common_render_text($text);
+ $gm->url = $gm->uri;
+ $gm->created = common_sql_now();
+
+ // This throws a conniption if there's a problem
+
+ $gm->insert();
+
+ $gm->distribute();
+
+ return $gm;
+ }
+
+ function distribute()
+ {
+ $group = User_group::getKV('id', $this->to_group);
+
+ $member = $group->getMembers();
+
+ while ($member->fetch()) {
+ Group_message_profile::send($this, $member);
+ }
+ }
+
+ function getGroup()
+ {
+ $group = User_group::getKV('id', $this->to_group);
+ if (empty($group)) {
+ // TRANS: Exception thrown when trying to send group private message to a non-existing group.
+ throw new ServerException(_m('No group for group message.'));
+ }
+ return $group;
+ }
+
+ function getSender()
+ {
+ $sender = Profile::getKV('id', $this->from_profile);
+ if (empty($sender)) {
+ // TRANS: Exception thrown when trying to send group private message without having a sender.
+ throw new ServerException(_m('No sender for group message.'));
+ }
+ return $sender;
+ }
+
+ static function forGroup($group, $offset, $limit)
+ {
+ // XXX: cache
+ $gm = new Group_message();
+
+ $gm->to_group = $group->id;
+ $gm->orderBy('created DESC');
+ $gm->limit($offset, $limit);
+
+ $gm->find();
+
+ return $gm;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Who received a group message
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for group direct messages for users
+ *
+ * @category GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Group_message_profile extends Managed_DataObject
+{
+ public $__table = 'group_message_profile'; // table name
+ public $to_profile; // int
+ public $group_message_id; // varchar(36) primary_key not_null
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'to_profile' => array('type' => 'int', 'not null' => true, 'description' => 'id of group direct message'),
+ 'group_message_id' => array('type' => 'char', 'not null' => true, 'length' => 36, 'description' => 'related group message uuid'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('to_profile', 'group_message_id'),
+ 'foreign keys' => array(
+ 'group_message_profile_to_profile_fkey' => array('profile', array('to_profile' => 'id')),
+ 'group_message_profile_group_message_id_fkey' => array('group_message', array('group_message_id' => 'id')),
+ ),
+ );
+ }
+
+ function send($gm, $profile)
+ {
+ $gmp = new Group_message_profile();
+
+ $gmp->group_message_id = $gm->id;
+ $gmp->to_profile = $profile->id;
+ $gmp->created = common_sql_now();
+
+ $gmp->insert();
+
+ // If it's not for the author, send email notification
+ if ($gm->from_profile != $profile->id) {
+ $gmp->notify();
+ }
+
+ return $gmp;
+ }
+
+ function notify()
+ {
+ // XXX: add more here
+ $this->notifyByMail();
+ }
+
+ function notifyByMail()
+ {
+ $to = User::getKV('id', $this->to_profile);
+
+ if (empty($to) || is_null($to->email) || !$to->emailnotifymsg) {
+ return true;
+ }
+
+ $gm = Group_message::getKV('id', $this->group_message_id);
+
+ $from_profile = Profile::getKV('id', $gm->from_profile);
+
+ $group = $gm->getGroup();
+
+ common_switch_locale($to->language);
+
+ // TRANS: Subject for direct-message notification email.
+ // TRANS: %1$s is the sending user's nickname, %2$s is the group nickname.
+ $subject = sprintf(_m('New private message from %1$s to group %2$s'), $from_profile->nickname, $group->nickname);
+
+ // TRANS: Body for direct-message notification email.
+ // TRANS: %1$s is the sending user's long name, %2$s is the sending user's nickname,
+ // TRANS: %3$s is the message content, %4$s a URL to the message,
+ // TRANS: %5$s is the StatusNet sitename.
+ $body = sprintf(_m("%1\$s (%2\$s) sent a private message to group %3\$s:\n\n".
+ "------------------------------------------------------\n".
+ "%4\$s\n".
+ "------------------------------------------------------\n\n".
+ "You can reply to their message here:\n\n".
+ "%5\$s\n\n".
+ "Do not reply to this email; it will not get to them.\n\n".
+ "With kind regards,\n".
+ "%6\$s"),
+ $from_profile->getBestName(),
+ $from_profile->nickname,
+ $group->nickname,
+ $gm->content,
+ common_local_url('newmessage', array('to' => $from_profile->id)),
+ common_config('site', 'name')) . "\n";
+
+ $headers = _mail_prepare_headers('message', $to->nickname, $from_profile->nickname);
+
+ common_switch_locale();
+
+ return mail_to_user($to, $subject, $body, $headers);
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class for group privacy settings
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Data class for group privacy
+ *
+ * Stores admin preferences about the group.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Group_privacy_settings extends Managed_DataObject
+{
+ public $__table = 'group_privacy_settings';
+ /** ID of the group. */
+ public $group_id;
+ /** When to allow privacy: always, sometimes, or never. */
+ public $allow_privacy;
+ /** Who can send private messages: everyone, member, admin */
+ public $allow_sender;
+ /** row creation timestamp */
+ public $created;
+ /** Last-modified timestamp */
+ public $modified;
+
+ /** NEVER is */
+
+ const SOMETIMES = -1;
+ const NEVER = 0;
+ const ALWAYS = 1;
+
+ /** These are bit-mappy, as a hedge against the future. */
+
+ const EVERYONE = 1;
+ const MEMBER = 2;
+ const ADMIN = 4;
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'group_id' => array('type' => 'int', 'not null' => true, 'description' => 'group_privacy_settings'),
+ 'allow_privacy' => array('type' => 'int', 'not null' => true, 'description' => 'sometimes=-1, never=0, always=1'),
+ 'allow_sender' => array('type' => 'int', 'not null' => true, 'description' => 'list of bit-mappy values in source code'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('group_id'),
+ 'foreign keys' => array(
+ 'group_privacy_settings_group_id_fkey' => array('user_group', array('group_id' => 'id')),
+ ),
+ );
+ }
+
+ function forGroup($group)
+ {
+ $gps = Group_privacy_settings::getKV('group_id', $group->id);
+
+ if (empty($gps)) {
+ // make a fake one with defaults
+ $gps = new Group_privacy_settings();
+ $gps->allow_privacy = Group_privacy_settings::SOMETIMES;
+ $gps->allow_sender = Group_privacy_settings::MEMBER;
+ }
+
+ return $gps;
+ }
+
+ function ensurePost($user, $group)
+ {
+ $gps = self::forGroup($group);
+
+ if ($gps->allow_privacy == Group_privacy_settings::NEVER) {
+ // TRANS: Exception thrown when trying to set group privacy setting if group %s does not allow private messages.
+ throw new Exception(sprintf(_m('Group %s does not allow private messages.'),
+ $group->nickname));
+ }
+
+ switch ($gps->allow_sender) {
+ case Group_privacy_settings::EVERYONE:
+ $profile = $user->getProfile();
+ if (Group_block::isBlocked($group, $profile)) {
+ // TRANS: Exception thrown when trying to send group private message while blocked from that group.
+ // TRANS: %1$s is a user nickname, %2$s is a group nickname.
+ throw new Exception(sprintf(_m('User %1$s is blocked from group %2$s.'),
+ $user->nickname,
+ $group->nickname));
+ }
+ break;
+ case Group_privacy_settings::MEMBER:
+ if (!$user->isMember($group)) {
+ // TRANS: Exception thrown when trying to send group private message while not a member.
+ // TRANS: %1$s is a user nickname, %2$s is a group nickname.
+ throw new Exception(sprintf(_m('User %1$s is not a member of group %2$s.'),
+ $user->nickname,
+ $group->nickname));
+ }
+ break;
+ case Group_privacy_settings::ADMIN:
+ if (!$user->isAdmin($group)) {
+ // TRANS: Exception thrown when trying to send group private message while not a group administrator.
+ // TRANS: %1$s is a user nickname, %2$s is a group nickname.
+ throw new Exception(sprintf(_m('User %1$s is not an administrator of group %2$s.'),
+ $user->nickname,
+ $group->nickname));
+ }
+ break;
+ default:
+ // TRANS: Exception thrown when encountering undefined group privacy settings.
+ // TRANS: %s is a group nickname.
+ throw new Exception(sprintf(_m('Unknown privacy settings for group %s.'),
+ $group->nickname));
+ }
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for posting a group message
+ *
+ * PHP version 5
+ *
+ * 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 GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form for posting a group message
+ *
+ * @category GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class GroupMessageForm extends Form
+{
+ var $group;
+ var $content;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out Output context
+ * @param User_group $group Group to post to
+ *
+ * @todo add a drop-down list to post to any group
+ */
+ function __construct($out, $group, $content=null)
+ {
+ parent::__construct($out);
+
+ $this->group = $group;
+ $this->content = $content;
+ }
+
+ /**
+ * Action for the form
+ */
+ function action()
+ {
+ return common_local_url('newgroupmessage',
+ array('nickname' => $this->group->nickname));
+ }
+
+ /**
+ * Legend for the form
+ *
+ * @param
+ *
+ * @return
+ */
+ function formLegend()
+ {
+ $this->out->element('legend',
+ null,
+ // TRANS: Form legend for sending private message to group %s.
+ sprintf(_m('Message to %s'), $this->group->nickname));
+ }
+
+ /**
+ * id for the form
+ *
+ * @param
+ *
+ * @return
+ */
+ function id()
+ {
+ return 'form_notice-group-message';
+ }
+
+ /**
+ * class for the form
+ *
+ * @param
+ *
+ * @return
+ */
+ function formClass()
+ {
+ return 'form_notice';
+ }
+
+ /**
+ * Entry data
+ *
+ * @param
+ *
+ * @return
+ */
+ function formData()
+ {
+ $this->out->element('label', array('for' => 'notice_data-text',
+ 'id' => 'notice_data-text-label'),
+ // TRANS: Field label for private group message to group %s.
+ sprintf(_m('Direct message to %s'), $this->group->nickname));
+
+ $this->out->element('textarea', array('id' => 'notice_data-text',
+ 'cols' => 35,
+ 'rows' => 4,
+ 'name' => 'content'),
+ ($this->content) ? $this->content : '');
+
+ $contentLimit = Message::maxContent();
+
+ if ($contentLimit > 0) {
+ $this->out->elementStart('dl', 'form_note');
+ // TRANS: Indicator for number of chatacters still available for notice.
+ $this->out->element('dt', null, _m('Available characters'));
+ $this->out->element('dd', array('class' => 'count'),
+ $contentLimit);
+ $this->out->elementEnd('dl');
+ }
+ }
+
+ /**
+ * Legend for the form
+ *
+ * @param
+ *
+ * @return
+ */
+ function formActions()
+ {
+ $this->out->element('input', array('id' => 'notice_action-submit',
+ 'class' => 'submit',
+ 'name' => 'message_send',
+ 'type' => 'submit',
+ // TRANS: Send button text for sending private group notice.
+ 'value' => _m('Send button for sending notice', 'Send')));
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * List of private messages to this group
- *
- * PHP version 5
- *
- * 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 GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Show a list of private messages to this group
- *
- * @category GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class GroupinboxAction extends GroupAction
-{
- var $gm;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- $cur = common_current_user();
-
- if (empty($cur)) {
- // TRANS: Client exception thrown when trying to view group inbox while not logged in.
- throw new ClientException(_m('Only for logged-in users.'), 403);
- }
-
- $nicknameArg = $this->trimmed('nickname');
-
- $nickname = common_canonical_nickname($nicknameArg);
-
- if ($nickname != $nicknameArg) {
- $url = common_local_url('groupinbox', array('nickname' => $nickname));
- common_redirect($url);
- return false;
- }
-
- $localGroup = Local_group::getKV('nickname', $nickname);
-
- if (empty($localGroup)) {
- // TRANS: Client exception thrown when trying to view group inbox for non-existing group.
- throw new ClientException(_m('No such group.'), 404);
- }
-
- $this->group = User_group::getKV('id', $localGroup->group_id);
-
- if (empty($this->group)) {
- // TRANS: Client exception thrown when trying to view group inbox for non-existing group.
- throw new ClientException(_m('No such group.'), 404);
- }
-
- if (!$cur->isMember($this->group)) {
- // TRANS: Client exception thrown when trying to view group inbox while not a member.
- throw new ClientException(_m('Only for members.'), 403);
- }
-
- $this->page = $this->trimmed('page');
-
- if (!$this->page) {
- $this->page = 1;
- }
-
- $this->gm = Group_message::forGroup($this->group,
- ($this->page - 1) * MESSAGES_PER_PAGE,
- MESSAGES_PER_PAGE + 1);
- return true;
- }
-
- function showLocalNav()
- {
- $nav = new GroupNav($this, $this->group);
- $nav->show();
- }
-
- function showNoticeForm()
- {
- $form = new GroupMessageForm($this, $this->group);
- $form->show();
- }
-
- function showContent()
- {
- $gml = new GroupMessageList($this, $this->gm);
- $cnt = $gml->show();
-
- if ($cnt == 0) {
- // TRANS: Text of group inbox if no private messages were sent to it.
- $this->element('p', 'guide', _m('This group has not received any private messages.'));
- }
- $this->pagination($this->page > 1,
- $cnt > MESSAGES_PER_PAGE,
- $this->page,
- 'groupinbox',
- array('nickname' => $this->group->nickname));
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- $this->showPage();
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return true;
- }
-
- /**
- * Title of the page
- *
- * @return string page title, with page number
- */
- function title()
- {
- $base = $this->group->getFancyName();
-
- if ($this->page == 1) {
- // TRANS: Title of inbox for group %s.
- return sprintf(_m('%s group inbox'), $base);
- } else {
- // TRANS: Page title for any but first group page.
- // TRANS: %1$s is a group name, $2$s is a page number.
- return sprintf(_m('%1$s group inbox, page %2$d'),
- $base,
- $this->page);
- }
- }
-
- /**
- * Show the page notice
- *
- * Shows instructions for the page
- *
- * @return void
- */
- function showPageNotice()
- {
- $instr = $this->getInstructions();
- $output = common_markup_to_html($instr);
-
- $this->elementStart('div', 'instructions');
- $this->raw($output);
- $this->elementEnd('div');
- }
-
- /**
- * Instructions for using this page
- *
- * @return string localised instructions for using the page
- */
- function getInstructions()
- {
- // TRANS: Instructions for user inbox page.
- return _m('This is the group inbox, which lists all incoming private messages for this group.');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Command object for messages to groups
- *
- * PHP version 5
- *
- * 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 Command
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Command object for messages to groups
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class GroupMessageCommand extends Command
-{
- /** User sending the message. */
- var $user;
- /** Nickname of the group they're sending to. */
- var $nickname;
- /** Text of the message. */
- var $text;
-
- /**
- * Constructor
- *
- * @param User $user User sending the message
- * @param string $nickname Nickname of the group
- * @param string $text Text of message
- */
- function __construct($user, $nickname, $text)
- {
- $this->user = $user;
- $this->nickname = $nickname;
- $this->text = $text;
- }
-
- function handle($channel)
- {
- // Throws a command exception if group not found
- $group = $this->getGroup($this->nickname);
-
- $gm = Group_message::send($this->user, $group, $this->text);
-
- $channel->output($this->user,
- // TRANS: Succes message after sending private group message to group %s.
- sprintf(_m('Direct message to group %s sent.'),
- $group->nickname));
-
- return true;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form for posting a group message
- *
- * PHP version 5
- *
- * 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 GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form for posting a group message
- *
- * @category GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class GroupMessageForm extends Form
-{
- var $group;
- var $content;
-
- /**
- * Constructor
- *
- * @param HTMLOutputter $out Output context
- * @param User_group $group Group to post to
- *
- * @todo add a drop-down list to post to any group
- */
- function __construct($out, $group, $content=null)
- {
- parent::__construct($out);
-
- $this->group = $group;
- $this->content = $content;
- }
-
- /**
- * Action for the form
- */
- function action()
- {
- return common_local_url('newgroupmessage',
- array('nickname' => $this->group->nickname));
- }
-
- /**
- * Legend for the form
- *
- * @param
- *
- * @return
- */
- function formLegend()
- {
- $this->out->element('legend',
- null,
- // TRANS: Form legend for sending private message to group %s.
- sprintf(_m('Message to %s'), $this->group->nickname));
- }
-
- /**
- * id for the form
- *
- * @param
- *
- * @return
- */
- function id()
- {
- return 'form_notice-group-message';
- }
-
- /**
- * class for the form
- *
- * @param
- *
- * @return
- */
- function formClass()
- {
- return 'form_notice';
- }
-
- /**
- * Entry data
- *
- * @param
- *
- * @return
- */
- function formData()
- {
- $this->out->element('label', array('for' => 'notice_data-text',
- 'id' => 'notice_data-text-label'),
- // TRANS: Field label for private group message to group %s.
- sprintf(_m('Direct message to %s'), $this->group->nickname));
-
- $this->out->element('textarea', array('id' => 'notice_data-text',
- 'cols' => 35,
- 'rows' => 4,
- 'name' => 'content'),
- ($this->content) ? $this->content : '');
-
- $contentLimit = Message::maxContent();
-
- if ($contentLimit > 0) {
- $this->out->elementStart('dl', 'form_note');
- // TRANS: Indicator for number of chatacters still available for notice.
- $this->out->element('dt', null, _m('Available characters'));
- $this->out->element('dd', array('class' => 'count'),
- $contentLimit);
- $this->out->elementEnd('dl');
- }
- }
-
- /**
- * Legend for the form
- *
- * @param
- *
- * @return
- */
- function formActions()
- {
- $this->out->element('input', array('id' => 'notice_action-submit',
- 'class' => 'submit',
- 'name' => 'message_send',
- 'type' => 'submit',
- // TRANS: Send button text for sending private group notice.
- 'value' => _m('Send button for sending notice', 'Send')));
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Widget for showing list of group messages
- *
- * PHP version 5
- *
- * 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 GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Widget for showing list of group messages
- *
- * @category GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class GroupMessageList extends Widget
-{
- var $gm;
-
- /**
- * Constructor
- *
- * @param HTMLOutputter $out output context
- * @param Group_message $gm Group message stream
- */
- function __construct($out, $gm)
- {
- parent::__construct($out);
- $this->gm = $gm;
- }
-
- /**
- * Show the list
- *
- * @return void
- */
- function show()
- {
- $this->out->elementStart('ul', 'notices messages group-messages');
-
- $cnt = 0;
-
- while ($this->gm->fetch() && $cnt <= MESSAGES_PER_PAGE) {
-
- $cnt++;
-
- if ($cnt > MESSAGES_PER_PAGE) {
- break;
- }
-
- $gmli = new GroupMessageListItem($this->out, $this->gm);
- $gmli->show();
- }
-
- $this->out->elementEnd('ul');
-
- return $cnt;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Widget for showing an individual group message
- *
- * PHP version 5
- *
- * 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 GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Widget for showing a single group message
- *
- * @category GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class GroupMessageListItem extends Widget
-{
- var $gm;
-
- /**
- * Constructor
- *
- * @param HTMLOutputter $out output context
- * @param Group_message $gm Group message
- */
- function __construct($out, $gm)
- {
- parent::__construct($out);
- $this->gm = $gm;
- }
-
- /**
- * Show the item
- *
- * @return void
- */
- function show()
- {
- $group = $this->gm->getGroup();
- $sender = $this->gm->getSender();
-
- $this->out->elementStart('li', array('class' => 'hentry notice message group-message',
- 'id' => 'message-' . $this->gm->id));
-
- $this->out->elementStart('div', 'entry-title');
- $this->out->elementStart('span', 'vcard author');
- $this->out->elementStart('a',
- array('href' => $sender->profileurl,
- 'class' => 'url'));
- $avatar = $sender->getAvatar(AVATAR_STREAM_SIZE);
- $this->out->element('img', array('src' => ($avatar) ?
- $avatar->displayUrl() :
- Avatar::defaultImage(AVATAR_STREAM_SIZE),
- 'width' => AVATAR_STREAM_SIZE,
- 'height' => AVATAR_STREAM_SIZE,
- 'class' => 'photo avatar',
- 'alt' => $sender->getBestName()));
- $this->out->element('span',
- array('class' => 'nickname fn'),
- $sender->nickname);
- $this->out->elementEnd('a');
- $this->out->elementEnd('span');
-
- $this->out->elementStart('p', array('class' => 'entry-content message-content'));
- $this->out->raw($this->gm->rendered);
- $this->out->elementEnd('p');
- $this->out->elementEnd('div');
-
- $this->out->elementStart('div', 'entry-content');
- $this->out->elementStart('a', array('rel' => 'bookmark',
- 'class' => 'timestamp',
- 'href' => $this->gm->url));
- $dt = common_date_iso8601($this->gm->created);
- $this->out->element('abbr', array('class' => 'published',
- 'title' => $dt),
- common_date_string($this->gm->created));
- $this->out->elementEnd('a');
- $this->out->elementEnd('div');
-
- $this->out->elementEnd('li');
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Command object for messages to groups
+ *
+ * PHP version 5
+ *
+ * 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 Command
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Command object for messages to groups
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class GroupMessageCommand extends Command
+{
+ /** User sending the message. */
+ var $user;
+ /** Nickname of the group they're sending to. */
+ var $nickname;
+ /** Text of the message. */
+ var $text;
+
+ /**
+ * Constructor
+ *
+ * @param User $user User sending the message
+ * @param string $nickname Nickname of the group
+ * @param string $text Text of message
+ */
+ function __construct($user, $nickname, $text)
+ {
+ $this->user = $user;
+ $this->nickname = $nickname;
+ $this->text = $text;
+ }
+
+ function handle($channel)
+ {
+ // Throws a command exception if group not found
+ $group = $this->getGroup($this->nickname);
+
+ $gm = Group_message::send($this->user, $group, $this->text);
+
+ $channel->output($this->user,
+ // TRANS: Succes message after sending private group message to group %s.
+ sprintf(_m('Direct message to group %s sent.'),
+ $group->nickname));
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Widget for showing list of group messages
+ *
+ * PHP version 5
+ *
+ * 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 GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Widget for showing list of group messages
+ *
+ * @category GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class GroupMessageList extends Widget
+{
+ var $gm;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output context
+ * @param Group_message $gm Group message stream
+ */
+ function __construct($out, $gm)
+ {
+ parent::__construct($out);
+ $this->gm = $gm;
+ }
+
+ /**
+ * Show the list
+ *
+ * @return void
+ */
+ function show()
+ {
+ $this->out->elementStart('ul', 'notices messages group-messages');
+
+ $cnt = 0;
+
+ while ($this->gm->fetch() && $cnt <= MESSAGES_PER_PAGE) {
+
+ $cnt++;
+
+ if ($cnt > MESSAGES_PER_PAGE) {
+ break;
+ }
+
+ $gmli = new GroupMessageListItem($this->out, $this->gm);
+ $gmli->show();
+ }
+
+ $this->out->elementEnd('ul');
+
+ return $cnt;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Widget for showing an individual group message
+ *
+ * PHP version 5
+ *
+ * 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 GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Widget for showing a single group message
+ *
+ * @category GroupPrivateMessage
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class GroupMessageListItem extends Widget
+{
+ var $gm;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output context
+ * @param Group_message $gm Group message
+ */
+ function __construct($out, $gm)
+ {
+ parent::__construct($out);
+ $this->gm = $gm;
+ }
+
+ /**
+ * Show the item
+ *
+ * @return void
+ */
+ function show()
+ {
+ $group = $this->gm->getGroup();
+ $sender = $this->gm->getSender();
+
+ $this->out->elementStart('li', array('class' => 'hentry notice message group-message',
+ 'id' => 'message-' . $this->gm->id));
+
+ $this->out->elementStart('div', 'entry-title');
+ $this->out->elementStart('span', 'vcard author');
+ $this->out->elementStart('a',
+ array('href' => $sender->profileurl,
+ 'class' => 'url'));
+ $avatar = $sender->getAvatar(AVATAR_STREAM_SIZE);
+ $this->out->element('img', array('src' => ($avatar) ?
+ $avatar->displayUrl() :
+ Avatar::defaultImage(AVATAR_STREAM_SIZE),
+ 'width' => AVATAR_STREAM_SIZE,
+ 'height' => AVATAR_STREAM_SIZE,
+ 'class' => 'photo avatar',
+ 'alt' => $sender->getBestName()));
+ $this->out->element('span',
+ array('class' => 'nickname fn'),
+ $sender->nickname);
+ $this->out->elementEnd('a');
+ $this->out->elementEnd('span');
+
+ $this->out->elementStart('p', array('class' => 'entry-content message-content'));
+ $this->out->raw($this->gm->rendered);
+ $this->out->elementEnd('p');
+ $this->out->elementEnd('div');
+
+ $this->out->elementStart('div', 'entry-content');
+ $this->out->elementStart('a', array('rel' => 'bookmark',
+ 'class' => 'timestamp',
+ 'href' => $this->gm->url));
+ $dt = common_date_iso8601($this->gm->created);
+ $this->out->element('abbr', array('class' => 'published',
+ 'title' => $dt),
+ common_date_string($this->gm->created));
+ $this->out->elementEnd('a');
+ $this->out->elementEnd('div');
+
+ $this->out->elementEnd('li');
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Action for adding a new group message
- *
- * PHP version 5
- *
- * 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 Cache
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Action for adding a new group message
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class NewgroupmessageAction extends Action
-{
- var $group;
- var $user;
- var $text;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Client exception thrown when trying to send a private group message while not logged in.
- throw new ClientException(_m('Must be logged in.'), 403);
- }
-
- if (!$this->user->hasRight(Right::NEWMESSAGE)) {
- // TRANS: Exception thrown when user %s is not allowed to send a private group message.
- throw new Exception(sprintf(_m('User %s is not allowed to send private messages.'),
- $this->user->nickname));
- }
-
- $nicknameArg = $this->trimmed('nickname');
-
- $nickname = common_canonical_nickname($nicknameArg);
-
- if ($nickname != $nicknameArg) {
- $url = common_local_url('newgroupmessage', array('nickname' => $nickname));
- common_redirect($url, 301);
- return false;
- }
-
- $localGroup = Local_group::getKV('nickname', $nickname);
-
- if (empty($localGroup)) {
- // TRANS: Client exception thrown when trying to send a private group message to a non-existing group.
- throw new ClientException(_m('No such group.'), 404);
- }
-
- $this->group = User_group::getKV('id', $localGroup->group_id);
-
- if (empty($this->group)) {
- // TRANS: Client exception thrown when trying to send a private group message to a non-existing group.
- throw new ClientException(_m('No such group.'), 404);
- }
-
- // This throws an exception on error
- Group_privacy_settings::ensurePost($this->user, $this->group);
-
- // If we're posted to, check session token and get text
- if ($this->isPost()) {
- $this->checkSessionToken();
- $this->text = $this->trimmed('content');
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- if ($this->isPost()) {
- $this->sendNewMessage();
- } else {
- $this->showPage();
- }
- }
-
- function showNoticeForm()
- {
- $form = new GroupMessageForm($this, $this->group);
- $form->show();
- }
-
- function sendNewMessage()
- {
- $gm = Group_message::send($this->user, $this->group, $this->text);
-
- if ($this->boolean('ajax')) {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- // TRANS: Title after sending a private group message.
- $this->element('title', null, _m('Message sent'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $this->element('p',
- array('id' => 'command_result'),
- // TRANS: Succes text after sending a direct message to group %s.
- sprintf(_m('Direct message to %s sent.'),
- $this->group->nickname));
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- common_redirect($gm->url, 303);
- }
- }
-
- function title()
- {
- // TRANS: Title of form for new private group message.
- return sprintf(_m('New message to group %s'), $this->group->nickname);
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Show a single group message
- *
- * PHP version 5
- *
- * 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 GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Show a single private group message
- *
- * @category GroupPrivateMessage
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ShowgroupmessageAction extends Action
-{
- var $gm;
- var $group;
- var $sender;
- var $user;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Client exception thrown when trying to view group private messages without being logged in.
- throw new ClientException(_m('Only logged-in users can view private messages.'),
- 403);
- }
-
- $id = $this->trimmed('id');
-
- $this->gm = Group_message::getKV('id', $id);
-
- if (empty($this->gm)) {
- // TRANS: Client exception thrown when trying to view a non-existing group private message.
- throw new ClientException(_m('No such message.'), 404);
- }
-
- $this->group = User_group::getKV('id', $this->gm->to_group);
-
- if (empty($this->group)) {
- // TRANS: Server exception thrown when trying to view group private messages for a non-exsting group.
- throw new ServerException(_m('Group not found.'));
- }
-
- if (!$this->user->isMember($this->group)) {
- // TRANS: Client exception thrown when trying to view a group private message without being a group member.
- throw new ClientException(_m('Cannot read message.'), 403);
- }
-
- $this->sender = Profile::getKV('id', $this->gm->from_profile);
-
- if (empty($this->sender)) {
- // TRANS: Server exception thrown when trying to view a group private message without a sender.
- throw new ServerException(_m('No sender found.'));
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- $this->showPage();
- }
-
- /**
- * Title of the page
- */
- function title()
- {
- // TRANS: Title for private group message.
- // TRANS: %1$s is the sender name, %2$s is the group name, %3$s is a timestamp.
- return sprintf(_m('Message from %1$s to group %2$s on %3$s'),
- $this->sender->nickname,
- $this->group->nickname,
- common_exact_date($this->gm->created));
- }
-
- /**
- * Show the content area.
- */
- function showContent()
- {
- $this->elementStart('ul', 'notices messages');
- $gmli = new GroupMessageListItem($this, $this->gm);
- $gmli->show();
- $this->elementEnd('ul');
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return true;
- }
-
- /**
- * Return last modified, if applicable.
- *
- * MAY override
- *
- * @return string last modified http header
- */
- function lastModified()
- {
- return max(strtotime($this->group->modified),
- strtotime($this->sender->modified),
- strtotime($this->gm->modified));
- }
-
- /**
- * Return etag, if applicable.
- *
- * MAY override
- *
- * @return string etag http header
- */
- function etag()
- {
- $avatar = $this->sender->getAvatar(AVATAR_STREAM_SIZE);
-
- $avtime = ($avatar) ? strtotime($avatar->modified) : 0;
-
- return 'W/"' . implode(':', array($this->arg('action'),
- common_user_cache_hash(),
- common_language(),
- $this->gm->id,
- strtotime($this->sender->modified),
- strtotime($this->group->modified),
- $avtime)) . '"';
- }
-}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'ImapManager':
- case 'IMAPMailHandler':
- include_once $dir . '/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
- }
- }
-
function onStartQueueDaemonIoManagers(&$classes)
{
$classes[] = new ImapManager($this);
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-class IMAPMailHandler extends MailHandler
-{
- function error($from, $msg)
- {
- $this->log(LOG_INFO, "Error: $from $msg");
- $headers['To'] = $from;
- // TRANS: E-mail subject in case of an error.
- $headers['Subject'] = _m('Error');
-
- return mail_send(array($from), $headers, $msg);
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * IMAP IO Manager
- *
- * 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
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2009-2010 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @maintainer Craig Andrews <candrews@integralblue.com>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-class ImapManager extends IoManager
-{
- protected $conn = null;
-
- function __construct($plugin)
- {
- $this->plugin = $plugin;
- }
-
- /**
- * Fetch the singleton manager for the current site.
- * @return mixed ImapManager, or false if unneeded
- */
- public static function get()
- {
- // TRANS: Exception thrown when the ImapManager is used incorrectly in the code.
- throw new Exception(_m('ImapManager should be created using its constructor, not using the static "get()" method.'));
- }
-
- /**
- * Lists the IM connection socket to allow i/o master to wake
- * when input comes in here as well as from the queue source.
- *
- * @return array of resources
- */
- public function getSockets()
- {
- return array();
- }
-
- /**
- * Tell the i/o master we need one instance globally.
- * Since this is a plugin manager, the plugin class itself will
- * create one instance per site. This prevents the IoMaster from
- * making more instances.
- */
- public static function multiSite()
- {
- return IoManager::GLOBAL_SINGLE_ONLY;
- }
-
- /**
- * Initialize connection to server.
- * @return boolean true on success
- */
- public function start($master)
- {
- if(parent::start($master))
- {
- $this->conn = $this->connect();
- return true;
- }else{
- return false;
- }
- }
-
- public function handleInput($socket)
- {
- $this->check_mailbox();
- return true;
- }
-
- public function poll()
- {
- return $this->check_mailbox() > 0;
- }
-
- function pollInterval()
- {
- return $this->plugin->poll_frequency;
- }
-
- protected function connect()
- {
- $this->conn = imap_open($this->plugin->mailbox, $this->plugin->user, $this->plugin->password);
- if($this->conn){
- common_log(LOG_INFO, "Connected");
- return $this->conn;
- }else{
- common_log(LOG_INFO, "Failed to connect: " . imap_last_error());
- return $this->conn;
- }
- }
-
- protected function check_mailbox()
- {
- imap_ping($this->conn);
- $count = imap_num_msg($this->conn);
- common_log(LOG_INFO, "Found $count messages");
- if($count > 0){
- $handler = new IMAPMailHandler();
- for($i=1; $i <= $count; $i++)
- {
- $rawmessage = imap_fetchheader($this->conn, $count, FT_PREFETCHTEXT) . imap_body($this->conn, $i);
- $handler->handle_message($rawmessage);
- imap_delete($this->conn, $i);
- }
- imap_expunge($this->conn);
- common_log(LOG_INFO, "Finished processing messages");
- }
- return $count;
- }
-}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class IMAPMailHandler extends MailHandler
+{
+ function error($from, $msg)
+ {
+ $this->log(LOG_INFO, "Error: $from $msg");
+ $headers['To'] = $from;
+ // TRANS: E-mail subject in case of an error.
+ $headers['Subject'] = _m('Error');
+
+ return mail_send(array($from), $headers, $msg);
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * IMAP IO Manager
+ *
+ * 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
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009-2010 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @maintainer Craig Andrews <candrews@integralblue.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class ImapManager extends IoManager
+{
+ protected $conn = null;
+
+ function __construct($plugin)
+ {
+ $this->plugin = $plugin;
+ }
+
+ /**
+ * Fetch the singleton manager for the current site.
+ * @return mixed ImapManager, or false if unneeded
+ */
+ public static function get()
+ {
+ // TRANS: Exception thrown when the ImapManager is used incorrectly in the code.
+ throw new Exception(_m('ImapManager should be created using its constructor, not using the static "get()" method.'));
+ }
+
+ /**
+ * Lists the IM connection socket to allow i/o master to wake
+ * when input comes in here as well as from the queue source.
+ *
+ * @return array of resources
+ */
+ public function getSockets()
+ {
+ return array();
+ }
+
+ /**
+ * Tell the i/o master we need one instance globally.
+ * Since this is a plugin manager, the plugin class itself will
+ * create one instance per site. This prevents the IoMaster from
+ * making more instances.
+ */
+ public static function multiSite()
+ {
+ return IoManager::GLOBAL_SINGLE_ONLY;
+ }
+
+ /**
+ * Initialize connection to server.
+ * @return boolean true on success
+ */
+ public function start($master)
+ {
+ if(parent::start($master))
+ {
+ $this->conn = $this->connect();
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+ public function handleInput($socket)
+ {
+ $this->check_mailbox();
+ return true;
+ }
+
+ public function poll()
+ {
+ return $this->check_mailbox() > 0;
+ }
+
+ function pollInterval()
+ {
+ return $this->plugin->poll_frequency;
+ }
+
+ protected function connect()
+ {
+ $this->conn = imap_open($this->plugin->mailbox, $this->plugin->user, $this->plugin->password);
+ if($this->conn){
+ common_log(LOG_INFO, "Connected");
+ return $this->conn;
+ }else{
+ common_log(LOG_INFO, "Failed to connect: " . imap_last_error());
+ return $this->conn;
+ }
+ }
+
+ protected function check_mailbox()
+ {
+ imap_ping($this->conn);
+ $count = imap_num_msg($this->conn);
+ common_log(LOG_INFO, "Found $count messages");
+ if($count > 0){
+ $handler = new IMAPMailHandler();
+ for($i=1; $i <= $count; $i++)
+ {
+ $rawmessage = imap_fetchheader($this->conn, $count, FT_PREFETCHTEXT) . imap_body($this->conn, $i);
+ $handler->handle_message($rawmessage);
+ imap_delete($this->conn, $i);
+ }
+ imap_expunge($this->conn);
+ common_log(LOG_INFO, "Finished processing messages");
+ }
+ return $count;
+ }
+}
+++ /dev/null
-<?php\r
-/**\r
- * StatusNet, the distributed open-source microblogging tool\r
- *\r
- * Extend the IMChannel class to allow commands to send messages\r
- * to a channel instead of PMing a user\r
- *\r
- * PHP version 5\r
- *\r
- * LICENCE: This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU Affero General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU Affero General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Affero General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- *\r
- * @category Network\r
- * @package StatusNet\r
- * @author Luke Fitzgerald <lw.fitzgerald@googlemail.com>\r
- * @copyright 2010 StatusNet, Inc.\r
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0\r
- * @link http://status.net/\r
- */\r
-\r
-if (!defined('STATUSNET') && !defined('LACONICA')) {\r
- exit(1);\r
-}\r
-\r
-class ChannelResponseChannel extends IMChannel {\r
- protected $ircChannel;\r
-\r
- /**\r
- * Construct a ChannelResponseChannel\r
- *\r
- * @param IMplugin $imPlugin IMPlugin\r
- * @param string $ircChannel IRC Channel to reply to\r
- * @return ChannelResponseChannel\r
- */\r
- public function __construct($imPlugin, $ircChannel) {\r
- $this->ircChannel = $ircChannel;\r
- parent::__construct($imPlugin);\r
- }\r
-\r
- /**\r
- * Send a message using the plugin\r
- *\r
- * @param User $user User\r
- * @param string $text Message text\r
- * @return void\r
- */\r
- public function output($user, $text) {\r
- $text = $user->nickname.': ['.common_config('site', 'name') . '] ' . $text;\r
- $this->imPlugin->sendMessage($this->ircChannel, $text);\r
- }\r
-}\r
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Instead of sending IRC messages, retrieve the raw data that would be sent
- *
- * 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 Network
- * @package StatusNet
- * @author Luke Fitzgerald <lw.fitzgerald@googlemail.com>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-class Fake_Irc extends Phergie_Driver_Streams {
- public $would_be_sent = null;
-
- /**
- * Store the components for sending a command
- *
- * @param string $command Command
- * @param array $args Arguments
- * @return void
- */
- protected function send($command, $args = '') {
- $this->would_be_sent = array('command' => $command, 'args' => $args);
- }
-}
* @return boolean hook value; true means continue processing, false means stop.
*/
public function onAutoload($cls) {
- $dir = dirname(__FILE__);
-
- switch ($cls) {
- case 'IrcManager':
- include_once $dir . '/'.strtolower($cls).'.php';
- return false;
- case 'Fake_Irc':
- case 'Irc_waiting_message':
- case 'ChannelResponseChannel':
- include_once $dir . '/'. $cls .'.php';
- return false;
- default:
- if (substr($cls, 0, 7) == 'Phergie') {
- include_once str_replace('_', DIRECTORY_SEPARATOR, $cls) . '.php';
- return false;
- }
- return true;
+ // in the beginning of this file, we have added an include path
+ if (substr($cls, 0, 7) == 'Phergie') {
+ include_once str_replace('_', DIRECTORY_SEPARATOR, $cls) . '.php';
+ return false;
}
+
+ return parent::onAutoload($cls);
}
/*
+++ /dev/null
-<?php\r
-/**\r
- * Table Definition for irc_waiting_message\r
- */\r
-\r
-require_once INSTALLDIR.'/classes/Memcached_DataObject.php';\r
-\r
-class Irc_waiting_message extends Managed_DataObject {\r
-\r
- public $__table = 'irc_waiting_message'; // table name\r
- public $id; // int primary_key not_null auto_increment\r
- public $data; // blob not_null\r
- public $prioritise; // tinyint(1) not_null\r
- public $attempts; // int not_null\r
- public $claimed; // datetime()\r
- public $created; // datetime() not_null\r
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP\r
-\r
- public static function schemaDef()\r
- {\r
- return array(\r
- 'fields' => array(\r
- 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique ID for entry'),\r
- 'data' => array('type' => 'blob', 'not null' => true, 'description' => 'data blob'),\r
- 'prioritise' => array('type' => 'int', 'size' => 'tiny', 'description' => 'tinyint priority value'),\r
- 'attempts' => array('type' => 'int', 'not null' => true, 'description' => 'attempts count'),\r
- 'claimed' => array('type' => 'datetime', 'description' => 'date this irc message was claimed'),\r
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),\r
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),\r
- ),\r
- 'primary key' => array('id'),\r
- 'indexes' => array(\r
- 'irc_waiting_message_prioritise_idx' => array('prioritise'),\r
- ),\r
- );\r
- }\r
-\r
- /**\r
- * Get the next item in the queue\r
- *\r
- * @return Irc_waiting_message Next message if there is one\r
- */\r
- public static function top() {\r
- $wm = new Irc_waiting_message();\r
-\r
- $wm->orderBy('prioritise DESC, created');\r
- $wm->whereAdd('claimed is null');\r
-\r
- $wm->limit(1);\r
-\r
- $cnt = $wm->find(true);\r
-\r
- if ($cnt) {\r
- // XXX: potential race condition\r
- // can we force it to only update if claimed is still null\r
- // (or old)?\r
- common_log(LOG_INFO, 'claiming IRC waiting message id = ' . $wm->id);\r
- $orig = clone($wm);\r
- $wm->claimed = common_sql_now();\r
- $result = $wm->update($orig);\r
- if ($result) {\r
- common_log(LOG_INFO, 'claim succeeded.');\r
- return $wm;\r
- } else {\r
- common_log(LOG_INFO, 'claim failed.');\r
- }\r
- }\r
- $wm = null;\r
- return null;\r
- }\r
-\r
- /**\r
- * Increment the attempts count\r
- *\r
- * @return void\r
- * @throws Exception\r
- */\r
- public function incAttempts() {\r
- $orig = clone($this);\r
- $this->attempts++;\r
- $result = $this->update($orig);\r
-\r
- if (!$result) {\r
- // TRANS: Exception thrown when an IRC attempts count could not be updated.\r
- // TRANS: %d is the object ID for which the count could not be updated.\r
- throw Exception(sprintf(_m('Could not increment attempts count for %d.'), $this->id));\r
- }\r
- }\r
-\r
- /**\r
- * Release a claimed item.\r
- */\r
- public function releaseClaim() {\r
- // DB_DataObject doesn't let us save nulls right now\r
- $sql = sprintf("UPDATE irc_waiting_message SET claimed=NULL WHERE id=%d", $this->id);\r
- $this->query($sql);\r
-\r
- $this->claimed = null;\r
- $this->encache();\r
- }\r
-}\r
--- /dev/null
+<?php\r
+/**\r
+ * Table Definition for irc_waiting_message\r
+ */\r
+\r
+require_once INSTALLDIR.'/classes/Memcached_DataObject.php';\r
+\r
+class Irc_waiting_message extends Managed_DataObject {\r
+\r
+ public $__table = 'irc_waiting_message'; // table name\r
+ public $id; // int primary_key not_null auto_increment\r
+ public $data; // blob not_null\r
+ public $prioritise; // tinyint(1) not_null\r
+ public $attempts; // int not_null\r
+ public $claimed; // datetime()\r
+ public $created; // datetime() not_null\r
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP\r
+\r
+ public static function schemaDef()\r
+ {\r
+ return array(\r
+ 'fields' => array(\r
+ 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique ID for entry'),\r
+ 'data' => array('type' => 'blob', 'not null' => true, 'description' => 'data blob'),\r
+ 'prioritise' => array('type' => 'int', 'size' => 'tiny', 'description' => 'tinyint priority value'),\r
+ 'attempts' => array('type' => 'int', 'not null' => true, 'description' => 'attempts count'),\r
+ 'claimed' => array('type' => 'datetime', 'description' => 'date this irc message was claimed'),\r
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),\r
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),\r
+ ),\r
+ 'primary key' => array('id'),\r
+ 'indexes' => array(\r
+ 'irc_waiting_message_prioritise_idx' => array('prioritise'),\r
+ ),\r
+ );\r
+ }\r
+\r
+ /**\r
+ * Get the next item in the queue\r
+ *\r
+ * @return Irc_waiting_message Next message if there is one\r
+ */\r
+ public static function top() {\r
+ $wm = new Irc_waiting_message();\r
+\r
+ $wm->orderBy('prioritise DESC, created');\r
+ $wm->whereAdd('claimed is null');\r
+\r
+ $wm->limit(1);\r
+\r
+ $cnt = $wm->find(true);\r
+\r
+ if ($cnt) {\r
+ // XXX: potential race condition\r
+ // can we force it to only update if claimed is still null\r
+ // (or old)?\r
+ common_log(LOG_INFO, 'claiming IRC waiting message id = ' . $wm->id);\r
+ $orig = clone($wm);\r
+ $wm->claimed = common_sql_now();\r
+ $result = $wm->update($orig);\r
+ if ($result) {\r
+ common_log(LOG_INFO, 'claim succeeded.');\r
+ return $wm;\r
+ } else {\r
+ common_log(LOG_INFO, 'claim failed.');\r
+ }\r
+ }\r
+ $wm = null;\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Increment the attempts count\r
+ *\r
+ * @return void\r
+ * @throws Exception\r
+ */\r
+ public function incAttempts() {\r
+ $orig = clone($this);\r
+ $this->attempts++;\r
+ $result = $this->update($orig);\r
+\r
+ if (!$result) {\r
+ // TRANS: Exception thrown when an IRC attempts count could not be updated.\r
+ // TRANS: %d is the object ID for which the count could not be updated.\r
+ throw Exception(sprintf(_m('Could not increment attempts count for %d.'), $this->id));\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Release a claimed item.\r
+ */\r
+ public function releaseClaim() {\r
+ // DB_DataObject doesn't let us save nulls right now\r
+ $sql = sprintf("UPDATE irc_waiting_message SET claimed=NULL WHERE id=%d", $this->id);\r
+ $this->query($sql);\r
+\r
+ $this->claimed = null;\r
+ $this->encache();\r
+ }\r
+}\r
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-/**
- * IRC background connection manager for IRC-using queue handlers,
- * allowing them to send outgoing messages on the right connection.
- *
- * Input is handled during socket select loop, Any incoming messages will be handled.
- *
- * In a multi-site queuedaemon.php run, one connection will be instantiated
- * for each site being handled by the current process that has IRC enabled.
- */
-class IrcManager extends ImManager {
- protected $conn = null;
- protected $lastPing = null;
- protected $messageWaiting = true;
- protected $lastMessage = null;
-
- protected $regChecks = array();
- protected $regChecksLookup = array();
-
- protected $connected = false;
-
- /**
- * Initialize connection to server.
- *
- * @return boolean true on success
- */
- public function start($master) {
- if (parent::start($master)) {
- $this->connect();
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Return any open sockets that the run loop should listen
- * for input on.
- *
- * @return array Array of socket resources
- */
- public function getSockets() {
- $this->connect();
- if ($this->conn) {
- return $this->conn->getSockets();
- } else {
- return array();
- }
- }
-
- /**
- * Request a maximum timeout for listeners before the next idle period.
- *
- * @return integer Maximum timeout
- */
- public function timeout() {
- if ($this->messageWaiting) {
- return 1;
- } else {
- return $this->plugin->pinginterval;
- }
- }
-
- /**
- * Idle processing for io manager's execution loop.
- *
- * @return void
- */
- public function idle() {
- // Send a ping if necessary
- if (empty($this->lastPing) || time() - $this->lastPing > $this->plugin->pinginterval) {
- $this->sendPing();
- }
-
- if ($this->connected) {
- // Send a waiting message if appropriate
- if ($this->messageWaiting && time() - $this->lastMessage > 1) {
- $wm = Irc_waiting_message::top();
- if ($wm === NULL) {
- $this->messageWaiting = false;
- return;
- }
-
- $data = unserialize($wm->data);
- $wm->incAttempts();
-
- if ($this->send_raw_message($data)) {
- $wm->delete();
- } else {
- if ($wm->attempts <= common_config('queue', 'max_retries')) {
- // Try again next idle
- $wm->releaseClaim();
- } else {
- // Exceeded the maximum number of retries
- $wm->delete();
- }
- }
- }
- }
- }
-
- /**
- * Process IRC events that have come in over the wire.
- *
- * @param resource $socket Socket to handle input on
- * @return void
- */
- public function handleInput($socket) {
- common_log(LOG_DEBUG, 'Servicing the IRC queue.');
- $this->stats('irc_process');
-
- try {
- $this->conn->handleEvents();
- } catch (Phergie_Driver_Exception $e) {
- $this->connected = false;
- $this->conn->reconnect();
- }
- }
-
- /**
- * Initiate connection
- *
- * @return void
- */
- public function connect() {
- if (!$this->conn) {
- $this->conn = new Phergie_StatusnetBot;
-
- $config = new Phergie_Config;
- $config->readArray(
- array(
- 'connections' => array(
- array(
- 'host' => $this->plugin->host,
- 'port' => $this->plugin->port,
- 'username' => $this->plugin->username,
- 'realname' => $this->plugin->realname,
- 'nick' => $this->plugin->nick,
- 'password' => $this->plugin->password,
- 'transport' => $this->plugin->transporttype,
- 'encoding' => $this->plugin->encoding
- )
- ),
-
- 'driver' => 'statusnet',
-
- 'processor' => 'async',
- 'processor.options' => array('sec' => 0, 'usec' => 0),
-
- 'plugins' => array(
- 'Pong',
- 'NickServ',
- 'AutoJoin',
- 'Statusnet',
- ),
-
- 'plugins.autoload' => true,
-
- // Uncomment to enable debugging output
- //'ui.enabled' => true,
-
- 'nickserv.password' => $this->plugin->nickservpassword,
- 'nickserv.identify_message' => $this->plugin->nickservidentifyregexp,
-
- 'autojoin.channels' => $this->plugin->channels,
-
- 'statusnet.messagecallback' => array($this, 'handle_irc_message'),
- 'statusnet.regcallback' => array($this, 'handle_reg_response'),
- 'statusnet.connectedcallback' => array($this, 'handle_connected'),
- 'statusnet.unregregexp' => $this->plugin->unregregexp,
- 'statusnet.regregexp' => $this->plugin->regregexp
- )
- );
-
- $this->conn->setConfig($config);
- $this->conn->connect();
- $this->lastPing = time();
- $this->lastMessage = time();
- }
- return $this->conn;
- }
-
- /**
- * Called via a callback when a message is received
- * Passes it back to the queuing system
- *
- * @param array $data Data
- * @return boolean
- */
- public function handle_irc_message($data) {
- $this->plugin->enqueueIncomingRaw($data);
- return true;
- }
-
- /**
- * Called via a callback when NickServ responds to
- * the bots query asking if a nick is registered
- *
- * @param array $data Data
- * @return void
- */
- public function handle_reg_response($data) {
- // Retrieve data
- $screenname = $data['screenname'];
- $nickdata = $this->regChecks[$screenname];
- $usernick = $nickdata['user']->nickname;
-
- if (isset($this->regChecksLookup[$usernick])) {
- if ($data['registered']) {
- // Send message
- $this->plugin->sendConfirmationCode($screenname, $nickdata['code'], $nickdata['user'], true);
- } else {
- // TRANS: Message given when using an unregistered IRC nickname.
- $this->plugin->sendMessage($screenname, _m('Your nickname is not registered so IRC connectivity cannot be enabled.'));
-
- $confirm = new Confirm_address();
-
- $confirm->user_id = $user->id;
- $confirm->address_type = $this->plugin->transport;
-
- if ($confirm->find(true)) {
- $result = $confirm->delete();
-
- if (!$result) {
- common_log_db_error($confirm, 'DELETE', __FILE__);
- // TRANS: Server error thrown on database error when deleting IRC nickname confirmation.
- $this->serverError(_m('Could not delete confirmation.'));
- return;
- }
- }
- }
-
- // Unset lookup value
- unset($this->regChecksLookup[$usernick]);
-
- // Unset data
- unset($this->regChecks[$screename]);
- }
- }
-
- /**
- * Called when the connection is established
- *
- * @return void
- */
- public function handle_connected() {
- $this->connected = true;
- }
-
- /**
- * Enters a message into the database for sending when ready
- *
- * @param string $command Command
- * @param array $args Arguments
- * @return boolean
- */
- protected function enqueue_waiting_message($data) {
- $wm = new Irc_waiting_message();
-
- $wm->data = serialize($data);
- $wm->prioritise = $data['prioritise'];
- $wm->attempts = 0;
- $wm->created = common_sql_now();
- $result = $wm->insert();
-
- if (!$result) {
- common_log_db_error($wm, 'INSERT', __FILE__);
- // TRANS: Server exception thrown when an IRC waiting queue item could not be added to the database.
- throw new ServerException(_m('Database error inserting IRC waiting queue item.'));
- }
-
- return true;
- }
-
- /**
- * Send a message using the daemon
- *
- * @param $data Message data
- * @return boolean true on success
- */
- public function send_raw_message($data) {
- $this->connect();
- if (!$this->conn) {
- return false;
- }
-
- if ($data['type'] != 'delayedmessage') {
- if ($data['type'] != 'message') {
- // Nick checking
- $nickdata = $data['nickdata'];
- $usernick = $nickdata['user']->nickname;
- $screenname = $nickdata['screenname'];
-
- // Cancel any existing checks for this user
- if (isset($this->regChecksLookup[$usernick])) {
- unset($this->regChecks[$this->regChecksLookup[$usernick]]);
- }
-
- $this->regChecks[$screenname] = $nickdata;
- $this->regChecksLookup[$usernick] = $screenname;
- }
-
- // If there is a backlog or we need to wait, queue the message
- if ($this->messageWaiting || time() - $this->lastMessage < 1) {
- $this->enqueue_waiting_message(
- array(
- 'type' => 'delayedmessage',
- 'prioritise' => $data['prioritise'],
- 'data' => $data['data']
- )
- );
- $this->messageWaiting = true;
- return true;
- }
- }
-
- try {
- $this->conn->send($data['data']['command'], $data['data']['args']);
- } catch (Phergie_Driver_Exception $e) {
- $this->connected = false;
- $this->conn->reconnect();
- return false;
- }
-
- $this->lastMessage = time();
- return true;
- }
-
- /**
- * Sends a ping
- *
- * @return void
- */
- protected function sendPing() {
- $this->lastPing = time();
- $this->conn->send('PING', $this->lastPing);
- }
-}
--- /dev/null
+<?php\r
+/**\r
+ * StatusNet, the distributed open-source microblogging tool\r
+ *\r
+ * Extend the IMChannel class to allow commands to send messages\r
+ * to a channel instead of PMing a user\r
+ *\r
+ * PHP version 5\r
+ *\r
+ * LICENCE: This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU Affero General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU Affero General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Affero General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ * @category Network\r
+ * @package StatusNet\r
+ * @author Luke Fitzgerald <lw.fitzgerald@googlemail.com>\r
+ * @copyright 2010 StatusNet, Inc.\r
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0\r
+ * @link http://status.net/\r
+ */\r
+\r
+if (!defined('STATUSNET') && !defined('LACONICA')) {\r
+ exit(1);\r
+}\r
+\r
+class ChannelResponseChannel extends IMChannel {\r
+ protected $ircChannel;\r
+\r
+ /**\r
+ * Construct a ChannelResponseChannel\r
+ *\r
+ * @param IMplugin $imPlugin IMPlugin\r
+ * @param string $ircChannel IRC Channel to reply to\r
+ * @return ChannelResponseChannel\r
+ */\r
+ public function __construct($imPlugin, $ircChannel) {\r
+ $this->ircChannel = $ircChannel;\r
+ parent::__construct($imPlugin);\r
+ }\r
+\r
+ /**\r
+ * Send a message using the plugin\r
+ *\r
+ * @param User $user User\r
+ * @param string $text Message text\r
+ * @return void\r
+ */\r
+ public function output($user, $text) {\r
+ $text = $user->nickname.': ['.common_config('site', 'name') . '] ' . $text;\r
+ $this->imPlugin->sendMessage($this->ircChannel, $text);\r
+ }\r
+}\r
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Instead of sending IRC messages, retrieve the raw data that would be sent
+ *
+ * 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 Network
+ * @package StatusNet
+ * @author Luke Fitzgerald <lw.fitzgerald@googlemail.com>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class Fake_Irc extends Phergie_Driver_Streams {
+ public $would_be_sent = null;
+
+ /**
+ * Store the components for sending a command
+ *
+ * @param string $command Command
+ * @param array $args Arguments
+ * @return void
+ */
+ protected function send($command, $args = '') {
+ $this->would_be_sent = array('command' => $command, 'args' => $args);
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+/**
+ * IRC background connection manager for IRC-using queue handlers,
+ * allowing them to send outgoing messages on the right connection.
+ *
+ * Input is handled during socket select loop, Any incoming messages will be handled.
+ *
+ * In a multi-site queuedaemon.php run, one connection will be instantiated
+ * for each site being handled by the current process that has IRC enabled.
+ */
+class IrcManager extends ImManager {
+ protected $conn = null;
+ protected $lastPing = null;
+ protected $messageWaiting = true;
+ protected $lastMessage = null;
+
+ protected $regChecks = array();
+ protected $regChecksLookup = array();
+
+ protected $connected = false;
+
+ /**
+ * Initialize connection to server.
+ *
+ * @return boolean true on success
+ */
+ public function start($master) {
+ if (parent::start($master)) {
+ $this->connect();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Return any open sockets that the run loop should listen
+ * for input on.
+ *
+ * @return array Array of socket resources
+ */
+ public function getSockets() {
+ $this->connect();
+ if ($this->conn) {
+ return $this->conn->getSockets();
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * Request a maximum timeout for listeners before the next idle period.
+ *
+ * @return integer Maximum timeout
+ */
+ public function timeout() {
+ if ($this->messageWaiting) {
+ return 1;
+ } else {
+ return $this->plugin->pinginterval;
+ }
+ }
+
+ /**
+ * Idle processing for io manager's execution loop.
+ *
+ * @return void
+ */
+ public function idle() {
+ // Send a ping if necessary
+ if (empty($this->lastPing) || time() - $this->lastPing > $this->plugin->pinginterval) {
+ $this->sendPing();
+ }
+
+ if ($this->connected) {
+ // Send a waiting message if appropriate
+ if ($this->messageWaiting && time() - $this->lastMessage > 1) {
+ $wm = Irc_waiting_message::top();
+ if ($wm === NULL) {
+ $this->messageWaiting = false;
+ return;
+ }
+
+ $data = unserialize($wm->data);
+ $wm->incAttempts();
+
+ if ($this->send_raw_message($data)) {
+ $wm->delete();
+ } else {
+ if ($wm->attempts <= common_config('queue', 'max_retries')) {
+ // Try again next idle
+ $wm->releaseClaim();
+ } else {
+ // Exceeded the maximum number of retries
+ $wm->delete();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Process IRC events that have come in over the wire.
+ *
+ * @param resource $socket Socket to handle input on
+ * @return void
+ */
+ public function handleInput($socket) {
+ common_log(LOG_DEBUG, 'Servicing the IRC queue.');
+ $this->stats('irc_process');
+
+ try {
+ $this->conn->handleEvents();
+ } catch (Phergie_Driver_Exception $e) {
+ $this->connected = false;
+ $this->conn->reconnect();
+ }
+ }
+
+ /**
+ * Initiate connection
+ *
+ * @return void
+ */
+ public function connect() {
+ if (!$this->conn) {
+ $this->conn = new Phergie_StatusnetBot;
+
+ $config = new Phergie_Config;
+ $config->readArray(
+ array(
+ 'connections' => array(
+ array(
+ 'host' => $this->plugin->host,
+ 'port' => $this->plugin->port,
+ 'username' => $this->plugin->username,
+ 'realname' => $this->plugin->realname,
+ 'nick' => $this->plugin->nick,
+ 'password' => $this->plugin->password,
+ 'transport' => $this->plugin->transporttype,
+ 'encoding' => $this->plugin->encoding
+ )
+ ),
+
+ 'driver' => 'statusnet',
+
+ 'processor' => 'async',
+ 'processor.options' => array('sec' => 0, 'usec' => 0),
+
+ 'plugins' => array(
+ 'Pong',
+ 'NickServ',
+ 'AutoJoin',
+ 'Statusnet',
+ ),
+
+ 'plugins.autoload' => true,
+
+ // Uncomment to enable debugging output
+ //'ui.enabled' => true,
+
+ 'nickserv.password' => $this->plugin->nickservpassword,
+ 'nickserv.identify_message' => $this->plugin->nickservidentifyregexp,
+
+ 'autojoin.channels' => $this->plugin->channels,
+
+ 'statusnet.messagecallback' => array($this, 'handle_irc_message'),
+ 'statusnet.regcallback' => array($this, 'handle_reg_response'),
+ 'statusnet.connectedcallback' => array($this, 'handle_connected'),
+ 'statusnet.unregregexp' => $this->plugin->unregregexp,
+ 'statusnet.regregexp' => $this->plugin->regregexp
+ )
+ );
+
+ $this->conn->setConfig($config);
+ $this->conn->connect();
+ $this->lastPing = time();
+ $this->lastMessage = time();
+ }
+ return $this->conn;
+ }
+
+ /**
+ * Called via a callback when a message is received
+ * Passes it back to the queuing system
+ *
+ * @param array $data Data
+ * @return boolean
+ */
+ public function handle_irc_message($data) {
+ $this->plugin->enqueueIncomingRaw($data);
+ return true;
+ }
+
+ /**
+ * Called via a callback when NickServ responds to
+ * the bots query asking if a nick is registered
+ *
+ * @param array $data Data
+ * @return void
+ */
+ public function handle_reg_response($data) {
+ // Retrieve data
+ $screenname = $data['screenname'];
+ $nickdata = $this->regChecks[$screenname];
+ $usernick = $nickdata['user']->nickname;
+
+ if (isset($this->regChecksLookup[$usernick])) {
+ if ($data['registered']) {
+ // Send message
+ $this->plugin->sendConfirmationCode($screenname, $nickdata['code'], $nickdata['user'], true);
+ } else {
+ // TRANS: Message given when using an unregistered IRC nickname.
+ $this->plugin->sendMessage($screenname, _m('Your nickname is not registered so IRC connectivity cannot be enabled.'));
+
+ $confirm = new Confirm_address();
+
+ $confirm->user_id = $user->id;
+ $confirm->address_type = $this->plugin->transport;
+
+ if ($confirm->find(true)) {
+ $result = $confirm->delete();
+
+ if (!$result) {
+ common_log_db_error($confirm, 'DELETE', __FILE__);
+ // TRANS: Server error thrown on database error when deleting IRC nickname confirmation.
+ $this->serverError(_m('Could not delete confirmation.'));
+ return;
+ }
+ }
+ }
+
+ // Unset lookup value
+ unset($this->regChecksLookup[$usernick]);
+
+ // Unset data
+ unset($this->regChecks[$screename]);
+ }
+ }
+
+ /**
+ * Called when the connection is established
+ *
+ * @return void
+ */
+ public function handle_connected() {
+ $this->connected = true;
+ }
+
+ /**
+ * Enters a message into the database for sending when ready
+ *
+ * @param string $command Command
+ * @param array $args Arguments
+ * @return boolean
+ */
+ protected function enqueue_waiting_message($data) {
+ $wm = new Irc_waiting_message();
+
+ $wm->data = serialize($data);
+ $wm->prioritise = $data['prioritise'];
+ $wm->attempts = 0;
+ $wm->created = common_sql_now();
+ $result = $wm->insert();
+
+ if (!$result) {
+ common_log_db_error($wm, 'INSERT', __FILE__);
+ // TRANS: Server exception thrown when an IRC waiting queue item could not be added to the database.
+ throw new ServerException(_m('Database error inserting IRC waiting queue item.'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Send a message using the daemon
+ *
+ * @param $data Message data
+ * @return boolean true on success
+ */
+ public function send_raw_message($data) {
+ $this->connect();
+ if (!$this->conn) {
+ return false;
+ }
+
+ if ($data['type'] != 'delayedmessage') {
+ if ($data['type'] != 'message') {
+ // Nick checking
+ $nickdata = $data['nickdata'];
+ $usernick = $nickdata['user']->nickname;
+ $screenname = $nickdata['screenname'];
+
+ // Cancel any existing checks for this user
+ if (isset($this->regChecksLookup[$usernick])) {
+ unset($this->regChecks[$this->regChecksLookup[$usernick]]);
+ }
+
+ $this->regChecks[$screenname] = $nickdata;
+ $this->regChecksLookup[$usernick] = $screenname;
+ }
+
+ // If there is a backlog or we need to wait, queue the message
+ if ($this->messageWaiting || time() - $this->lastMessage < 1) {
+ $this->enqueue_waiting_message(
+ array(
+ 'type' => 'delayedmessage',
+ 'prioritise' => $data['prioritise'],
+ 'data' => $data['data']
+ )
+ );
+ $this->messageWaiting = true;
+ return true;
+ }
+ }
+
+ try {
+ $this->conn->send($data['data']['command'], $data['data']['args']);
+ } catch (Phergie_Driver_Exception $e) {
+ $this->connected = false;
+ $this->conn->reconnect();
+ return false;
+ }
+
+ $this->lastMessage = time();
+ return true;
+ }
+
+ /**
+ * Sends a ping
+ *
+ * @return void
+ */
+ protected function sendPing() {
+ $this->lastPing = time();
+ $this->conn->send('PING', $this->lastPing);
+ }
+}
require_once(INSTALLDIR.'/plugins/LdapCommon/LdapCommon.php');
return false;
}
+
+ return parent::onAutoload($cls);
}
function onEndShowPageNotice($action)
require_once(INSTALLDIR.'/plugins/LdapCommon/LdapCommon.php');
return false;
}
+
+ return parent::onAutoload($cls);
}
//---interface implementation---//
function onAutoload($cls)
{
+ // we've added an extra include-path in the beginning of this file
switch ($cls)
{
case 'MemcacheSchemaCache':
require_once 'Net/LDAP2/Entry.php';
return false;
}
+
+ return parent::onAutoload($cls);
}
function get_ldap_config(){
return true;
}
- /**
- * Autoloader
- *
- * Loads our classes if they're requested.
- *
- * @param string $cls Class requested
- *
- * @return boolean hook return
- */
- function onAutoload($cls)
- {
- $lower = strtolower($cls);
- switch ($lower)
- {
- case 'oembedproxyaction':
- require_once dirname(__FILE__) . '/' . $lower . '.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Hook for RouterInitialized event.
*
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * StatusNet-only extensions to the Twitter-like API
+ *
+ * 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/>.
+ *
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Oembed proxy implementation
+ *
+ * This class provides an interface for our JS-side code to pull info on
+ * links from other sites, using either native oEmbed, our own custom
+ * handlers, or the noembed.com offsite proxy service as configured.
+ *
+ * @category oEmbed
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class OembedproxyAction extends OembedAction
+{
+ function handle($args)
+ {
+ // Trigger short error responses; not a human-readable web page.
+ StatusNet::setApi(true);
+
+ // We're not a general oEmbed proxy service; limit to valid sessions.
+ $token = $this->trimmed('token');
+ if (!$token || $token != common_session_token()) {
+ // TRANS: Client error displayed when the session token does not match or is not given.
+ $this->clientError(_m('There was a problem with your session token. '.
+ 'Try again, please.'));
+ }
+
+ $format = $this->arg('format');
+ if ($format && $format != 'json') {
+ // TRANS: Client exception thrown when requesting a different format than JSON.
+ throw new ClientException(_m('Invalid format; only JSON supported.'));
+ }
+
+ $url = $this->arg('url');
+ if (!common_valid_http_url($url)) {
+ // TRANS: Client exception thrown when not providing a valid URL.
+ throw new ClientException(_m('Invalid URL.'));
+ }
+
+ $params = array();
+ if ($this->arg('maxwidth')) {
+ $params['maxwidth'] = $this->arg('maxwidth');
+ }
+ if ($this->arg('maxheight')) {
+ $params['maxheight'] = $this->arg('maxheight');
+ }
+
+ $data = oEmbedHelper::getObject($url, $params);
+
+ $this->init_document('json');
+ print json_encode($data);
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * StatusNet-only extensions to the Twitter-like API
- *
- * 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/>.
- *
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * Oembed proxy implementation
- *
- * This class provides an interface for our JS-side code to pull info on
- * links from other sites, using either native oEmbed, our own custom
- * handlers, or the noembed.com offsite proxy service as configured.
- *
- * @category oEmbed
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class OembedproxyAction extends OembedAction
-{
- function handle($args)
- {
- // Trigger short error responses; not a human-readable web page.
- StatusNet::setApi(true);
-
- // We're not a general oEmbed proxy service; limit to valid sessions.
- $token = $this->trimmed('token');
- if (!$token || $token != common_session_token()) {
- // TRANS: Client error displayed when the session token does not match or is not given.
- $this->clientError(_m('There was a problem with your session token. '.
- 'Try again, please.'));
- }
-
- $format = $this->arg('format');
- if ($format && $format != 'json') {
- // TRANS: Client exception thrown when requesting a different format than JSON.
- throw new ClientException(_m('Invalid format; only JSON supported.'));
- }
-
- $url = $this->arg('url');
- if (!common_valid_http_url($url)) {
- // TRANS: Client exception thrown when not providing a valid URL.
- throw new ClientException(_m('Invalid URL.'));
- }
-
- $params = array();
- if ($this->arg('maxwidth')) {
- $params['maxwidth'] = $this->arg('maxwidth');
- }
- if ($this->arg('maxheight')) {
- $params['maxheight'] = $this->arg('maxheight');
- }
-
- $data = oEmbedHelper::getObject($url, $params);
-
- $this->init_document('json');
- print json_encode($data);
- }
-}
return true;
}
- /**
- * Hook for autoloading classes
- *
- * This makes sure our classes get autoloaded from our directory
- *
- * @param string $cls name of class being used
- *
- * @return boolean event handler return
- */
- function onAutoload($cls)
- {
- switch ($cls)
- {
- case 'AllmapAction':
- case 'UsermapAction':
- case 'MapAction':
- include_once INSTALLDIR.'/plugins/Mapstraction/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Hook for adding extra JavaScript
*
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a map of user's friends' notices
+ *
+ * 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 Mapstraction
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Show a map of user's notices
+ *
+ * @category Mapstraction
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class AllmapAction extends MapAction
+{
+ function prepare($args)
+ {
+ if (parent::prepare($args)) {
+ $cur = common_current_user();
+ $stream = new InboxNoticeStream($this->user, $cur->getProfile());
+ $this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
+ NOTICES_PER_PAGE + 1,
+ null,
+ null);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ function title()
+ {
+ $base = $this->profile->getFancyName();
+
+ if ($this->page == 1) {
+ // TRANS: Page title.
+ // TRANS: %s is a user nickname.
+ return sprintf(_m("%s friends map"),
+ $base);
+ } else {
+ // @todo CHECKME: does this even happen? May not be needed.
+ // TRANS: Page title.
+ // TRANS: %1$s is a user nickname, %2$d is a page number.
+ return sprintf(_m('%1$s friends map, page %2$d'),
+ $base,
+ $this->page);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a map of user's notices
+ *
+ * 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 Mapstraction
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009-2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Show a map of notices
+ *
+ * @category Mapstraction
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class MapAction extends Action
+{
+ var $profile = null;
+ var $page = null;
+ var $notices = null;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $nickname_arg = $this->arg('nickname');
+ $nickname = Nickname::normalize($nickname_arg);
+
+ // Permanent redirect on non-canonical nickname
+
+ if ($nickname_arg != $nickname) {
+ $args = array('nickname' => $nickname);
+ if ($this->arg('page') && $this->arg('page') != 1) {
+ $args['page'] = $this->arg['page'];
+ }
+ common_redirect(common_local_url($this->trimmed('action'), $args), 301);
+ return false;
+ }
+
+ $this->user = User::getKV('nickname', $nickname);
+
+ if (!$this->user) {
+ // TRANS: Client error displayed when referring to a non-existing user.
+ $this->clientError(_m('No such user.'), 404);
+ return false;
+ }
+
+ $this->profile = $this->user->getProfile();
+
+ if (!$this->profile) {
+ // TRANS: Error message displayed when referring to a user without a profile.
+ $this->serverError(_m('User has no profile.'));
+ return false;
+ }
+
+ $page = $this->trimmed('page');
+
+ if (!empty($page) && Validate::number($page)) {
+ $this->page = $page+0;
+ } else {
+ $this->page = 1;
+ }
+
+ $this->notices = empty($this->tag)
+ ? $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1)
+ : $this->user->getTaggedNotices($this->tag, ($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1, 0, 0, null);
+
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showPage();
+ }
+
+ function showContent()
+ {
+ $this->element('div', array('id' => 'map_canvas',
+ 'class' => 'gray smallmap',
+ 'style' => "width: 100%; height: 400px"));
+ }
+
+ /**
+ * Hook for adding extra JavaScript
+ *
+ * @param Action $action Action object for the page
+ *
+ * @return boolean event handler return
+ */
+ function showScripts()
+ {
+ parent::showScripts();
+ $jsonArray = array();
+
+ while ($this->notice->fetch()) {
+ if (!empty($this->notice->lat) && !empty($this->notice->lon)) {
+ $jsonNotice = $this->noticeAsJson($this->notice);
+ $jsonArray[] = $jsonNotice;
+ }
+ }
+
+ $this->inlineScript('$(document).ready(function() { '.
+ ' var _notices = ' . json_encode($jsonArray).'; ' .
+ 'showMapstraction($("#map_canvas"), _notices); });');
+
+ return true;
+ }
+
+ function noticeAsJson($notice)
+ {
+ // FIXME: this code should be abstracted to a neutral third
+ // party, like Notice::asJson(). I'm not sure of the ethics
+ // of refactoring from within a plugin, so I'm just abusing
+ // the ApiAction method. Don't do this unless you're me!
+
+ $act = new ApiAction('/dev/null');
+
+ $arr = $act->twitterStatusArray($notice, true);
+ $arr['url'] = $notice->bestUrl();
+ $arr['html'] = $notice->rendered;
+ $arr['source'] = $arr['source'];
+
+ if (!empty($notice->reply_to)) {
+ $reply_to = Notice::getKV('id', $notice->reply_to);
+ if (!empty($reply_to)) {
+ $arr['in_reply_to_status_url'] = $reply_to->bestUrl();
+ }
+ $reply_to = null;
+ }
+
+ $profile = $notice->getProfile();
+ $arr['user']['profile_url'] = $profile->profileurl;
+
+ return $arr;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a map of user's notices
+ *
+ * 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 Mapstraction
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Show a map of user's notices
+ *
+ * @category Mapstraction
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class UsermapAction extends MapAction
+{
+ function prepare($args)
+ {
+ if(parent::prepare($args)) {
+ $this->notice = empty($this->tag)
+ ? $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1)
+ : $this->user->getTaggedNotices($this->tag, ($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1, 0, 0, null);
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+ function title()
+ {
+ $base = $this->profile->getFancyName();
+
+ if ($this->page == 1) {
+ // TRANS: Title for map widget.
+ // TRANS: %s is a user name.
+ return sprintf(_m('%s map'),$base);
+ } else {
+ // @todo CHECKME: Is the part ", page %2$d" relevant here?
+ // TRANS: Title for map widget.
+ // TRANS: %1$s is a user name, %2$d is a page nember.
+ return sprintf(_m("%1$s map, page %2$d"),
+ $base,
+ $this->page);
+ }
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Show a map of user's friends' notices
- *
- * 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 Mapstraction
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Show a map of user's notices
- *
- * @category Mapstraction
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class AllmapAction extends MapAction
-{
- function prepare($args)
- {
- if (parent::prepare($args)) {
- $cur = common_current_user();
- $stream = new InboxNoticeStream($this->user, $cur->getProfile());
- $this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
- NOTICES_PER_PAGE + 1,
- null,
- null);
- return true;
- } else {
- return false;
- }
- }
-
- function title()
- {
- $base = $this->profile->getFancyName();
-
- if ($this->page == 1) {
- // TRANS: Page title.
- // TRANS: %s is a user nickname.
- return sprintf(_m("%s friends map"),
- $base);
- } else {
- // @todo CHECKME: does this even happen? May not be needed.
- // TRANS: Page title.
- // TRANS: %1$s is a user nickname, %2$d is a page number.
- return sprintf(_m('%1$s friends map, page %2$d'),
- $base,
- $this->page);
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Show a map of user's notices
- *
- * 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 Mapstraction
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2009-2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Show a map of notices
- *
- * @category Mapstraction
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class MapAction extends Action
-{
- var $profile = null;
- var $page = null;
- var $notices = null;
-
- function prepare($args)
- {
- parent::prepare($args);
-
- $nickname_arg = $this->arg('nickname');
- $nickname = Nickname::normalize($nickname_arg);
-
- // Permanent redirect on non-canonical nickname
-
- if ($nickname_arg != $nickname) {
- $args = array('nickname' => $nickname);
- if ($this->arg('page') && $this->arg('page') != 1) {
- $args['page'] = $this->arg['page'];
- }
- common_redirect(common_local_url($this->trimmed('action'), $args), 301);
- return false;
- }
-
- $this->user = User::getKV('nickname', $nickname);
-
- if (!$this->user) {
- // TRANS: Client error displayed when referring to a non-existing user.
- $this->clientError(_m('No such user.'), 404);
- return false;
- }
-
- $this->profile = $this->user->getProfile();
-
- if (!$this->profile) {
- // TRANS: Error message displayed when referring to a user without a profile.
- $this->serverError(_m('User has no profile.'));
- return false;
- }
-
- $page = $this->trimmed('page');
-
- if (!empty($page) && Validate::number($page)) {
- $this->page = $page+0;
- } else {
- $this->page = 1;
- }
-
- $this->notices = empty($this->tag)
- ? $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1)
- : $this->user->getTaggedNotices($this->tag, ($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1, 0, 0, null);
-
- return true;
- }
-
- function handle($args)
- {
- parent::handle($args);
- $this->showPage();
- }
-
- function showContent()
- {
- $this->element('div', array('id' => 'map_canvas',
- 'class' => 'gray smallmap',
- 'style' => "width: 100%; height: 400px"));
- }
-
- /**
- * Hook for adding extra JavaScript
- *
- * @param Action $action Action object for the page
- *
- * @return boolean event handler return
- */
- function showScripts()
- {
- parent::showScripts();
- $jsonArray = array();
-
- while ($this->notice->fetch()) {
- if (!empty($this->notice->lat) && !empty($this->notice->lon)) {
- $jsonNotice = $this->noticeAsJson($this->notice);
- $jsonArray[] = $jsonNotice;
- }
- }
-
- $this->inlineScript('$(document).ready(function() { '.
- ' var _notices = ' . json_encode($jsonArray).'; ' .
- 'showMapstraction($("#map_canvas"), _notices); });');
-
- return true;
- }
-
- function noticeAsJson($notice)
- {
- // FIXME: this code should be abstracted to a neutral third
- // party, like Notice::asJson(). I'm not sure of the ethics
- // of refactoring from within a plugin, so I'm just abusing
- // the ApiAction method. Don't do this unless you're me!
-
- $act = new ApiAction('/dev/null');
-
- $arr = $act->twitterStatusArray($notice, true);
- $arr['url'] = $notice->bestUrl();
- $arr['html'] = $notice->rendered;
- $arr['source'] = $arr['source'];
-
- if (!empty($notice->reply_to)) {
- $reply_to = Notice::getKV('id', $notice->reply_to);
- if (!empty($reply_to)) {
- $arr['in_reply_to_status_url'] = $reply_to->bestUrl();
- }
- $reply_to = null;
- }
-
- $profile = $notice->getProfile();
- $arr['user']['profile_url'] = $profile->profileurl;
-
- return $arr;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Show a map of user's notices
- *
- * 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 Mapstraction
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Show a map of user's notices
- *
- * @category Mapstraction
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class UsermapAction extends MapAction
-{
- function prepare($args)
- {
- if(parent::prepare($args)) {
- $this->notice = empty($this->tag)
- ? $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1)
- : $this->user->getTaggedNotices($this->tag, ($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1, 0, 0, null);
- return true;
- }else{
- return false;
- }
- }
-
- function title()
- {
- $base = $this->profile->getFancyName();
-
- if ($this->page == 1) {
- // TRANS: Title for map widget.
- // TRANS: %s is a user name.
- return sprintf(_m('%s map'),$base);
- } else {
- // @todo CHECKME: Is the part ", page %2$d" relevant here?
- // TRANS: Title for map widget.
- // TRANS: %1$s is a user name, %2$d is a page nember.
- return sprintf(_m("%1$s map, page %2$d"),
- $base,
- $this->page);
- }
- }
-}
return true;
}
- function onAutoload($cls)
- {
- switch ($cls)
- {
- case 'MinifyAction':
- require_once(INSTALLDIR.'/plugins/Minify/' . strtolower(mb_substr($cls, 0, -6)) . '.php');
- return false;
- default:
- return true;
- }
- }
-
function onLoginAction($action, &$login)
{
switch ($action)
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+class MinifyAction extends Action
+{
+ const TYPE_CSS = 'text/css';
+ const TYPE_HTML = 'text/html';
+ // there is some debate over the ideal JS Content-Type, but this is the
+ // Apache default and what Yahoo! uses..
+ const TYPE_JS = 'application/x-javascript';
+
+ var $file;
+ var $v;
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $this->v = $args['v'];
+
+ $f = $this->arg('f');
+ if(isset($f)) {
+ $this->file = INSTALLDIR.'/'.$f;
+ if(file_exists($this->file)) {
+ return true;
+ } else {
+ // TRANS: Client error displayed when not providing a valid path in parameter "f".
+ $this->clientError(_m('The parameter "f" is not a valid path.'),404);
+ return false;
+ }
+ }else{
+ // TRANS: Client error displayed when not providing parameter "f".
+ $this->clientError(_m('The parameter "f" is required but missing.'),500);
+ return false;
+ }
+ }
+
+ function etag()
+ {
+ if(isset($this->v)) {
+ return "\"" . crc32($this->file . $this->v) . "\"";
+ }else{
+ $stat = stat($this->file);
+ return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
+ }
+ }
+
+ function lastModified()
+ {
+ return filemtime($this->file);
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ $c = Cache::instance();
+ if (!empty($c)) {
+ $cacheKey = Cache::key(MinifyPlugin::cacheKey . ':' . $this->file . '?v=' . empty($this->v)?'':$this->v);
+ $out = $c->get($cacheKey);
+ }
+ if(empty($out)) {
+ $out = $this->minify($this->file);
+ }
+ if (!empty($c)) {
+ $c->set($cacheKey, $out);
+ }
+
+ $sec = session_cache_expire() * 60;
+ header('Cache-Control: public, max-age=' . $sec);
+ header('Pragma: public');
+ $this->raw($out);
+ }
+
+ function minify($file)
+ {
+ $info = pathinfo($file);
+ switch(strtolower($info['extension'])){
+ case 'js':
+ $out = MinifyPlugin::minifyJs(file_get_contents($file));
+ header('Content-Type: ' . self::TYPE_JS);
+ break;
+ case 'css':
+ $options = array();
+ $options['currentDir'] = dirname($file);
+ $options['docRoot'] = INSTALLDIR;
+ $out = MinifyPlugin::minifyCss(file_get_contents($file),$options);
+ header('Content-Type: ' . self::TYPE_CSS);
+ break;
+ default:
+ // TRANS: Client error displayed when trying to minify an unsupported file type.
+ $this->clientError(_m('File type not supported.'),500);
+ return false;
+ }
+ return $out;
+ }
+}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-class MinifyAction extends Action
-{
- const TYPE_CSS = 'text/css';
- const TYPE_HTML = 'text/html';
- // there is some debate over the ideal JS Content-Type, but this is the
- // Apache default and what Yahoo! uses..
- const TYPE_JS = 'application/x-javascript';
-
- var $file;
- var $v;
-
- function isReadOnly($args)
- {
- return true;
- }
-
- function prepare($args)
- {
- parent::prepare($args);
- $this->v = $args['v'];
-
- $f = $this->arg('f');
- if(isset($f)) {
- $this->file = INSTALLDIR.'/'.$f;
- if(file_exists($this->file)) {
- return true;
- } else {
- // TRANS: Client error displayed when not providing a valid path in parameter "f".
- $this->clientError(_m('The parameter "f" is not a valid path.'),404);
- return false;
- }
- }else{
- // TRANS: Client error displayed when not providing parameter "f".
- $this->clientError(_m('The parameter "f" is required but missing.'),500);
- return false;
- }
- }
-
- function etag()
- {
- if(isset($this->v)) {
- return "\"" . crc32($this->file . $this->v) . "\"";
- }else{
- $stat = stat($this->file);
- return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"';
- }
- }
-
- function lastModified()
- {
- return filemtime($this->file);
- }
-
- function handle($args)
- {
- parent::handle($args);
-
- $c = Cache::instance();
- if (!empty($c)) {
- $cacheKey = Cache::key(MinifyPlugin::cacheKey . ':' . $this->file . '?v=' . empty($this->v)?'':$this->v);
- $out = $c->get($cacheKey);
- }
- if(empty($out)) {
- $out = $this->minify($this->file);
- }
- if (!empty($c)) {
- $c->set($cacheKey, $out);
- }
-
- $sec = session_cache_expire() * 60;
- header('Cache-Control: public, max-age=' . $sec);
- header('Pragma: public');
- $this->raw($out);
- }
-
- function minify($file)
- {
- $info = pathinfo($file);
- switch(strtolower($info['extension'])){
- case 'js':
- $out = MinifyPlugin::minifyJs(file_get_contents($file));
- header('Content-Type: ' . self::TYPE_JS);
- break;
- case 'css':
- $options = array();
- $options['currentDir'] = dirname($file);
- $options['docRoot'] = INSTALLDIR;
- $out = MinifyPlugin::minifyCss(file_get_contents($file),$options);
- header('Content-Type: ' . self::TYPE_CSS);
- break;
- default:
- // TRANS: Client error displayed when trying to minify an unsupported file type.
- $this->clientError(_m('File type not supported.'),500);
- return false;
- }
- return $out;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2012, StatusNet, Inc.
- *
- * ModLog.php -- data object to store moderation logs
- *
- * PHP version 5
- *
- * 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 Moderation
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Class comment here
- *
- * @category Category here
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-
-class ModLog extends Managed_DataObject
-{
- public $__table = 'mod_log'; // table name
-
- public $id; // UUID
- public $profile_id; // profile id
- public $moderator_id; // profile id
- public $role; // the role
- public $grant; // 1 = grant, 0 = revoke
- public $created; // datetime
-
- /**
- * The One True Thingy that must be defined and declared.
- */
- public static function schemaDef()
- {
- return array('description' => 'Log of moderation events',
- 'fields' => array(
- 'id' => array('type' => 'varchar',
- 'length' => 36,
- 'not null' => true,
- 'description' => 'unique event ID'),
- 'profile_id' => array('type' => 'int',
- 'not null' => true,
- 'description' => 'profile getting the role'),
- 'moderator_id' => array('type' => 'int',
- 'description' => 'profile granting or revoking the role'),
- 'role' => array('type' => 'varchar',
- 'length' => 32,
- 'not null' => true,
- 'description' => 'role granted or revoked'),
- 'is_grant' => array('type' => 'int',
- 'size' => 'tiny',
- 'default' => 1,
- 'description' => 'Was this a grant or revocation of a role'),
- 'created' => array('type' => 'datetime',
- 'not null' => true,
- 'description' => 'date this record was created')
- ),
- 'primary key' => array('id'),
- 'foreign keys' => array(
- 'mod_log_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
- 'mod_log_moderator_id_fkey' => array('user', array('user_id' => 'id'))
- ),
- 'indexes' => array(
- 'mod_log_profile_id_created_idx' => array('profile_id', 'created'),
- ),
- );
- }
-}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
-
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'ModLog':
- include_once $dir . '/'.$cls.'.php';
- return false;
- default:
- return true;
- }
- }
-
function onEndGrantRole($profile, $role)
{
$modlog = new ModLog();
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * ModLog.php -- data object to store moderation logs
+ *
+ * PHP version 5
+ *
+ * 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 Moderation
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Class comment here
+ *
+ * @category Category here
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+
+class ModLog extends Managed_DataObject
+{
+ public $__table = 'mod_log'; // table name
+
+ public $id; // UUID
+ public $profile_id; // profile id
+ public $moderator_id; // profile id
+ public $role; // the role
+ public $grant; // 1 = grant, 0 = revoke
+ public $created; // datetime
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array('description' => 'Log of moderation events',
+ 'fields' => array(
+ 'id' => array('type' => 'varchar',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'unique event ID'),
+ 'profile_id' => array('type' => 'int',
+ 'not null' => true,
+ 'description' => 'profile getting the role'),
+ 'moderator_id' => array('type' => 'int',
+ 'description' => 'profile granting or revoking the role'),
+ 'role' => array('type' => 'varchar',
+ 'length' => 32,
+ 'not null' => true,
+ 'description' => 'role granted or revoked'),
+ 'is_grant' => array('type' => 'int',
+ 'size' => 'tiny',
+ 'default' => 1,
+ 'description' => 'Was this a grant or revocation of a role'),
+ 'created' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was created')
+ ),
+ 'primary key' => array('id'),
+ 'foreign keys' => array(
+ 'mod_log_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
+ 'mod_log_moderator_id_fkey' => array('user', array('user_id' => 'id'))
+ ),
+ 'indexes' => array(
+ 'mod_log_profile_id_created_idx' => array('profile_id', 'created'),
+ ),
+ );
+ }
+}
return true;
}
- /**
- * Autoloader
- *
- * Loads our classes if they're requested.
- *
- * @param string $cls Class requested
- *
- * @return boolean hook return
- */
- function onAutoload($cls)
- {
- switch ($cls)
- {
- case 'RemoteprofileAction':
- case 'RemoteProfileAction':
- require_once dirname(__FILE__) . '/remoteprofileaction.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Add ModPlus-related paths to the router table
*
--- /dev/null
+<?php
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+class RemoteProfileAction extends ShowstreamAction
+{
+ function prepare($args)
+ {
+ Action::prepare($args); // skip the ProfileAction code and replace it...
+
+ $id = $this->arg('id');
+ $this->user = false;
+ $this->profile = Profile::getKV('id', $id);
+
+ if (!$this->profile) {
+ // TRANS: Error message displayed when referring to a user without a profile.
+ $this->serverError(_m('User has no profile.'));
+ return false;
+ }
+
+ $user = User::getKV('id', $this->profile->id);
+ if ($user) {
+ // This is a local user -- send to their regular profile.
+ $url = common_local_url('showstream', array('nickname' => $user->nickname));
+ common_redirect($url);
+ return false;
+ }
+
+ $this->tag = $this->trimmed('tag');
+ $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
+ common_set_returnto($this->selfUrl());
+
+ $p = Profile::current();
+ if (empty($this->tag)) {
+ $stream = new ProfileNoticeStream($this->profile, $p);
+ } else {
+ $stream = new TaggedProfileNoticeStream($this->profile, $this->tag, $p);
+ }
+ $this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
+
+ return true;
+ }
+
+ function handle($args)
+ {
+ // skip yadis thingy
+ $this->showPage();
+ }
+
+ function title()
+ {
+ $base = $this->profile->getBestName();
+ $host = parse_url($this->profile->profileurl, PHP_URL_HOST);
+ // TRANS: Remote profile action page title.
+ // TRANS: %1$s is a username, %2$s is a hostname.
+ return sprintf(_m('%1$s on %2$s'), $base, $host);
+ }
+
+ /**
+ * Instead of showing notices, link to the original offsite profile.
+ */
+ function showNotices()
+ {
+ $url = $this->profile->profileurl;
+ $host = parse_url($url, PHP_URL_HOST);
+ $markdown = sprintf(
+ // TRANS: Message on remote profile page.
+ // TRANS: This message contains Markdown links in the form [description](link).
+ // TRANS: %1$s is a profile nickname, %2$s is a hostname, %3$s is a URL.
+ _m('This remote profile is registered on another site; see [%1$s\'s original profile page on %2$s](%3$s).'),
+ $this->profile->nickname,
+ $host,
+ $url);
+ $html = common_markup_to_html($markdown);
+ $this->raw($html);
+
+ if ($this->profile->hasRole(Profile_role::SILENCED)) {
+ // TRANS: Message on blocked remote profile page.
+ $markdown = _m('Site moderators have silenced this profile, which prevents delivery of new messages to any users on this site.');
+ $this->raw(common_markup_to_html($markdown));
+ }else{
+
+ $pnl = null;
+ if (Event::handle('ShowStreamNoticeList', array($this->notice, $this, &$pnl))) {
+ $pnl = new ProfileNoticeList($this->notice, $this);
+ }
+ $cnt = $pnl->show();
+ if (0 == $cnt) {
+ $this->showEmptyListMessage();
+ }
+
+ $args = array('id' => $this->profile->id);
+ if (!empty($this->tag))
+ {
+ $args['tag'] = $this->tag;
+ }
+ $this->pagination($this->page>1, $cnt>NOTICES_PER_PAGE, $this->page,
+ 'remoteprofile', $args);
+
+ }
+ }
+
+ function getFeeds()
+ {
+ // none
+ }
+
+ /**
+ * Don't do various extra stuff, and also trim some things to avoid crawlers.
+ */
+ function extraHead()
+ {
+ $this->element('meta', array('name' => 'robots',
+ 'content' => 'noindex,nofollow'));
+ }
+
+ function showLocalNav()
+ {
+ // skip
+ }
+
+ function showSections()
+ {
+ // skip
+ }
+
+ function showStatistics()
+ {
+ // skip
+ }
+}
+++ /dev/null
-<?php
-/*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
-class RemoteProfileAction extends ShowstreamAction
-{
- function prepare($args)
- {
- Action::prepare($args); // skip the ProfileAction code and replace it...
-
- $id = $this->arg('id');
- $this->user = false;
- $this->profile = Profile::getKV('id', $id);
-
- if (!$this->profile) {
- // TRANS: Error message displayed when referring to a user without a profile.
- $this->serverError(_m('User has no profile.'));
- return false;
- }
-
- $user = User::getKV('id', $this->profile->id);
- if ($user) {
- // This is a local user -- send to their regular profile.
- $url = common_local_url('showstream', array('nickname' => $user->nickname));
- common_redirect($url);
- return false;
- }
-
- $this->tag = $this->trimmed('tag');
- $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
- common_set_returnto($this->selfUrl());
-
- $p = Profile::current();
- if (empty($this->tag)) {
- $stream = new ProfileNoticeStream($this->profile, $p);
- } else {
- $stream = new TaggedProfileNoticeStream($this->profile, $this->tag, $p);
- }
- $this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
-
- return true;
- }
-
- function handle($args)
- {
- // skip yadis thingy
- $this->showPage();
- }
-
- function title()
- {
- $base = $this->profile->getBestName();
- $host = parse_url($this->profile->profileurl, PHP_URL_HOST);
- // TRANS: Remote profile action page title.
- // TRANS: %1$s is a username, %2$s is a hostname.
- return sprintf(_m('%1$s on %2$s'), $base, $host);
- }
-
- /**
- * Instead of showing notices, link to the original offsite profile.
- */
- function showNotices()
- {
- $url = $this->profile->profileurl;
- $host = parse_url($url, PHP_URL_HOST);
- $markdown = sprintf(
- // TRANS: Message on remote profile page.
- // TRANS: This message contains Markdown links in the form [description](link).
- // TRANS: %1$s is a profile nickname, %2$s is a hostname, %3$s is a URL.
- _m('This remote profile is registered on another site; see [%1$s\'s original profile page on %2$s](%3$s).'),
- $this->profile->nickname,
- $host,
- $url);
- $html = common_markup_to_html($markdown);
- $this->raw($html);
-
- if ($this->profile->hasRole(Profile_role::SILENCED)) {
- // TRANS: Message on blocked remote profile page.
- $markdown = _m('Site moderators have silenced this profile, which prevents delivery of new messages to any users on this site.');
- $this->raw(common_markup_to_html($markdown));
- }else{
-
- $pnl = null;
- if (Event::handle('ShowStreamNoticeList', array($this->notice, $this, &$pnl))) {
- $pnl = new ProfileNoticeList($this->notice, $this);
- }
- $cnt = $pnl->show();
- if (0 == $cnt) {
- $this->showEmptyListMessage();
- }
-
- $args = array('id' => $this->profile->id);
- if (!empty($this->tag))
- {
- $args['tag'] = $this->tag;
- }
- $this->pagination($this->page>1, $cnt>NOTICES_PER_PAGE, $this->page,
- 'remoteprofile', $args);
-
- }
- }
-
- function getFeeds()
- {
- // none
- }
-
- /**
- * Don't do various extra stuff, and also trim some things to avoid crawlers.
- */
- function extraHead()
- {
- $this->element('meta', array('name' => 'robots',
- 'content' => 'noindex,nofollow'));
- }
-
- function showLocalNav()
- {
- // skip
- }
-
- function showSections()
- {
- // skip
- }
-
- function showStatistics()
- {
- // skip
- }
-}
case 'MSN':\r
require_once(INSTALLDIR.'/plugins/Msn/extlib/phpmsnclass/msn.class.php');\r
return false;\r
- case 'MsnManager':\r
- case 'Msn_waiting_message':\r
- include_once $dir . '/'.strtolower($cls).'.php';\r
- return false;\r
- default:\r
- return true;\r
}\r
+\r
+ return parent::onAutoload($cls);\r
}\r
\r
/*\r
--- /dev/null
+<?php\r
+/**\r
+ * Table Definition for msn_waiting_message\r
+ */\r
+require_once INSTALLDIR.'/classes/Memcached_DataObject.php';\r
+\r
+class Msn_waiting_message extends Managed_DataObject {\r
+\r
+ public $__table = 'msn_waiting_message'; // table name\r
+ public $id; // int primary_key not_null auto_increment\r
+ public $screenname; // varchar(255) not_null\r
+ public $message; // text not_null\r
+ public $claimed; // datetime()\r
+ public $created; // datetime() not_null\r
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP\r
+\r
+ public static function schemaDef()\r
+ {\r
+ return array(\r
+ 'fields' => array(\r
+ 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique ID for entry'),\r
+ 'screenname' => array('type' => 'varchar', 'length' => 255, 'description' => 'from screenname'),\r
+ 'message' => array('type' => 'text', 'not null' => true, 'description' => 'MSN message text'),\r
+ 'claimed' => array('type' => 'datetime', 'description' => 'date this irc message was claimed'),\r
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),\r
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),\r
+ ),\r
+ 'primary key' => array('id'),\r
+ 'indexes' => array(\r
+ 'msn_waiting_message_prioritise_idx' => array('screenname'),\r
+ ),\r
+ );\r
+ }\r
+\r
+ /**\r
+ * @param string $screenname screenname or array of screennames to pull from\r
+ * If not specified, checks all queues in the system.\r
+ */\r
+ public static function top($screenname = null) {\r
+ $wm = new Msn_waiting_message();\r
+ if ($screenname) {\r
+ if (is_array($screenname)) {\r
+ // @fixme use safer escaping\r
+ $list = implode("','", array_map('addslashes', $screenname));\r
+ $wm->whereAdd("screenname in ('$list')");\r
+ } else {\r
+ $wm->screenname = $screenname;\r
+ }\r
+ }\r
+ $wm->orderBy('created');\r
+ $wm->whereAdd('claimed is null');\r
+\r
+ $wm->limit(1);\r
+\r
+ $cnt = $wm->find(true);\r
+\r
+ if ($cnt) {\r
+ // XXX: potential race condition\r
+ // can we force it to only update if claimed is still null\r
+ // (or old)?\r
+ common_log(LOG_INFO, 'claiming msn waiting message id = ' . $wm->id);\r
+ $orig = clone($wm);\r
+ $wm->claimed = common_sql_now();\r
+ $result = $wm->update($orig);\r
+ if ($result) {\r
+ common_log(LOG_INFO, 'claim succeeded.');\r
+ return $wm;\r
+ } else {\r
+ common_log(LOG_INFO, 'claim failed.');\r
+ }\r
+ }\r
+ $wm = null;\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Release a claimed item.\r
+ */\r
+ public function releaseClaim() {\r
+ // DB_DataObject doesn't let us save nulls right now\r
+ $sql = sprintf("UPDATE msn_waiting_message SET claimed=NULL WHERE id=%d", $this->id);\r
+ $this->query($sql);\r
+\r
+ $this->claimed = null;\r
+ $this->encache();\r
+ }\r
+}\r
--- /dev/null
+<?php\r
+/*\r
+ * StatusNet - the distributed open-source microblogging tool\r
+ * Copyright (C) 2008, 2009, StatusNet, Inc.\r
+ *\r
+ * This program is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU Affero General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU Affero General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Affero General Public License\r
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+\r
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\r
+\r
+/**\r
+ * MSN background connection manager for MSN-using queue handlers,\r
+ * allowing them to send outgoing messages on the right connection.\r
+ *\r
+ * Input is handled during socket select loop, keepalive pings during idle.\r
+ * Any incoming messages will be handled.\r
+ *\r
+ * In a multi-site queuedaemon.php run, one connection will be instantiated\r
+ * for each site being handled by the current process that has MSN enabled.\r
+ */\r
+class MsnManager extends ImManager {\r
+ public $conn = null;\r
+ protected $lastPing = null;\r
+ protected $pingInterval;\r
+\r
+ /**\r
+ * Initialise connection to server.\r
+ *\r
+ * @return boolean true on success\r
+ */\r
+ public function start($master) {\r
+ if (parent::start($master)) {\r
+ $this->requeue_waiting_messages();\r
+ $this->connect();\r
+ return true;\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Return any open sockets that the run loop should listen\r
+ * for input on.\r
+ *\r
+ * @return array Array of socket resources\r
+ */\r
+ public function getSockets() {\r
+ $this->connect();\r
+ if ($this->conn) {\r
+ return $this->conn->getSockets();\r
+ } else {\r
+ return array();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Idle processing for io manager's execution loop.\r
+ * Send keepalive pings to server.\r
+ *\r
+ * @return void\r
+ */\r
+ public function idle($timeout = 0) {\r
+ if (empty($this->lastPing) || time() - $this->lastPing > $this->pingInterval) {\r
+ $this->send_ping();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Message pump is triggered on socket input, so we only need an idle()\r
+ * call often enough to trigger our outgoing pings.\r
+ */\r
+ public function timeout() {\r
+ return $this->pingInterval;\r
+ }\r
+\r
+ /**\r
+ * Process MSN events that have come in over the wire.\r
+ *\r
+ * @param resource $socket Socket ready\r
+ * @return void\r
+ */\r
+ public function handleInput($socket) {\r
+ common_log(LOG_DEBUG, 'Servicing the MSN queue.');\r
+ $this->stats('msn_process');\r
+ $this->conn->receive();\r
+ }\r
+\r
+ /**\r
+ * Initiate connection\r
+ *\r
+ * @return void\r
+ */\r
+ public function connect() {\r
+ if (!$this->conn) {\r
+ $this->conn = new MSN(\r
+ array(\r
+ 'user' => $this->plugin->user,\r
+ 'password' => $this->plugin->password,\r
+ 'alias' => $this->plugin->nickname,\r
+ // TRANS: MSN bot status message.\r
+ 'psm' => _m('Send me a message to post a notice'),\r
+ 'debug' => false\r
+ )\r
+ );\r
+ $this->conn->registerHandler('IMin', array($this, 'handle_msn_message'));\r
+ $this->conn->registerHandler('SessionReady', array($this, 'handle_session_ready'));\r
+ $this->conn->registerHandler('Pong', array($this, 'update_ping_time'));\r
+ $this->conn->registerHandler('ConnectFailed', array($this, 'handle_connect_failed'));\r
+ $this->conn->registerHandler('Reconnect', array($this, 'handle_reconnect'));\r
+ $this->conn->signon();\r
+ $this->lastPing = time();\r
+ }\r
+ return $this->conn;\r
+ }\r
+\r
+ /**\r
+ * Called by the idle process to send a ping\r
+ * when necessary\r
+ *\r
+ * @return void\r
+ */\r
+ protected function send_ping() {\r
+ $this->connect();\r
+ if (!$this->conn) {\r
+ return false;\r
+ }\r
+\r
+ $this->conn->sendPing();\r
+ $this->lastPing = time();\r
+ $this->pingInterval = 50;\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Update the time till the next ping\r
+ *\r
+ * @param $data Time till next ping\r
+ * @return void\r
+ */\r
+ public function update_ping_time($data) {\r
+ $this->pingInterval = $data;\r
+ }\r
+\r
+ /**\r
+ * Called via a callback when a message is received\r
+ *\r
+ * Passes it back to the queuing system\r
+ *\r
+ * @param array $data Data\r
+ * @return boolean\r
+ */\r
+ public function handle_msn_message($data) {\r
+ $this->plugin->enqueueIncomingRaw($data);\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Called via a callback when a session becomes ready\r
+ *\r
+ * @param array $data Data\r
+ */\r
+ public function handle_session_ready($data) {\r
+ $sessionFailed = false;\r
+ $wm = Msn_waiting_message::top($data['to']);\r
+ while ($wm != NULL) {\r
+ if ($sessionFailed) {\r
+ $this->plugin->sendMessage($wm->screenname, $wm->message);\r
+ $sessionFailed = true;\r
+ } elseif (!$this->conn->sendMessage($wm->screenname, $wm->message, $ignore)) {\r
+ $this->plugin->sendMessage($wm->screenname, $wm->message);\r
+ }\r
+\r
+ $wm->delete();\r
+ $wm = Msn_waiting_message::top($data['to']);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Requeue messages from the waiting table so we try\r
+ * to send them again\r
+ *\r
+ * @return void\r
+ */\r
+ protected function requeue_waiting_messages() {\r
+ $wm = Msn_waiting_message::top();\r
+ while ($wm != NULL) {\r
+ $this->plugin->sendMessage($wm->screenname, $wm->message);\r
+ $wm->delete();\r
+ $wm = Msn_waiting_message::top();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Called by callback to log failure during connect\r
+ *\r
+ * @param string $message error message reported\r
+ * @return void\r
+ */\r
+ public function handle_connect_failed($message) {\r
+ common_log(LOG_NOTICE, 'MSN connect failed, retrying: ' . $message);\r
+ }\r
+\r
+ /**\r
+ * Called by callback to log reconnection\r
+ *\r
+ * @param void $data Not used (there to keep callback happy)\r
+ * @return void\r
+ */\r
+ public function handle_reconnect($data) {\r
+ common_log(LOG_NOTICE, 'MSN reconnecting');\r
+ // Requeue messages waiting in the DB\r
+ $this->requeue_waiting_messages();\r
+ }\r
+\r
+ /**\r
+ * Enters a message into the database for sending via a callback\r
+ * when the session is established\r
+ *\r
+ * @param string $to Intended recipient\r
+ * @param string $message Message\r
+ */\r
+ protected function enqueue_waiting_message($to, $message) {\r
+ $wm = new Msn_waiting_message();\r
+\r
+ $wm->screenname = $to;\r
+ $wm->message = $message;\r
+ $wm->created = common_sql_now();\r
+ $result = $wm->insert();\r
+\r
+ if (!$result) {\r
+ common_log_db_error($wm, 'INSERT', __FILE__);\r
+ // TRANS: Server exception thrown when a message to be sent through MSN cannot be added to the database queue.\r
+ throw new ServerException(_m('Database error inserting queue item.'));\r
+ }\r
+\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Send a message using the daemon\r
+ *\r
+ * @param $data Message data\r
+ * @return boolean true on success\r
+ */\r
+ public function send_raw_message($data) {\r
+ $this->connect();\r
+ if (!$this->conn) {\r
+ return false;\r
+ }\r
+\r
+ $waitForSession = false;\r
+ if (!$this->conn->sendMessage($data['to'], $data['message'], $waitForSession)) {\r
+ if ($waitForSession) {\r
+ $this->enqueue_waiting_message($data['to'], $data['message']);\r
+ } else {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ // Sending a command updates the time till next ping\r
+ $this->lastPing = time();\r
+ $this->pingInterval = 50;\r
+ return true;\r
+ }\r
+}\r
+++ /dev/null
-<?php\r
-/**\r
- * Table Definition for msn_waiting_message\r
- */\r
-require_once INSTALLDIR.'/classes/Memcached_DataObject.php';\r
-\r
-class Msn_waiting_message extends Managed_DataObject {\r
-\r
- public $__table = 'msn_waiting_message'; // table name\r
- public $id; // int primary_key not_null auto_increment\r
- public $screenname; // varchar(255) not_null\r
- public $message; // text not_null\r
- public $claimed; // datetime()\r
- public $created; // datetime() not_null\r
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP\r
-\r
- public static function schemaDef()\r
- {\r
- return array(\r
- 'fields' => array(\r
- 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'Unique ID for entry'),\r
- 'screenname' => array('type' => 'varchar', 'length' => 255, 'description' => 'from screenname'),\r
- 'message' => array('type' => 'text', 'not null' => true, 'description' => 'MSN message text'),\r
- 'claimed' => array('type' => 'datetime', 'description' => 'date this irc message was claimed'),\r
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),\r
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),\r
- ),\r
- 'primary key' => array('id'),\r
- 'indexes' => array(\r
- 'msn_waiting_message_prioritise_idx' => array('screenname'),\r
- ),\r
- );\r
- }\r
-\r
- /**\r
- * @param string $screenname screenname or array of screennames to pull from\r
- * If not specified, checks all queues in the system.\r
- */\r
- public static function top($screenname = null) {\r
- $wm = new Msn_waiting_message();\r
- if ($screenname) {\r
- if (is_array($screenname)) {\r
- // @fixme use safer escaping\r
- $list = implode("','", array_map('addslashes', $screenname));\r
- $wm->whereAdd("screenname in ('$list')");\r
- } else {\r
- $wm->screenname = $screenname;\r
- }\r
- }\r
- $wm->orderBy('created');\r
- $wm->whereAdd('claimed is null');\r
-\r
- $wm->limit(1);\r
-\r
- $cnt = $wm->find(true);\r
-\r
- if ($cnt) {\r
- // XXX: potential race condition\r
- // can we force it to only update if claimed is still null\r
- // (or old)?\r
- common_log(LOG_INFO, 'claiming msn waiting message id = ' . $wm->id);\r
- $orig = clone($wm);\r
- $wm->claimed = common_sql_now();\r
- $result = $wm->update($orig);\r
- if ($result) {\r
- common_log(LOG_INFO, 'claim succeeded.');\r
- return $wm;\r
- } else {\r
- common_log(LOG_INFO, 'claim failed.');\r
- }\r
- }\r
- $wm = null;\r
- return null;\r
- }\r
-\r
- /**\r
- * Release a claimed item.\r
- */\r
- public function releaseClaim() {\r
- // DB_DataObject doesn't let us save nulls right now\r
- $sql = sprintf("UPDATE msn_waiting_message SET claimed=NULL WHERE id=%d", $this->id);\r
- $this->query($sql);\r
-\r
- $this->claimed = null;\r
- $this->encache();\r
- }\r
-}\r
+++ /dev/null
-<?php\r
-/*\r
- * StatusNet - the distributed open-source microblogging tool\r
- * Copyright (C) 2008, 2009, StatusNet, Inc.\r
- *\r
- * This program is free software: you can redistribute it and/or modify\r
- * it under the terms of the GNU Affero General Public License as published by\r
- * the Free Software Foundation, either version 3 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU Affero General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Affero General Public License\r
- * along with this program. If not, see <http://www.gnu.org/licenses/>.\r
- */\r
-\r
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\r
-\r
-/**\r
- * MSN background connection manager for MSN-using queue handlers,\r
- * allowing them to send outgoing messages on the right connection.\r
- *\r
- * Input is handled during socket select loop, keepalive pings during idle.\r
- * Any incoming messages will be handled.\r
- *\r
- * In a multi-site queuedaemon.php run, one connection will be instantiated\r
- * for each site being handled by the current process that has MSN enabled.\r
- */\r
-class MsnManager extends ImManager {\r
- public $conn = null;\r
- protected $lastPing = null;\r
- protected $pingInterval;\r
-\r
- /**\r
- * Initialise connection to server.\r
- *\r
- * @return boolean true on success\r
- */\r
- public function start($master) {\r
- if (parent::start($master)) {\r
- $this->requeue_waiting_messages();\r
- $this->connect();\r
- return true;\r
- } else {\r
- return false;\r
- }\r
- }\r
-\r
- /**\r
- * Return any open sockets that the run loop should listen\r
- * for input on.\r
- *\r
- * @return array Array of socket resources\r
- */\r
- public function getSockets() {\r
- $this->connect();\r
- if ($this->conn) {\r
- return $this->conn->getSockets();\r
- } else {\r
- return array();\r
- }\r
- }\r
-\r
- /**\r
- * Idle processing for io manager's execution loop.\r
- * Send keepalive pings to server.\r
- *\r
- * @return void\r
- */\r
- public function idle($timeout = 0) {\r
- if (empty($this->lastPing) || time() - $this->lastPing > $this->pingInterval) {\r
- $this->send_ping();\r
- }\r
- }\r
-\r
- /**\r
- * Message pump is triggered on socket input, so we only need an idle()\r
- * call often enough to trigger our outgoing pings.\r
- */\r
- public function timeout() {\r
- return $this->pingInterval;\r
- }\r
-\r
- /**\r
- * Process MSN events that have come in over the wire.\r
- *\r
- * @param resource $socket Socket ready\r
- * @return void\r
- */\r
- public function handleInput($socket) {\r
- common_log(LOG_DEBUG, 'Servicing the MSN queue.');\r
- $this->stats('msn_process');\r
- $this->conn->receive();\r
- }\r
-\r
- /**\r
- * Initiate connection\r
- *\r
- * @return void\r
- */\r
- public function connect() {\r
- if (!$this->conn) {\r
- $this->conn = new MSN(\r
- array(\r
- 'user' => $this->plugin->user,\r
- 'password' => $this->plugin->password,\r
- 'alias' => $this->plugin->nickname,\r
- // TRANS: MSN bot status message.\r
- 'psm' => _m('Send me a message to post a notice'),\r
- 'debug' => false\r
- )\r
- );\r
- $this->conn->registerHandler('IMin', array($this, 'handle_msn_message'));\r
- $this->conn->registerHandler('SessionReady', array($this, 'handle_session_ready'));\r
- $this->conn->registerHandler('Pong', array($this, 'update_ping_time'));\r
- $this->conn->registerHandler('ConnectFailed', array($this, 'handle_connect_failed'));\r
- $this->conn->registerHandler('Reconnect', array($this, 'handle_reconnect'));\r
- $this->conn->signon();\r
- $this->lastPing = time();\r
- }\r
- return $this->conn;\r
- }\r
-\r
- /**\r
- * Called by the idle process to send a ping\r
- * when necessary\r
- *\r
- * @return void\r
- */\r
- protected function send_ping() {\r
- $this->connect();\r
- if (!$this->conn) {\r
- return false;\r
- }\r
-\r
- $this->conn->sendPing();\r
- $this->lastPing = time();\r
- $this->pingInterval = 50;\r
- return true;\r
- }\r
-\r
- /**\r
- * Update the time till the next ping\r
- *\r
- * @param $data Time till next ping\r
- * @return void\r
- */\r
- public function update_ping_time($data) {\r
- $this->pingInterval = $data;\r
- }\r
-\r
- /**\r
- * Called via a callback when a message is received\r
- *\r
- * Passes it back to the queuing system\r
- *\r
- * @param array $data Data\r
- * @return boolean\r
- */\r
- public function handle_msn_message($data) {\r
- $this->plugin->enqueueIncomingRaw($data);\r
- return true;\r
- }\r
-\r
- /**\r
- * Called via a callback when a session becomes ready\r
- *\r
- * @param array $data Data\r
- */\r
- public function handle_session_ready($data) {\r
- $sessionFailed = false;\r
- $wm = Msn_waiting_message::top($data['to']);\r
- while ($wm != NULL) {\r
- if ($sessionFailed) {\r
- $this->plugin->sendMessage($wm->screenname, $wm->message);\r
- $sessionFailed = true;\r
- } elseif (!$this->conn->sendMessage($wm->screenname, $wm->message, $ignore)) {\r
- $this->plugin->sendMessage($wm->screenname, $wm->message);\r
- }\r
-\r
- $wm->delete();\r
- $wm = Msn_waiting_message::top($data['to']);\r
- }\r
- }\r
-\r
- /**\r
- * Requeue messages from the waiting table so we try\r
- * to send them again\r
- *\r
- * @return void\r
- */\r
- protected function requeue_waiting_messages() {\r
- $wm = Msn_waiting_message::top();\r
- while ($wm != NULL) {\r
- $this->plugin->sendMessage($wm->screenname, $wm->message);\r
- $wm->delete();\r
- $wm = Msn_waiting_message::top();\r
- }\r
- }\r
-\r
- /**\r
- * Called by callback to log failure during connect\r
- *\r
- * @param string $message error message reported\r
- * @return void\r
- */\r
- public function handle_connect_failed($message) {\r
- common_log(LOG_NOTICE, 'MSN connect failed, retrying: ' . $message);\r
- }\r
-\r
- /**\r
- * Called by callback to log reconnection\r
- *\r
- * @param void $data Not used (there to keep callback happy)\r
- * @return void\r
- */\r
- public function handle_reconnect($data) {\r
- common_log(LOG_NOTICE, 'MSN reconnecting');\r
- // Requeue messages waiting in the DB\r
- $this->requeue_waiting_messages();\r
- }\r
-\r
- /**\r
- * Enters a message into the database for sending via a callback\r
- * when the session is established\r
- *\r
- * @param string $to Intended recipient\r
- * @param string $message Message\r
- */\r
- protected function enqueue_waiting_message($to, $message) {\r
- $wm = new Msn_waiting_message();\r
-\r
- $wm->screenname = $to;\r
- $wm->message = $message;\r
- $wm->created = common_sql_now();\r
- $result = $wm->insert();\r
-\r
- if (!$result) {\r
- common_log_db_error($wm, 'INSERT', __FILE__);\r
- // TRANS: Server exception thrown when a message to be sent through MSN cannot be added to the database queue.\r
- throw new ServerException(_m('Database error inserting queue item.'));\r
- }\r
-\r
- return true;\r
- }\r
-\r
- /**\r
- * Send a message using the daemon\r
- *\r
- * @param $data Message data\r
- * @return boolean true on success\r
- */\r
- public function send_raw_message($data) {\r
- $this->connect();\r
- if (!$this->conn) {\r
- return false;\r
- }\r
-\r
- $waitForSession = false;\r
- if (!$this->conn->sendMessage($data['to'], $data['message'], $waitForSession)) {\r
- if ($waitForSession) {\r
- $this->enqueue_waiting_message($data['to'], $data['message']);\r
- } else {\r
- return false;\r
- }\r
- }\r
-\r
- // Sending a command updates the time till next ping\r
- $this->lastPing = time();\r
- $this->pingInterval = 50;\r
- return true;\r
- }\r
-}\r
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'Notice_title':
- include_once $dir . '/'.$cls.'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Provide plugin version information.
*
+++ /dev/null
-<?php
-/**
- * Data class for notice titles
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for notice titles
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Notice_title extends Managed_DataObject
-{
- const MAXCHARS = 255;
-
- public $__table = 'notice_title'; // table name
- public $notice_id; // int(11) primary_key not_null
- public $title; // varchar(255)
- public $created; // datetime() not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice id this title relates to'),
- 'title' => array('type' => 'varchar', 'length' => Notice_title::MAXCHARS, 'description' => 'title to notice'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('notice_id'),
- 'foreign keys' => array(
- 'notice_title_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
- ),
- );
- }
-
- /**
- * Get a notice title based on the notice
- *
- * @param Notice $notice Notice to fetch a title for
- *
- * @return string title of the notice, or null if none
- */
- static function fromNotice($notice)
- {
- $nt = Notice_title::getKV('notice_id', $notice->id);
- if (empty($nt)) {
- return null;
- } else {
- return $nt->title;
- }
- }
-}
--- /dev/null
+<?php
+/**
+ * Data class for notice titles
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for notice titles
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Notice_title extends Managed_DataObject
+{
+ const MAXCHARS = 255;
+
+ public $__table = 'notice_title'; // table name
+ public $notice_id; // int(11) primary_key not_null
+ public $title; // varchar(255)
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'notice id this title relates to'),
+ 'title' => array('type' => 'varchar', 'length' => Notice_title::MAXCHARS, 'description' => 'title to notice'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('notice_id'),
+ 'foreign keys' => array(
+ 'notice_title_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
+ ),
+ );
+ }
+
+ /**
+ * Get a notice title based on the notice
+ *
+ * @param Notice $notice Notice to fetch a title for
+ *
+ * @return string title of the notice, or null if none
+ */
+ static function fromNotice($notice)
+ {
+ $nt = Notice_title::getKV('notice_id', $notice->id);
+ if (empty($nt)) {
+ return null;
+ } else {
+ return $nt->title;
+ }
+ }
+}
*/
class OMBPlugin extends Plugin
{
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'Requesttokenaction':
- case 'Accesstokenaction':
- case 'Userauthorizationaction':
- case 'Postnoticeaction':
- case 'Updateprofileaction':
- case 'Finishremotesubscribeaction':
- case 'Remotesubscribeaction':
- case 'XrdsAction':
- include_once $dir . '/action/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- break;
- case 'OmbQueueHandler':
- case 'ProfileQueueHandler':
- include_once $dir . '/lib/' . strtolower($cls) . '.php';
- return false;
- case 'OMBOAuthDataStore':
- include_once $dir . '/lib/omboauthstore.php';
- default:
- return true;
- }
- }
/**
* Map URLs to actions
$dir = dirname(__FILE__);
-require_once $dir . '/omboauthstore.php';
require_once $dir . '/../extlib/libomb/constants.php';
require_once $dir . '/../extlib/libomb/service_consumer.php';
require_once $dir . '/../extlib/libomb/notice.php';
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008-2011 StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+require_once dirname(__FILE__) . '/../extlib/libomb/datastore.php';
+
+// @todo FIXME: Class documentation missing.
+class OMBOAuthDataStore extends OAuthDataStore
+{
+ // We keep a record of who's contacted us
+ function lookup_consumer($consumer_key)
+ {
+ $con = Consumer::getKV('consumer_key', $consumer_key);
+ if (!$con) {
+ $con = new Consumer();
+ $con->consumer_key = $consumer_key;
+ $con->seed = common_good_rand(16);
+ $con->created = DB_DataObject_Cast::dateTime();
+ if (!$con->insert()) {
+ return null;
+ }
+ }
+ return new OAuthConsumer($con->consumer_key, '');
+ }
+
+ function lookup_token($consumer, $token_type, $token_key)
+ {
+ $t = new Token();
+ if (!is_null($consumer)) {
+ $t->consumer_key = $consumer->key;
+ }
+ $t->tok = $token_key;
+ $t->type = ($token_type == 'access') ? 1 : 0;
+ if ($t->find(true)) {
+ return new OAuthToken($t->tok, $t->secret);
+ } else {
+ return null;
+ }
+ }
+
+ // http://oauth.net/core/1.0/#nonce
+ // "The Consumer SHALL then generate a Nonce value that is unique for
+ // all requests with that timestamp."
+ // XXX: It's not clear why the token is here
+ function lookup_nonce($consumer, $token, $nonce, $timestamp)
+ {
+ $n = new Nonce();
+ $n->consumer_key = $consumer->key;
+ $n->ts = common_sql_date($timestamp);
+ $n->nonce = $nonce;
+ if ($n->find(true)) {
+ return true;
+ } else {
+ $n->created = DB_DataObject_Cast::dateTime();
+ $n->insert();
+ return false;
+ }
+ }
+
+ function new_request_token($consumer)
+ {
+ $t = new Token();
+ $t->consumer_key = $consumer->key;
+ $t->tok = common_good_rand(16);
+ $t->secret = common_good_rand(16);
+ $t->type = 0; // request
+ $t->state = 0; // unauthorized
+ $t->created = DB_DataObject_Cast::dateTime();
+ if (!$t->insert()) {
+ return null;
+ } else {
+ return new OAuthToken($t->tok, $t->secret);
+ }
+ }
+
+ // defined in OAuthDataStore, but not implemented anywhere
+ function fetch_request_token($consumer)
+ {
+ return $this->new_request_token($consumer);
+ }
+
+ function new_access_token($token, $consumer)
+ {
+ common_debug('new_access_token("'.$token->key.'","'.$consumer->key.'")', __FILE__);
+ $rt = new Token();
+ $rt->consumer_key = $consumer->key;
+ $rt->tok = $token->key;
+ $rt->type = 0; // request
+ if ($rt->find(true) && $rt->state == 1) { // authorized
+ common_debug('request token found.', __FILE__);
+ $at = new Token();
+ $at->consumer_key = $consumer->key;
+ $at->tok = common_good_rand(16);
+ $at->secret = common_good_rand(16);
+ $at->type = 1; // access
+ $at->created = DB_DataObject_Cast::dateTime();
+ if (!$at->insert()) {
+ $e = $at->_lastError;
+ common_debug('access token "'.$at->tok.'" not inserted: "'.$e->message.'"', __FILE__);
+ return null;
+ } else {
+ common_debug('access token "'.$at->tok.'" inserted', __FILE__);
+ // burn the old one
+ $orig_rt = clone($rt);
+ $rt->state = 2; // used
+ if (!$rt->update($orig_rt)) {
+ return null;
+ }
+ common_debug('request token "'.$rt->tok.'" updated', __FILE__);
+ // Update subscription
+ // XXX: mixing levels here
+ $sub = Subscription::getKV('token', $rt->tok);
+ if (!$sub) {
+ return null;
+ }
+ common_debug('subscription for request token found', __FILE__);
+ $orig_sub = clone($sub);
+ $sub->token = $at->tok;
+ $sub->secret = $at->secret;
+ if (!$sub->update($orig_sub)) {
+ return null;
+ } else {
+ common_debug('subscription updated to use access token', __FILE__);
+ return new OAuthToken($at->tok, $at->secret);
+ }
+ }
+ } else {
+ return null;
+ }
+ }
+
+ // defined in OAuthDataStore, but not implemented anywhere
+ function fetch_access_token($consumer)
+ {
+ return $this->new_access_token($consumer);
+ }
+
+ /**
+ * Revoke specified OAuth token
+ *
+ * Revokes the authorization token specified by $token_key.
+ * Throws exceptions in case of error.
+ *
+ * @param string $token_key The token to be revoked
+ *
+ * @access public
+ **/
+ public function revoke_token($token_key) {
+ $rt = new Token();
+ $rt->tok = $token_key;
+ $rt->type = 0;
+ $rt->state = 0;
+ if (!$rt->find(true)) {
+ throw new Exception('Tried to revoke unknown token');
+ }
+ if (!$rt->delete()) {
+ throw new Exception('Failed to delete revoked token');
+ }
+ }
+
+ /**
+ * Authorize specified OAuth token
+ *
+ * Authorizes the authorization token specified by $token_key.
+ * Throws exceptions in case of error.
+ *
+ * @param string $token_key The token to be authorized
+ *
+ * @access public
+ **/
+ public function authorize_token($token_key) {
+ $rt = new Token();
+ $rt->tok = $token_key;
+ $rt->type = 0;
+ $rt->state = 0;
+ if (!$rt->find(true)) {
+ throw new Exception('Tried to authorize unknown token');
+ }
+ $orig_rt = clone($rt);
+ $rt->state = 1; # Authorized but not used
+ if (!$rt->update($orig_rt)) {
+ throw new Exception('Failed to authorize token');
+ }
+ }
+
+ /**
+ * Get profile by identifying URI
+ *
+ * Returns an OMB_Profile object representing the OMB profile identified by
+ * $identifier_uri.
+ * Returns null if there is no such OMB profile.
+ * Throws exceptions in case of other error.
+ *
+ * @param string $identifier_uri The OMB identifier URI specifying the
+ * requested profile
+ *
+ * @access public
+ *
+ * @return OMB_Profile The corresponding profile
+ **/
+ public function getProfile($identifier_uri) {
+ /* getProfile is only used for remote profiles by libomb.
+ @TODO: Make it work with local ones anyway. */
+ $remote = Remote_profile::getKV('uri', $identifier_uri);
+ if (!$remote) throw new Exception('No such remote profile');
+ $profile = Profile::getKV('id', $remote->id);
+ if (!$profile) throw new Exception('No profile for remote user');
+
+ require_once dirname(__FILE__) . '/omb.php';
+ return profile_to_omb_profile($identifier_uri, $profile);
+ }
+
+ /**
+ * Save passed profile
+ *
+ * Stores the OMB profile $profile. Overwrites an existing entry.
+ * Throws exceptions in case of error.
+ *
+ * @param OMB_Profile $profile The OMB profile which should be saved
+ *
+ * @access public
+ **/
+ public function saveProfile($omb_profile) {
+ if (common_profile_url($omb_profile->getNickname()) ==
+ $omb_profile->getProfileURL()) {
+ throw new Exception('Not implemented');
+ } else {
+ $remote = Remote_profile::getKV('uri', $omb_profile->getIdentifierURI());
+
+ if ($remote) {
+ $exists = true;
+ $profile = Profile::getKV($remote->id);
+ $orig_remote = clone($remote);
+ $orig_profile = clone($profile);
+ // XXX: compare current postNotice and updateProfile URLs to the ones
+ // stored in the DB to avoid (possibly...) above attack
+ } else {
+ $exists = false;
+ $remote = new Remote_profile();
+ $remote->uri = $omb_profile->getIdentifierURI();
+ $profile = new Profile();
+ }
+
+ $profile->nickname = $omb_profile->getNickname();
+ $profile->profileurl = $omb_profile->getProfileURL();
+
+ $fullname = $omb_profile->getFullname();
+ $profile->fullname = is_null($fullname) ? '' : $fullname;
+ $homepage = $omb_profile->getHomepage();
+ $profile->homepage = is_null($homepage) ? '' : $homepage;
+ $bio = $omb_profile->getBio();
+ $profile->bio = is_null($bio) ? '' : $bio;
+ $location = $omb_profile->getLocation();
+ $profile->location = is_null($location) ? '' : $location;
+
+ if ($exists) {
+ $profile->update($orig_profile);
+ } else {
+ $profile->created = DB_DataObject_Cast::dateTime(); # current time
+ $id = $profile->insert();
+ if (!$id) {
+ // TRANS: Exception thrown when creating a new profile fails in OAuth store.
+ throw new Exception(_('Error inserting new profile.'));
+ }
+ $remote->id = $id;
+ }
+
+ $avatar_url = $omb_profile->getAvatarURL();
+ if ($avatar_url) {
+ if (!$this->add_avatar($profile, $avatar_url)) {
+ // TRANS: Exception thrown when creating a new avatar fails in OAuth store.
+ throw new Exception(_('Error inserting avatar.'));
+ }
+ } else {
+ $avatar = $profile->getOriginalAvatar();
+ if($avatar) $avatar->delete();
+ $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
+ if($avatar) $avatar->delete();
+ $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
+ if($avatar) $avatar->delete();
+ $avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
+ if($avatar) $avatar->delete();
+ }
+
+ if ($exists) {
+ if (!$remote->update($orig_remote)) {
+ // TRANS: Exception thrown when updating a remote profile fails in OAuth store.
+ throw new Exception(_('Error updating remote profile.'));
+ }
+ } else {
+ $remote->created = DB_DataObject_Cast::dateTime(); # current time
+ if (!$remote->insert()) {
+ // TRANS: Exception thrown when creating a remote profile fails in OAuth store.
+ throw new Exception(_('Error inserting remote profile.'));
+ }
+ }
+ }
+ }
+
+ function add_avatar($profile, $url)
+ {
+ $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
+ try {
+ copy($url, $temp_filename);
+ $imagefile = new ImageFile($profile->id, $temp_filename);
+ $filename = Avatar::filename($profile->id,
+ image_type_to_extension($imagefile->type),
+ null,
+ common_timestamp());
+ rename($temp_filename, Avatar::path($filename));
+ } catch (Exception $e) {
+ unlink($temp_filename);
+ throw $e;
+ }
+ return $profile->setOriginal($filename);
+ }
+
+ /**
+ * Save passed notice
+ *
+ * Stores the OMB notice $notice. The datastore may change the passed notice.
+ * This might by neccessary for URIs depending on a database key. Note that
+ * it is the user’s duty to present a mechanism for his OMB_Datastore to
+ * appropriately change his OMB_Notice.
+ * Throws exceptions in case of error.
+ *
+ * @param OMB_Notice $notice The OMB notice which should be saved
+ *
+ * @access public
+ **/
+ public function saveNotice(&$omb_notice) {
+ if (Notice::getKV('uri', $omb_notice->getIdentifierURI())) {
+ // TRANS: Exception thrown when a notice is denied because it has been sent before.
+ throw new Exception(_('Duplicate notice.'));
+ }
+ $author_uri = $omb_notice->getAuthor()->getIdentifierURI();
+ common_log(LOG_DEBUG, $author_uri, __FILE__);
+ $author = Remote_profile::getKV('uri', $author_uri);
+ if (!$author) {
+ $author = User::getKV('uri', $author_uri);
+ }
+ if (!$author) {
+ throw new Exception('No such user.');
+ }
+
+ common_log(LOG_DEBUG, print_r($author, true), __FILE__);
+
+ $notice = Notice::saveNew($author->id,
+ $omb_notice->getContent(),
+ 'omb',
+ array('is_local' => Notice::REMOTE,
+ 'uri' => $omb_notice->getIdentifierURI()));
+
+ }
+
+ /**
+ * Get subscriptions of a given profile
+ *
+ * Returns an array containing subscription informations for the specified
+ * profile. Every array entry should in turn be an array with keys
+ * 'uri´: The identifier URI of the subscriber
+ * 'token´: The subscribe token
+ * 'secret´: The secret token
+ * Throws exceptions in case of error.
+ *
+ * @param string $subscribed_user_uri The OMB identifier URI specifying the
+ * subscribed profile
+ *
+ * @access public
+ *
+ * @return mixed An array containing the subscriptions or 0 if no
+ * subscription has been found.
+ **/
+ public function getSubscriptions($subscribed_user_uri) {
+ $sub = new Subscription();
+
+ $user = $this->_getAnyProfile($subscribed_user_uri);
+
+ $sub->subscribed = $user->id;
+
+ if (!$sub->find(true)) {
+ return array();
+ }
+
+ /* Since we do not use OMB_Service_Provider’s action methods, there
+ is no need to actually return the subscriptions. */
+ return 1;
+ }
+
+ private function _getAnyProfile($uri)
+ {
+ $user = Remote_profile::getKV('uri', $uri);
+ if (!$user) {
+ $user = User::getKV('uri', $uri);
+ }
+ if (!$user) {
+ throw new Exception('No such user.');
+ }
+ return $user;
+ }
+
+ /**
+ * Delete a subscription
+ *
+ * Deletes the subscription from $subscriber_uri to $subscribed_user_uri.
+ * Throws exceptions in case of error.
+ *
+ * @param string $subscriber_uri The OMB identifier URI specifying the
+ * subscribing profile
+ *
+ * @param string $subscribed_user_uri The OMB identifier URI specifying the
+ * subscribed profile
+ *
+ * @access public
+ **/
+ public function deleteSubscription($subscriber_uri, $subscribed_user_uri)
+ {
+ $sub = new Subscription();
+
+ $subscribed = $this->_getAnyProfile($subscribed_user_uri);
+ $subscriber = $this->_getAnyProfile($subscriber_uri);
+
+ $sub->subscribed = $subscribed->id;
+ $sub->subscriber = $subscriber->id;
+
+ $sub->delete();
+ }
+
+ /**
+ * Save a subscription
+ *
+ * Saves the subscription from $subscriber_uri to $subscribed_user_uri.
+ * Throws exceptions in case of error.
+ *
+ * @param string $subscriber_uri The OMB identifier URI specifying
+ * the subscribing profile
+ *
+ * @param string $subscribed_user_uri The OMB identifier URI specifying
+ * the subscribed profile
+ * @param OAuthToken $token The access token
+ *
+ * @access public
+ **/
+ public function saveSubscription($subscriber_uri, $subscribed_user_uri,
+ $token)
+ {
+ $sub = new Subscription();
+
+ $subscribed = $this->_getAnyProfile($subscribed_user_uri);
+ $subscriber = $this->_getAnyProfile($subscriber_uri);
+
+ if (!$subscriber->hasRight(Right::SUBSCRIBE)) {
+ common_log(LOG_INFO, __METHOD__ . ": remote subscriber banned ($subscriber_uri subbing to $subscribed_user_uri)");
+ // TRANS: Error message displayed to a banned user when they try to subscribe.
+ return _('You have been banned from subscribing.');
+ }
+
+ $sub->subscribed = $subscribed->id;
+ $sub->subscriber = $subscriber->id;
+
+ $sub_exists = $sub->find(true);
+
+ if ($sub_exists) {
+ $orig_sub = clone($sub);
+ } else {
+ $sub->created = DB_DataObject_Cast::dateTime();
+ }
+
+ $sub->token = $token->key;
+ $sub->secret = $token->secret;
+
+ if ($sub_exists) {
+ $result = $sub->update($orig_sub);
+ } else {
+ $result = $sub->insert();
+ }
+
+ if (!$result) {
+ common_log_db_error($sub, ($sub_exists) ? 'UPDATE' : 'INSERT', __FILE__);
+ // TRANS: Exception thrown when creating a new subscription fails in OAuth store.
+ throw new Exception(_('Could not insert new subscription.'));
+ return;
+ }
+
+ /* Notify user, if necessary. */
+
+ if ($subscribed instanceof User) {
+ mail_subscribe_notify_profile($subscribed,
+ Profile::getKV($subscriber->id));
+ }
+ }
+}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008-2011 StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-require_once dirname(__FILE__) . '/../extlib/libomb/datastore.php';
-
-// @todo FIXME: Class documentation missing.
-class OMBOAuthDataStore extends OAuthDataStore
-{
- // We keep a record of who's contacted us
- function lookup_consumer($consumer_key)
- {
- $con = Consumer::getKV('consumer_key', $consumer_key);
- if (!$con) {
- $con = new Consumer();
- $con->consumer_key = $consumer_key;
- $con->seed = common_good_rand(16);
- $con->created = DB_DataObject_Cast::dateTime();
- if (!$con->insert()) {
- return null;
- }
- }
- return new OAuthConsumer($con->consumer_key, '');
- }
-
- function lookup_token($consumer, $token_type, $token_key)
- {
- $t = new Token();
- if (!is_null($consumer)) {
- $t->consumer_key = $consumer->key;
- }
- $t->tok = $token_key;
- $t->type = ($token_type == 'access') ? 1 : 0;
- if ($t->find(true)) {
- return new OAuthToken($t->tok, $t->secret);
- } else {
- return null;
- }
- }
-
- // http://oauth.net/core/1.0/#nonce
- // "The Consumer SHALL then generate a Nonce value that is unique for
- // all requests with that timestamp."
- // XXX: It's not clear why the token is here
- function lookup_nonce($consumer, $token, $nonce, $timestamp)
- {
- $n = new Nonce();
- $n->consumer_key = $consumer->key;
- $n->ts = common_sql_date($timestamp);
- $n->nonce = $nonce;
- if ($n->find(true)) {
- return true;
- } else {
- $n->created = DB_DataObject_Cast::dateTime();
- $n->insert();
- return false;
- }
- }
-
- function new_request_token($consumer)
- {
- $t = new Token();
- $t->consumer_key = $consumer->key;
- $t->tok = common_good_rand(16);
- $t->secret = common_good_rand(16);
- $t->type = 0; // request
- $t->state = 0; // unauthorized
- $t->created = DB_DataObject_Cast::dateTime();
- if (!$t->insert()) {
- return null;
- } else {
- return new OAuthToken($t->tok, $t->secret);
- }
- }
-
- // defined in OAuthDataStore, but not implemented anywhere
- function fetch_request_token($consumer)
- {
- return $this->new_request_token($consumer);
- }
-
- function new_access_token($token, $consumer)
- {
- common_debug('new_access_token("'.$token->key.'","'.$consumer->key.'")', __FILE__);
- $rt = new Token();
- $rt->consumer_key = $consumer->key;
- $rt->tok = $token->key;
- $rt->type = 0; // request
- if ($rt->find(true) && $rt->state == 1) { // authorized
- common_debug('request token found.', __FILE__);
- $at = new Token();
- $at->consumer_key = $consumer->key;
- $at->tok = common_good_rand(16);
- $at->secret = common_good_rand(16);
- $at->type = 1; // access
- $at->created = DB_DataObject_Cast::dateTime();
- if (!$at->insert()) {
- $e = $at->_lastError;
- common_debug('access token "'.$at->tok.'" not inserted: "'.$e->message.'"', __FILE__);
- return null;
- } else {
- common_debug('access token "'.$at->tok.'" inserted', __FILE__);
- // burn the old one
- $orig_rt = clone($rt);
- $rt->state = 2; // used
- if (!$rt->update($orig_rt)) {
- return null;
- }
- common_debug('request token "'.$rt->tok.'" updated', __FILE__);
- // Update subscription
- // XXX: mixing levels here
- $sub = Subscription::getKV('token', $rt->tok);
- if (!$sub) {
- return null;
- }
- common_debug('subscription for request token found', __FILE__);
- $orig_sub = clone($sub);
- $sub->token = $at->tok;
- $sub->secret = $at->secret;
- if (!$sub->update($orig_sub)) {
- return null;
- } else {
- common_debug('subscription updated to use access token', __FILE__);
- return new OAuthToken($at->tok, $at->secret);
- }
- }
- } else {
- return null;
- }
- }
-
- // defined in OAuthDataStore, but not implemented anywhere
- function fetch_access_token($consumer)
- {
- return $this->new_access_token($consumer);
- }
-
- /**
- * Revoke specified OAuth token
- *
- * Revokes the authorization token specified by $token_key.
- * Throws exceptions in case of error.
- *
- * @param string $token_key The token to be revoked
- *
- * @access public
- **/
- public function revoke_token($token_key) {
- $rt = new Token();
- $rt->tok = $token_key;
- $rt->type = 0;
- $rt->state = 0;
- if (!$rt->find(true)) {
- throw new Exception('Tried to revoke unknown token');
- }
- if (!$rt->delete()) {
- throw new Exception('Failed to delete revoked token');
- }
- }
-
- /**
- * Authorize specified OAuth token
- *
- * Authorizes the authorization token specified by $token_key.
- * Throws exceptions in case of error.
- *
- * @param string $token_key The token to be authorized
- *
- * @access public
- **/
- public function authorize_token($token_key) {
- $rt = new Token();
- $rt->tok = $token_key;
- $rt->type = 0;
- $rt->state = 0;
- if (!$rt->find(true)) {
- throw new Exception('Tried to authorize unknown token');
- }
- $orig_rt = clone($rt);
- $rt->state = 1; # Authorized but not used
- if (!$rt->update($orig_rt)) {
- throw new Exception('Failed to authorize token');
- }
- }
-
- /**
- * Get profile by identifying URI
- *
- * Returns an OMB_Profile object representing the OMB profile identified by
- * $identifier_uri.
- * Returns null if there is no such OMB profile.
- * Throws exceptions in case of other error.
- *
- * @param string $identifier_uri The OMB identifier URI specifying the
- * requested profile
- *
- * @access public
- *
- * @return OMB_Profile The corresponding profile
- **/
- public function getProfile($identifier_uri) {
- /* getProfile is only used for remote profiles by libomb.
- @TODO: Make it work with local ones anyway. */
- $remote = Remote_profile::getKV('uri', $identifier_uri);
- if (!$remote) throw new Exception('No such remote profile');
- $profile = Profile::getKV('id', $remote->id);
- if (!$profile) throw new Exception('No profile for remote user');
-
- require_once dirname(__FILE__) . '/omb.php';
- return profile_to_omb_profile($identifier_uri, $profile);
- }
-
- /**
- * Save passed profile
- *
- * Stores the OMB profile $profile. Overwrites an existing entry.
- * Throws exceptions in case of error.
- *
- * @param OMB_Profile $profile The OMB profile which should be saved
- *
- * @access public
- **/
- public function saveProfile($omb_profile) {
- if (common_profile_url($omb_profile->getNickname()) ==
- $omb_profile->getProfileURL()) {
- throw new Exception('Not implemented');
- } else {
- $remote = Remote_profile::getKV('uri', $omb_profile->getIdentifierURI());
-
- if ($remote) {
- $exists = true;
- $profile = Profile::getKV($remote->id);
- $orig_remote = clone($remote);
- $orig_profile = clone($profile);
- // XXX: compare current postNotice and updateProfile URLs to the ones
- // stored in the DB to avoid (possibly...) above attack
- } else {
- $exists = false;
- $remote = new Remote_profile();
- $remote->uri = $omb_profile->getIdentifierURI();
- $profile = new Profile();
- }
-
- $profile->nickname = $omb_profile->getNickname();
- $profile->profileurl = $omb_profile->getProfileURL();
-
- $fullname = $omb_profile->getFullname();
- $profile->fullname = is_null($fullname) ? '' : $fullname;
- $homepage = $omb_profile->getHomepage();
- $profile->homepage = is_null($homepage) ? '' : $homepage;
- $bio = $omb_profile->getBio();
- $profile->bio = is_null($bio) ? '' : $bio;
- $location = $omb_profile->getLocation();
- $profile->location = is_null($location) ? '' : $location;
-
- if ($exists) {
- $profile->update($orig_profile);
- } else {
- $profile->created = DB_DataObject_Cast::dateTime(); # current time
- $id = $profile->insert();
- if (!$id) {
- // TRANS: Exception thrown when creating a new profile fails in OAuth store.
- throw new Exception(_('Error inserting new profile.'));
- }
- $remote->id = $id;
- }
-
- $avatar_url = $omb_profile->getAvatarURL();
- if ($avatar_url) {
- if (!$this->add_avatar($profile, $avatar_url)) {
- // TRANS: Exception thrown when creating a new avatar fails in OAuth store.
- throw new Exception(_('Error inserting avatar.'));
- }
- } else {
- $avatar = $profile->getOriginalAvatar();
- if($avatar) $avatar->delete();
- $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
- if($avatar) $avatar->delete();
- $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
- if($avatar) $avatar->delete();
- $avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
- if($avatar) $avatar->delete();
- }
-
- if ($exists) {
- if (!$remote->update($orig_remote)) {
- // TRANS: Exception thrown when updating a remote profile fails in OAuth store.
- throw new Exception(_('Error updating remote profile.'));
- }
- } else {
- $remote->created = DB_DataObject_Cast::dateTime(); # current time
- if (!$remote->insert()) {
- // TRANS: Exception thrown when creating a remote profile fails in OAuth store.
- throw new Exception(_('Error inserting remote profile.'));
- }
- }
- }
- }
-
- function add_avatar($profile, $url)
- {
- $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
- try {
- copy($url, $temp_filename);
- $imagefile = new ImageFile($profile->id, $temp_filename);
- $filename = Avatar::filename($profile->id,
- image_type_to_extension($imagefile->type),
- null,
- common_timestamp());
- rename($temp_filename, Avatar::path($filename));
- } catch (Exception $e) {
- unlink($temp_filename);
- throw $e;
- }
- return $profile->setOriginal($filename);
- }
-
- /**
- * Save passed notice
- *
- * Stores the OMB notice $notice. The datastore may change the passed notice.
- * This might by neccessary for URIs depending on a database key. Note that
- * it is the user’s duty to present a mechanism for his OMB_Datastore to
- * appropriately change his OMB_Notice.
- * Throws exceptions in case of error.
- *
- * @param OMB_Notice $notice The OMB notice which should be saved
- *
- * @access public
- **/
- public function saveNotice(&$omb_notice) {
- if (Notice::getKV('uri', $omb_notice->getIdentifierURI())) {
- // TRANS: Exception thrown when a notice is denied because it has been sent before.
- throw new Exception(_('Duplicate notice.'));
- }
- $author_uri = $omb_notice->getAuthor()->getIdentifierURI();
- common_log(LOG_DEBUG, $author_uri, __FILE__);
- $author = Remote_profile::getKV('uri', $author_uri);
- if (!$author) {
- $author = User::getKV('uri', $author_uri);
- }
- if (!$author) {
- throw new Exception('No such user.');
- }
-
- common_log(LOG_DEBUG, print_r($author, true), __FILE__);
-
- $notice = Notice::saveNew($author->id,
- $omb_notice->getContent(),
- 'omb',
- array('is_local' => Notice::REMOTE,
- 'uri' => $omb_notice->getIdentifierURI()));
-
- }
-
- /**
- * Get subscriptions of a given profile
- *
- * Returns an array containing subscription informations for the specified
- * profile. Every array entry should in turn be an array with keys
- * 'uri´: The identifier URI of the subscriber
- * 'token´: The subscribe token
- * 'secret´: The secret token
- * Throws exceptions in case of error.
- *
- * @param string $subscribed_user_uri The OMB identifier URI specifying the
- * subscribed profile
- *
- * @access public
- *
- * @return mixed An array containing the subscriptions or 0 if no
- * subscription has been found.
- **/
- public function getSubscriptions($subscribed_user_uri) {
- $sub = new Subscription();
-
- $user = $this->_getAnyProfile($subscribed_user_uri);
-
- $sub->subscribed = $user->id;
-
- if (!$sub->find(true)) {
- return array();
- }
-
- /* Since we do not use OMB_Service_Provider’s action methods, there
- is no need to actually return the subscriptions. */
- return 1;
- }
-
- private function _getAnyProfile($uri)
- {
- $user = Remote_profile::getKV('uri', $uri);
- if (!$user) {
- $user = User::getKV('uri', $uri);
- }
- if (!$user) {
- throw new Exception('No such user.');
- }
- return $user;
- }
-
- /**
- * Delete a subscription
- *
- * Deletes the subscription from $subscriber_uri to $subscribed_user_uri.
- * Throws exceptions in case of error.
- *
- * @param string $subscriber_uri The OMB identifier URI specifying the
- * subscribing profile
- *
- * @param string $subscribed_user_uri The OMB identifier URI specifying the
- * subscribed profile
- *
- * @access public
- **/
- public function deleteSubscription($subscriber_uri, $subscribed_user_uri)
- {
- $sub = new Subscription();
-
- $subscribed = $this->_getAnyProfile($subscribed_user_uri);
- $subscriber = $this->_getAnyProfile($subscriber_uri);
-
- $sub->subscribed = $subscribed->id;
- $sub->subscriber = $subscriber->id;
-
- $sub->delete();
- }
-
- /**
- * Save a subscription
- *
- * Saves the subscription from $subscriber_uri to $subscribed_user_uri.
- * Throws exceptions in case of error.
- *
- * @param string $subscriber_uri The OMB identifier URI specifying
- * the subscribing profile
- *
- * @param string $subscribed_user_uri The OMB identifier URI specifying
- * the subscribed profile
- * @param OAuthToken $token The access token
- *
- * @access public
- **/
- public function saveSubscription($subscriber_uri, $subscribed_user_uri,
- $token)
- {
- $sub = new Subscription();
-
- $subscribed = $this->_getAnyProfile($subscribed_user_uri);
- $subscriber = $this->_getAnyProfile($subscriber_uri);
-
- if (!$subscriber->hasRight(Right::SUBSCRIBE)) {
- common_log(LOG_INFO, __METHOD__ . ": remote subscriber banned ($subscriber_uri subbing to $subscribed_user_uri)");
- // TRANS: Error message displayed to a banned user when they try to subscribe.
- return _('You have been banned from subscribing.');
- }
-
- $sub->subscribed = $subscribed->id;
- $sub->subscriber = $subscriber->id;
-
- $sub_exists = $sub->find(true);
-
- if ($sub_exists) {
- $orig_sub = clone($sub);
- } else {
- $sub->created = DB_DataObject_Cast::dateTime();
- }
-
- $sub->token = $token->key;
- $sub->secret = $token->secret;
-
- if ($sub_exists) {
- $result = $sub->update($orig_sub);
- } else {
- $result = $sub->insert();
- }
-
- if (!$result) {
- common_log_db_error($sub, ($sub_exists) ? 'UPDATE' : 'INSERT', __FILE__);
- // TRANS: Exception thrown when creating a new subscription fails in OAuth store.
- throw new Exception(_('Could not insert new subscription.'));
- return;
- }
-
- /* Notify user, if necessary. */
-
- if ($subscribed instanceof User) {
- mail_subscribe_notify_profile($subscribed,
- Profile::getKV($subscriber->id));
- }
- }
-}
return true;
}
- /**
- * Automatically load the actions and libraries used by the plugin
- *
- * @param Class $cls the class
- *
- * @return boolean hook return
- *
- */
- function onAutoload($cls)
- {
- $base = dirname(__FILE__);
- $lower = strtolower($cls);
- $map = array('activityverb' => 'activity',
- 'activityobject' => 'activity',
- 'activityutils' => 'activity');
- if (isset($map[$lower])) {
- $lower = $map[$lower];
- }
- $files = array("$base/classes/$cls.php",
- "$base/lib/$lower.php");
- if (substr($lower, -6) == 'action') {
- $files[] = "$base/actions/" . substr($lower, 0, -6) . ".php";
- }
- foreach ($files as $file) {
- if (file_exists($file)) {
- include_once $file;
- return false;
- }
- }
- return true;
- }
-
/**
* Add in an OStatus subscribe button
*/
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+/**
+ * @package OStatusPlugin
+ * @author James Walker <james@status.net>
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class SalmonAction extends Action
+{
+ var $xml = null;
+ var $activity = null;
+ var $target = null;
+
+ function prepare($args)
+ {
+ StatusNet::setApi(true); // Send smaller error pages
+
+ parent::prepare($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ // TRANS: Client error. POST is a HTTP command. It should not be translated.
+ $this->clientError(_m('This method requires a POST.'));
+ }
+
+ if (empty($_SERVER['CONTENT_TYPE']) || $_SERVER['CONTENT_TYPE'] != 'application/magic-envelope+xml') {
+ // TRANS: Client error. Do not translate "application/magic-envelope+xml".
+ $this->clientError(_m('Salmon requires "application/magic-envelope+xml".'));
+ }
+
+ $xml = file_get_contents('php://input');
+
+ // Check the signature
+ $salmon = new Salmon;
+ if (!$salmon->verifyMagicEnv($xml)) {
+ common_log(LOG_DEBUG, "Salmon signature verification failed.");
+ // TRANS: Client error.
+ $this->clientError(_m('Salmon signature verification failed.'));
+ } else {
+ $magic_env = new MagicEnvelope();
+ $env = $magic_env->parse($xml);
+ $xml = $magic_env->unfold($env);
+ }
+
+ $dom = DOMDocument::loadXML($xml);
+ if ($dom->documentElement->namespaceURI != Activity::ATOM ||
+ $dom->documentElement->localName != 'entry') {
+ common_log(LOG_DEBUG, "Got invalid Salmon post: $xml");
+ // TRANS: Client error.
+ $this->clientError(_m('Salmon post must be an Atom entry.'));
+ }
+
+ $this->activity = new Activity($dom->documentElement);
+ return true;
+ }
+
+ /**
+ * Check the posted activity type and break out to appropriate processing.
+ */
+
+ function handle($args)
+ {
+ StatusNet::setApi(true); // Send smaller error pages
+
+ common_log(LOG_DEBUG, "Got a " . $this->activity->verb);
+ if (Event::handle('StartHandleSalmonTarget', array($this->activity, $this->target)) &&
+ Event::handle('StartHandleSalmon', array($this->activity))) {
+ switch ($this->activity->verb)
+ {
+ case ActivityVerb::POST:
+ $this->handlePost();
+ break;
+ case ActivityVerb::SHARE:
+ $this->handleShare();
+ break;
+ case ActivityVerb::FAVORITE:
+ $this->handleFavorite();
+ break;
+ case ActivityVerb::UNFAVORITE:
+ $this->handleUnfavorite();
+ break;
+ case ActivityVerb::FOLLOW:
+ case ActivityVerb::FRIEND:
+ $this->handleFollow();
+ break;
+ case ActivityVerb::UNFOLLOW:
+ $this->handleUnfollow();
+ break;
+ case ActivityVerb::JOIN:
+ $this->handleJoin();
+ break;
+ case ActivityVerb::LEAVE:
+ $this->handleLeave();
+ break;
+ case ActivityVerb::TAG:
+ $this->handleTag();
+ break;
+ case ActivityVerb::UNTAG:
+ $this->handleUntag();
+ break;
+ case ActivityVerb::UPDATE_PROFILE:
+ $this->handleUpdateProfile();
+ break;
+ default:
+ // TRANS: Client exception.
+ throw new ClientException(_m('Unrecognized activity type.'));
+ }
+ Event::handle('EndHandleSalmon', array($this->activity));
+ Event::handle('EndHandleSalmonTarget', array($this->activity, $this->target));
+ }
+ }
+
+ function handlePost()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m('This target does not understand posts.'));
+ }
+
+ function handleFollow()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m('This target does not understand follows.'));
+ }
+
+ function handleUnfollow()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m('This target does not understand unfollows.'));
+ }
+
+ function handleFavorite()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m('This target does not understand favorites.'));
+ }
+
+ function handleUnfavorite()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m('This target does not understand unfavorites.'));
+ }
+
+ function handleShare()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m('This target does not understand share events.'));
+ }
+
+ function handleJoin()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m('This target does not understand joins.'));
+ }
+
+ function handleLeave()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m('This target does not understand leave events.'));
+ }
+
+ function handleTag()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m('This target does not understand list events.'));
+ }
+
+ function handleUntag()
+ {
+ // TRANS: Client exception.
+ throw new ClientException(_m('This target does not understand unlist events.'));
+ }
+
+ /**
+ * Remote user sent us an update to their profile.
+ * If we already know them, accept the updates.
+ */
+ function handleUpdateProfile()
+ {
+ $oprofile = Ostatus_profile::getActorProfile($this->activity);
+ if ($oprofile) {
+ common_log(LOG_INFO, "Got a profile-update ping from $oprofile->uri");
+ $oprofile->updateFromActivityObject($this->activity->actor);
+ } else {
+ common_log(LOG_INFO, "Ignoring profile-update ping from unknown " . $this->activity->actor->id);
+ }
+ }
+
+ /**
+ * @return Ostatus_profile
+ */
+ function ensureProfile()
+ {
+ $actor = $this->activity->actor;
+ if (empty($actor->id)) {
+ common_log(LOG_ERR, "broken actor: " . var_export($actor, true));
+ common_log(LOG_ERR, "activity with no actor: " . var_export($this->activity, true));
+ // TRANS: Exception.
+ throw new Exception(_m('Received a salmon slap from unidentified actor.'));
+ }
+
+ return Ostatus_profile::ensureActivityObjectProfile($actor);
+ }
+
+ function saveNotice()
+ {
+ $oprofile = $this->ensureProfile();
+ return $oprofile->processPost($this->activity, 'salmon');
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+/**
+ * @package OStatusPlugin
+ * @maintainer James Walker <james@status.net>
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class XrdAction extends Action
+{
+ public $uri;
+
+ public $user;
+
+ public $xrd;
+
+ function handle()
+ {
+ $nick = $this->user->nickname;
+ $profile = $this->user->getProfile();
+
+ if (empty($this->xrd)) {
+ $xrd = new XRD();
+ } else {
+ $xrd = $this->xrd;
+ }
+
+ if (empty($xrd->subject)) {
+ $xrd->subject = Discovery::normalize($this->uri);
+ }
+
+ // Possible aliases for the user
+
+ $uris = array($this->user->uri, $profile->profileurl);
+
+ // FIXME: Webfinger generation code should live somewhere on its own
+
+ $path = common_config('site', 'path');
+
+ if (empty($path)) {
+ $uris[] = sprintf('acct:%s@%s', $nick, common_config('site', 'server'));
+ }
+
+ foreach ($uris as $uri) {
+ if ($uri != $xrd->subject) {
+ $xrd->alias[] = $uri;
+ }
+ }
+
+ $xrd->links[] = array('rel' => Discovery::PROFILEPAGE,
+ 'type' => 'text/html',
+ 'href' => $profile->profileurl);
+
+ $xrd->links[] = array('rel' => Discovery::UPDATESFROM,
+ 'href' => common_local_url('ApiTimelineUser',
+ array('id' => $this->user->id,
+ 'format' => 'atom')),
+ 'type' => 'application/atom+xml');
+
+ // XFN
+ $xrd->links[] = array('rel' => 'http://gmpg.org/xfn/11',
+ 'type' => 'text/html',
+ 'href' => $profile->profileurl);
+ // FOAF
+ $xrd->links[] = array('rel' => 'describedby',
+ 'type' => 'application/rdf+xml',
+ 'href' => common_local_url('foaf',
+ array('nickname' => $nick)));
+
+ // Salmon
+ $salmon_url = common_local_url('usersalmon',
+ array('id' => $this->user->id));
+
+ $xrd->links[] = array('rel' => Salmon::REL_SALMON,
+ 'href' => $salmon_url);
+ // XXX : Deprecated - to be removed.
+ $xrd->links[] = array('rel' => Salmon::NS_REPLIES,
+ 'href' => $salmon_url);
+
+ $xrd->links[] = array('rel' => Salmon::NS_MENTIONS,
+ 'href' => $salmon_url);
+
+ // Get this user's keypair
+ $magickey = Magicsig::getKV('user_id', $this->user->id);
+ if (!$magickey) {
+ // No keypair yet, let's generate one.
+ $magickey = new Magicsig();
+ $magickey->generate($this->user->id);
+ }
+
+ $xrd->links[] = array('rel' => Magicsig::PUBLICKEYREL,
+ 'href' => 'data:application/magic-public-key,'. $magickey->toString(false));
+
+ // TODO - finalize where the redirect should go on the publisher
+ $url = common_local_url('ostatussub') . '?profile={uri}';
+ $xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/subscribe',
+ 'template' => $url );
+
+ $url = common_local_url('tagprofile') . '?uri={uri}';
+ $xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/tag',
+ 'template' => $url );
+
+ header('Content-type: application/xrd+xml');
+ print $xrd->toXML();
+ }
+}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-/**
- * @package OStatusPlugin
- * @author James Walker <james@status.net>
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-class SalmonAction extends Action
-{
- var $xml = null;
- var $activity = null;
- var $target = null;
-
- function prepare($args)
- {
- StatusNet::setApi(true); // Send smaller error pages
-
- parent::prepare($args);
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- // TRANS: Client error. POST is a HTTP command. It should not be translated.
- $this->clientError(_m('This method requires a POST.'));
- }
-
- if (empty($_SERVER['CONTENT_TYPE']) || $_SERVER['CONTENT_TYPE'] != 'application/magic-envelope+xml') {
- // TRANS: Client error. Do not translate "application/magic-envelope+xml".
- $this->clientError(_m('Salmon requires "application/magic-envelope+xml".'));
- }
-
- $xml = file_get_contents('php://input');
-
- // Check the signature
- $salmon = new Salmon;
- if (!$salmon->verifyMagicEnv($xml)) {
- common_log(LOG_DEBUG, "Salmon signature verification failed.");
- // TRANS: Client error.
- $this->clientError(_m('Salmon signature verification failed.'));
- } else {
- $magic_env = new MagicEnvelope();
- $env = $magic_env->parse($xml);
- $xml = $magic_env->unfold($env);
- }
-
- $dom = DOMDocument::loadXML($xml);
- if ($dom->documentElement->namespaceURI != Activity::ATOM ||
- $dom->documentElement->localName != 'entry') {
- common_log(LOG_DEBUG, "Got invalid Salmon post: $xml");
- // TRANS: Client error.
- $this->clientError(_m('Salmon post must be an Atom entry.'));
- }
-
- $this->activity = new Activity($dom->documentElement);
- return true;
- }
-
- /**
- * Check the posted activity type and break out to appropriate processing.
- */
-
- function handle($args)
- {
- StatusNet::setApi(true); // Send smaller error pages
-
- common_log(LOG_DEBUG, "Got a " . $this->activity->verb);
- if (Event::handle('StartHandleSalmonTarget', array($this->activity, $this->target)) &&
- Event::handle('StartHandleSalmon', array($this->activity))) {
- switch ($this->activity->verb)
- {
- case ActivityVerb::POST:
- $this->handlePost();
- break;
- case ActivityVerb::SHARE:
- $this->handleShare();
- break;
- case ActivityVerb::FAVORITE:
- $this->handleFavorite();
- break;
- case ActivityVerb::UNFAVORITE:
- $this->handleUnfavorite();
- break;
- case ActivityVerb::FOLLOW:
- case ActivityVerb::FRIEND:
- $this->handleFollow();
- break;
- case ActivityVerb::UNFOLLOW:
- $this->handleUnfollow();
- break;
- case ActivityVerb::JOIN:
- $this->handleJoin();
- break;
- case ActivityVerb::LEAVE:
- $this->handleLeave();
- break;
- case ActivityVerb::TAG:
- $this->handleTag();
- break;
- case ActivityVerb::UNTAG:
- $this->handleUntag();
- break;
- case ActivityVerb::UPDATE_PROFILE:
- $this->handleUpdateProfile();
- break;
- default:
- // TRANS: Client exception.
- throw new ClientException(_m('Unrecognized activity type.'));
- }
- Event::handle('EndHandleSalmon', array($this->activity));
- Event::handle('EndHandleSalmonTarget', array($this->activity, $this->target));
- }
- }
-
- function handlePost()
- {
- // TRANS: Client exception.
- throw new ClientException(_m('This target does not understand posts.'));
- }
-
- function handleFollow()
- {
- // TRANS: Client exception.
- throw new ClientException(_m('This target does not understand follows.'));
- }
-
- function handleUnfollow()
- {
- // TRANS: Client exception.
- throw new ClientException(_m('This target does not understand unfollows.'));
- }
-
- function handleFavorite()
- {
- // TRANS: Client exception.
- throw new ClientException(_m('This target does not understand favorites.'));
- }
-
- function handleUnfavorite()
- {
- // TRANS: Client exception.
- throw new ClientException(_m('This target does not understand unfavorites.'));
- }
-
- function handleShare()
- {
- // TRANS: Client exception.
- throw new ClientException(_m('This target does not understand share events.'));
- }
-
- function handleJoin()
- {
- // TRANS: Client exception.
- throw new ClientException(_m('This target does not understand joins.'));
- }
-
- function handleLeave()
- {
- // TRANS: Client exception.
- throw new ClientException(_m('This target does not understand leave events.'));
- }
-
- function handleTag()
- {
- // TRANS: Client exception.
- throw new ClientException(_m('This target does not understand list events.'));
- }
-
- function handleUntag()
- {
- // TRANS: Client exception.
- throw new ClientException(_m('This target does not understand unlist events.'));
- }
-
- /**
- * Remote user sent us an update to their profile.
- * If we already know them, accept the updates.
- */
- function handleUpdateProfile()
- {
- $oprofile = Ostatus_profile::getActorProfile($this->activity);
- if ($oprofile) {
- common_log(LOG_INFO, "Got a profile-update ping from $oprofile->uri");
- $oprofile->updateFromActivityObject($this->activity->actor);
- } else {
- common_log(LOG_INFO, "Ignoring profile-update ping from unknown " . $this->activity->actor->id);
- }
- }
-
- /**
- * @return Ostatus_profile
- */
- function ensureProfile()
- {
- $actor = $this->activity->actor;
- if (empty($actor->id)) {
- common_log(LOG_ERR, "broken actor: " . var_export($actor, true));
- common_log(LOG_ERR, "activity with no actor: " . var_export($this->activity, true));
- // TRANS: Exception.
- throw new Exception(_m('Received a salmon slap from unidentified actor.'));
- }
-
- return Ostatus_profile::ensureActivityObjectProfile($actor);
- }
-
- function saveNotice()
- {
- $oprofile = $this->ensureProfile();
- return $oprofile->processPost($this->activity, 'salmon');
- }
-}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-/**
- * @package OStatusPlugin
- * @maintainer James Walker <james@status.net>
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-class XrdAction extends Action
-{
- public $uri;
-
- public $user;
-
- public $xrd;
-
- function handle()
- {
- $nick = $this->user->nickname;
- $profile = $this->user->getProfile();
-
- if (empty($this->xrd)) {
- $xrd = new XRD();
- } else {
- $xrd = $this->xrd;
- }
-
- if (empty($xrd->subject)) {
- $xrd->subject = Discovery::normalize($this->uri);
- }
-
- // Possible aliases for the user
-
- $uris = array($this->user->uri, $profile->profileurl);
-
- // FIXME: Webfinger generation code should live somewhere on its own
-
- $path = common_config('site', 'path');
-
- if (empty($path)) {
- $uris[] = sprintf('acct:%s@%s', $nick, common_config('site', 'server'));
- }
-
- foreach ($uris as $uri) {
- if ($uri != $xrd->subject) {
- $xrd->alias[] = $uri;
- }
- }
-
- $xrd->links[] = array('rel' => Discovery::PROFILEPAGE,
- 'type' => 'text/html',
- 'href' => $profile->profileurl);
-
- $xrd->links[] = array('rel' => Discovery::UPDATESFROM,
- 'href' => common_local_url('ApiTimelineUser',
- array('id' => $this->user->id,
- 'format' => 'atom')),
- 'type' => 'application/atom+xml');
-
- // XFN
- $xrd->links[] = array('rel' => 'http://gmpg.org/xfn/11',
- 'type' => 'text/html',
- 'href' => $profile->profileurl);
- // FOAF
- $xrd->links[] = array('rel' => 'describedby',
- 'type' => 'application/rdf+xml',
- 'href' => common_local_url('foaf',
- array('nickname' => $nick)));
-
- // Salmon
- $salmon_url = common_local_url('usersalmon',
- array('id' => $this->user->id));
-
- $xrd->links[] = array('rel' => Salmon::REL_SALMON,
- 'href' => $salmon_url);
- // XXX : Deprecated - to be removed.
- $xrd->links[] = array('rel' => Salmon::NS_REPLIES,
- 'href' => $salmon_url);
-
- $xrd->links[] = array('rel' => Salmon::NS_MENTIONS,
- 'href' => $salmon_url);
-
- // Get this user's keypair
- $magickey = Magicsig::getKV('user_id', $this->user->id);
- if (!$magickey) {
- // No keypair yet, let's generate one.
- $magickey = new Magicsig();
- $magickey->generate($this->user->id);
- }
-
- $xrd->links[] = array('rel' => Magicsig::PUBLICKEYREL,
- 'href' => 'data:application/magic-public-key,'. $magickey->toString(false));
-
- // TODO - finalize where the redirect should go on the publisher
- $url = common_local_url('ostatussub') . '?profile={uri}';
- $xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/subscribe',
- 'template' => $url );
-
- $url = common_local_url('tagprofile') . '?uri={uri}';
- $xrd->links[] = array('rel' => 'http://ostatus.org/schema/1.0/tag',
- 'template' => $url );
-
- header('Content-type: application/xrd+xml');
- print $xrd->toXML();
- }
-}
class OfflineBackupPlugin extends Plugin
{
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'OfflinebackupAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'OfflineBackupQueueHandler':
- include_once $dir . '/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
- }
- }
function onRouterInitialized($m)
{
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Initiate an offline backup
+ *
+ * PHP version 5
+ *
+ * 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 Offline backup
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Action to initiate an offline backup
+ *
+ * @category Offline backup
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class OfflinebackupAction extends BackupaccountAction
+{
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+
+ function handle($argarray=null)
+ {
+ if ($this->isPost()) {
+ $this->queueBackup();
+ } else {
+ $this->showPage();
+ }
+ return;
+ }
+
+ function queueBackup()
+ {
+ $cur = common_current_user();
+
+ $qm = QueueManager::get();
+
+ $qm->enqueue($cur->id, 'backoff');
+
+ $this->showPage();
+ }
+
+ function showContent()
+ {
+ if ($this->isPost()) {
+ $this->text(_('Backup queued. You will get a notification by email when your backup is ready to download.'));
+ } else {
+ parent::showContent();
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Offline backup queue handler
+ *
+ * PHP version 5
+ *
+ * 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 Offline backup
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Offline backup queue handler
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class OfflineBackupQueueHandler extends QueueHandler
+{
+ function transport()
+ {
+ return 'backoff';
+ }
+
+ function handle($object)
+ {
+ $userId = $object;
+
+ $user = User::getKV($userId);
+
+ common_log(LOG_INFO, "Making backup file for user ".$user->nickname);
+
+ $fileName = $this->makeBackupFile($user);
+
+ common_log(LOG_INFO, "Notifying user ".$user->nickname . " of their new backup file.");
+
+ $this->notifyBackupFile($user, $fileName);
+
+ return true;
+ }
+
+ function makeBackupFile($user)
+ {
+ // XXX: this is pretty lose-y; try another way
+
+ $tmpdir = sys_get_temp_dir() . '/offline-backup/' . $user->nickname . '/' . common_date_iso8601(common_sql_now());
+
+ common_log(LOG_INFO, 'Writing backup data to ' . $tmpdir . ' for ' . $user->nickname);
+
+ mkdir($tmpdir, 0700, true);
+
+ $this->dumpNotices($user, $tmpdir);
+ $this->dumpFaves($user, $tmpdir);
+ $this->dumpSubscriptions($user, $tmpdir);
+ $this->dumpSubscribers($user, $tmpdir);
+ $this->dumpGroups($user, $tmpdir);
+
+ $fileName = File::filename($user->getProfile(), "backup", "application/atom+xml");
+ $fullPath = File::path($fileName);
+
+ $this->makeActivityFeed($user, $tmpdir, $fullPath);
+
+ $this->delTree($tmpdir);
+
+ return $fileName;
+ }
+
+ function notifyBackupFile($user, $fileName)
+ {
+ $fileUrl = File::url($fileName);
+
+ $body = sprintf(_m("The backup file you requested is ready for download.\n\n".
+ "%s\n".
+ "Thanks for your time,\n",
+ "%s\n"),
+ $fileUrl,
+ common_config('site', 'name'));
+
+ $headers = _mail_prepare_headers('offlinebackup', $user->nickname, $user->nickname);
+
+ mail_to_user($user, _('Backup file ready for download'), $body, $headers);
+ }
+
+ function dumpNotices($user, $dir)
+ {
+ common_log(LOG_INFO, 'dumping notices by ' . $user->nickname . ' to directory ' . $dir);
+
+ $profile = $user->getProfile();
+
+ $stream = new ProfileNoticeStream($profile, $profile);
+
+ $page = 1;
+
+ do {
+
+ $notice = $stream->getNotices(($page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
+
+ while ($notice->fetch()) {
+ try {
+ $fname = $dir . '/'. common_date_iso8601($notice->created) . '-notice-' . $notice->id . '.atom';
+ $data = $notice->asAtomEntry(false, false, false, null);
+ common_log(LOG_INFO, 'dumping notice ' . $notice->id . ' to file ' . $fname);
+ file_put_contents($fname, $data);
+ $data = null;
+ } catch (Exception $e) {
+ common_log(LOG_ERR, "Error backing up notice " . $notice->id . ": " . $e->getMessage());
+ continue;
+ }
+ }
+
+ $page++;
+
+ } while ($notice->N > NOTICES_PER_PAGE);
+ }
+
+ function dumpFaves($user, $dir)
+ {
+ common_log(LOG_INFO, 'dumping faves by ' . $user->nickname . ' to directory ' . $dir);
+
+ $page = 1;
+
+ do {
+ $fave = Fave::byProfile($user->id, ($page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
+
+ while ($fave->fetch()) {
+ try {
+ $fname = $dir . '/'. common_date_iso8601($fave->modified) . '-fave-' . $fave->notice_id . '.atom';
+ $act = $fave->asActivity();
+ $data = $act->asString(false, false, false);
+ common_log(LOG_INFO, 'dumping fave of ' . $fave->notice_id . ' to file ' . $fname);
+ file_put_contents($fname, $data);
+ $data = null;
+ } catch (Exception $e) {
+ common_log(LOG_ERR, "Error backing up fave of " . $fave->notice_id . ": " . $e->getMessage());
+ continue;
+ }
+ }
+
+ $page++;
+
+ } while ($fave->N > NOTICES_PER_PAGE);
+ }
+
+ function dumpSubscriptions($user, $dir)
+ {
+ common_log(LOG_INFO, 'dumping subscriptions by ' . $user->nickname . ' to directory ' . $dir);
+
+ $page = 1;
+
+ do {
+ $sub = Subscription::bySubscriber($user->id, ($page-1)*PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1);
+
+ while ($sub->fetch()) {
+ try {
+ if ($sub->subscribed == $user->id) {
+ continue;
+ }
+ $fname = $dir . '/'. common_date_iso8601($sub->created) . '-subscription-' . $sub->subscribed . '.atom';
+ $act = $sub->asActivity();
+ $data = $act->asString(false, false, false);
+ common_log(LOG_INFO, 'dumping sub of ' . $sub->subscribed . ' to file ' . $fname);
+ file_put_contents($fname, $data);
+ $data = null;
+ } catch (Exception $e) {
+ common_log(LOG_ERR, "Error backing up subscription to " . $sub->subscribed . ": " . $e->getMessage());
+ continue;
+ }
+ }
+
+ $page++;
+
+ } while ($sub->N > PROFILES_PER_PAGE);
+ }
+
+ function dumpSubscribers($user, $dir)
+ {
+ common_log(LOG_INFO, 'dumping subscribers to ' . $user->nickname . ' to directory ' . $dir);
+
+ $page = 1;
+
+ do {
+ $sub = Subscription::bySubscribed($user->id, ($page-1)*PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1);
+
+ while ($sub->fetch()) {
+ try {
+ if ($sub->subscriber == $user->id) {
+ continue;
+ }
+ $fname = $dir . '/'. common_date_iso8601($sub->created) . '-subscriber-' . $sub->subscriber . '.atom';
+ $act = $sub->asActivity();
+ $data = $act->asString(false, true, false);
+ common_log(LOG_INFO, 'dumping sub by ' . $sub->subscriber . ' to file ' . $fname);
+ file_put_contents($fname, $data);
+ $data = null;
+ } catch (Exception $e) {
+ common_log(LOG_ERR, "Error backing up subscription from " . $sub->subscriber . ": " . $e->getMessage());
+ continue;
+ }
+ }
+
+ $page++;
+
+ } while ($sub->N > PROFILES_PER_PAGE);
+ }
+
+ function dumpGroups($user, $dir)
+ {
+ common_log(LOG_INFO, 'dumping memberships of ' . $user->nickname . ' to directory ' . $dir);
+
+ $page = 1;
+
+ do {
+
+ $mem = Group_member::byMember($user->id, ($page-1)*GROUPS_PER_PAGE, GROUPS_PER_PAGE + 1);
+
+ while ($mem->fetch()) {
+ try {
+ $fname = $dir . '/'. common_date_iso8601($mem->created) . '-membership-' . $mem->group_id . '.atom';
+ $act = $mem->asActivity();
+ $data = $act->asString(false, false, false);
+ common_log(LOG_INFO, 'dumping membership in ' . $mem->group_id . ' to file ' . $fname);
+ file_put_contents($fname, $data);
+ $data = null;
+ } catch (Exception $e) {
+ common_log(LOG_ERR, "Error backing up membership in " . $mem->group_id . ": " . $e->getMessage());
+ continue;
+ }
+ }
+
+ $page++;
+
+ } while ($mem->N > GROUPS_PER_PAGE);
+ }
+
+ function makeActivityFeed($user, $tmpdir, $fullPath)
+ {
+ $handle = fopen($fullPath, 'c');
+
+ $this->writeFeedHeader($user, $handle);
+
+ $objects = scandir($tmpdir);
+
+ rsort($objects);
+
+ foreach ($objects as $object) {
+ $objFull = $tmpdir . '/' . $object;
+ if (!is_dir($objFull)) {
+ $entry = file_get_contents($objFull);
+ fwrite($handle, $entry);
+ $entry = null;
+ }
+ }
+
+ $this->writeFeedFooter($user, $handle);
+ fclose($handle);
+ }
+
+ function writeFeedHeader($user, $handle)
+ {
+ fwrite($handle, '<?xml version="1.0" encoding="UTF-8"?>');
+ fwrite($handle, "\n");
+ fwrite($handle, '<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">');
+ fwrite($handle, "\n");
+
+ $profile = $user->getProfile();
+
+ $author = ActivityObject::fromProfile($profile);
+
+ $xs = new XMLStringer();
+ $author->outputTo($xs, 'author');
+ fwrite($handle, $xs->getString());
+ fwrite($handle, "\n");
+ }
+
+ function writeFeedFooter($user, $handle)
+ {
+ fwrite($handle, '</feed>');
+ }
+
+ function delTree($dir)
+ {
+ if (is_dir($dir)) {
+ $objects = scandir($dir);
+ foreach ($objects as $object) {
+ if ($object != "." && $object != "..") {
+ if (filetype($dir."/".$object) == "dir") {
+ $this->delTree($dir."/".$object);
+ } else {
+ unlink($dir."/".$object);
+ }
+ }
+ }
+ reset($objects);
+ rmdir($dir);
+ }
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Initiate an offline backup
- *
- * PHP version 5
- *
- * 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 Offline backup
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Action to initiate an offline backup
- *
- * @category Offline backup
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class OfflinebackupAction extends BackupaccountAction
-{
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
-
- function handle($argarray=null)
- {
- if ($this->isPost()) {
- $this->queueBackup();
- } else {
- $this->showPage();
- }
- return;
- }
-
- function queueBackup()
- {
- $cur = common_current_user();
-
- $qm = QueueManager::get();
-
- $qm->enqueue($cur->id, 'backoff');
-
- $this->showPage();
- }
-
- function showContent()
- {
- if ($this->isPost()) {
- $this->text(_('Backup queued. You will get a notification by email when your backup is ready to download.'));
- } else {
- parent::showContent();
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Offline backup queue handler
- *
- * PHP version 5
- *
- * 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 Offline backup
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Offline backup queue handler
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class OfflineBackupQueueHandler extends QueueHandler
-{
- function transport()
- {
- return 'backoff';
- }
-
- function handle($object)
- {
- $userId = $object;
-
- $user = User::getKV($userId);
-
- common_log(LOG_INFO, "Making backup file for user ".$user->nickname);
-
- $fileName = $this->makeBackupFile($user);
-
- common_log(LOG_INFO, "Notifying user ".$user->nickname . " of their new backup file.");
-
- $this->notifyBackupFile($user, $fileName);
-
- return true;
- }
-
- function makeBackupFile($user)
- {
- // XXX: this is pretty lose-y; try another way
-
- $tmpdir = sys_get_temp_dir() . '/offline-backup/' . $user->nickname . '/' . common_date_iso8601(common_sql_now());
-
- common_log(LOG_INFO, 'Writing backup data to ' . $tmpdir . ' for ' . $user->nickname);
-
- mkdir($tmpdir, 0700, true);
-
- $this->dumpNotices($user, $tmpdir);
- $this->dumpFaves($user, $tmpdir);
- $this->dumpSubscriptions($user, $tmpdir);
- $this->dumpSubscribers($user, $tmpdir);
- $this->dumpGroups($user, $tmpdir);
-
- $fileName = File::filename($user->getProfile(), "backup", "application/atom+xml");
- $fullPath = File::path($fileName);
-
- $this->makeActivityFeed($user, $tmpdir, $fullPath);
-
- $this->delTree($tmpdir);
-
- return $fileName;
- }
-
- function notifyBackupFile($user, $fileName)
- {
- $fileUrl = File::url($fileName);
-
- $body = sprintf(_m("The backup file you requested is ready for download.\n\n".
- "%s\n".
- "Thanks for your time,\n",
- "%s\n"),
- $fileUrl,
- common_config('site', 'name'));
-
- $headers = _mail_prepare_headers('offlinebackup', $user->nickname, $user->nickname);
-
- mail_to_user($user, _('Backup file ready for download'), $body, $headers);
- }
-
- function dumpNotices($user, $dir)
- {
- common_log(LOG_INFO, 'dumping notices by ' . $user->nickname . ' to directory ' . $dir);
-
- $profile = $user->getProfile();
-
- $stream = new ProfileNoticeStream($profile, $profile);
-
- $page = 1;
-
- do {
-
- $notice = $stream->getNotices(($page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
-
- while ($notice->fetch()) {
- try {
- $fname = $dir . '/'. common_date_iso8601($notice->created) . '-notice-' . $notice->id . '.atom';
- $data = $notice->asAtomEntry(false, false, false, null);
- common_log(LOG_INFO, 'dumping notice ' . $notice->id . ' to file ' . $fname);
- file_put_contents($fname, $data);
- $data = null;
- } catch (Exception $e) {
- common_log(LOG_ERR, "Error backing up notice " . $notice->id . ": " . $e->getMessage());
- continue;
- }
- }
-
- $page++;
-
- } while ($notice->N > NOTICES_PER_PAGE);
- }
-
- function dumpFaves($user, $dir)
- {
- common_log(LOG_INFO, 'dumping faves by ' . $user->nickname . ' to directory ' . $dir);
-
- $page = 1;
-
- do {
- $fave = Fave::byProfile($user->id, ($page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
-
- while ($fave->fetch()) {
- try {
- $fname = $dir . '/'. common_date_iso8601($fave->modified) . '-fave-' . $fave->notice_id . '.atom';
- $act = $fave->asActivity();
- $data = $act->asString(false, false, false);
- common_log(LOG_INFO, 'dumping fave of ' . $fave->notice_id . ' to file ' . $fname);
- file_put_contents($fname, $data);
- $data = null;
- } catch (Exception $e) {
- common_log(LOG_ERR, "Error backing up fave of " . $fave->notice_id . ": " . $e->getMessage());
- continue;
- }
- }
-
- $page++;
-
- } while ($fave->N > NOTICES_PER_PAGE);
- }
-
- function dumpSubscriptions($user, $dir)
- {
- common_log(LOG_INFO, 'dumping subscriptions by ' . $user->nickname . ' to directory ' . $dir);
-
- $page = 1;
-
- do {
- $sub = Subscription::bySubscriber($user->id, ($page-1)*PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1);
-
- while ($sub->fetch()) {
- try {
- if ($sub->subscribed == $user->id) {
- continue;
- }
- $fname = $dir . '/'. common_date_iso8601($sub->created) . '-subscription-' . $sub->subscribed . '.atom';
- $act = $sub->asActivity();
- $data = $act->asString(false, false, false);
- common_log(LOG_INFO, 'dumping sub of ' . $sub->subscribed . ' to file ' . $fname);
- file_put_contents($fname, $data);
- $data = null;
- } catch (Exception $e) {
- common_log(LOG_ERR, "Error backing up subscription to " . $sub->subscribed . ": " . $e->getMessage());
- continue;
- }
- }
-
- $page++;
-
- } while ($sub->N > PROFILES_PER_PAGE);
- }
-
- function dumpSubscribers($user, $dir)
- {
- common_log(LOG_INFO, 'dumping subscribers to ' . $user->nickname . ' to directory ' . $dir);
-
- $page = 1;
-
- do {
- $sub = Subscription::bySubscribed($user->id, ($page-1)*PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1);
-
- while ($sub->fetch()) {
- try {
- if ($sub->subscriber == $user->id) {
- continue;
- }
- $fname = $dir . '/'. common_date_iso8601($sub->created) . '-subscriber-' . $sub->subscriber . '.atom';
- $act = $sub->asActivity();
- $data = $act->asString(false, true, false);
- common_log(LOG_INFO, 'dumping sub by ' . $sub->subscriber . ' to file ' . $fname);
- file_put_contents($fname, $data);
- $data = null;
- } catch (Exception $e) {
- common_log(LOG_ERR, "Error backing up subscription from " . $sub->subscriber . ": " . $e->getMessage());
- continue;
- }
- }
-
- $page++;
-
- } while ($sub->N > PROFILES_PER_PAGE);
- }
-
- function dumpGroups($user, $dir)
- {
- common_log(LOG_INFO, 'dumping memberships of ' . $user->nickname . ' to directory ' . $dir);
-
- $page = 1;
-
- do {
-
- $mem = Group_member::byMember($user->id, ($page-1)*GROUPS_PER_PAGE, GROUPS_PER_PAGE + 1);
-
- while ($mem->fetch()) {
- try {
- $fname = $dir . '/'. common_date_iso8601($mem->created) . '-membership-' . $mem->group_id . '.atom';
- $act = $mem->asActivity();
- $data = $act->asString(false, false, false);
- common_log(LOG_INFO, 'dumping membership in ' . $mem->group_id . ' to file ' . $fname);
- file_put_contents($fname, $data);
- $data = null;
- } catch (Exception $e) {
- common_log(LOG_ERR, "Error backing up membership in " . $mem->group_id . ": " . $e->getMessage());
- continue;
- }
- }
-
- $page++;
-
- } while ($mem->N > GROUPS_PER_PAGE);
- }
-
- function makeActivityFeed($user, $tmpdir, $fullPath)
- {
- $handle = fopen($fullPath, 'c');
-
- $this->writeFeedHeader($user, $handle);
-
- $objects = scandir($tmpdir);
-
- rsort($objects);
-
- foreach ($objects as $object) {
- $objFull = $tmpdir . '/' . $object;
- if (!is_dir($objFull)) {
- $entry = file_get_contents($objFull);
- fwrite($handle, $entry);
- $entry = null;
- }
- }
-
- $this->writeFeedFooter($user, $handle);
- fclose($handle);
- }
-
- function writeFeedHeader($user, $handle)
- {
- fwrite($handle, '<?xml version="1.0" encoding="UTF-8"?>');
- fwrite($handle, "\n");
- fwrite($handle, '<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:georss="http://www.georss.org/georss" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:media="http://purl.org/syndication/atommedia" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:ostatus="http://ostatus.org/schema/1.0" xmlns:statusnet="http://status.net/schema/api/1/">');
- fwrite($handle, "\n");
-
- $profile = $user->getProfile();
-
- $author = ActivityObject::fromProfile($profile);
-
- $xs = new XMLStringer();
- $author->outputTo($xs, 'author');
- fwrite($handle, $xs->getString());
- fwrite($handle, "\n");
- }
-
- function writeFeedFooter($user, $handle)
- {
- fwrite($handle, '</feed>');
- }
-
- function delTree($dir)
- {
- if (is_dir($dir)) {
- $objects = scandir($dir);
- foreach ($objects as $object) {
- if ($object != "." && $object != "..") {
- if (filetype($dir."/".$object) == "dir") {
- $this->delTree($dir."/".$object);
- } else {
- unlink($dir."/".$object);
- }
- }
- }
- reset($objects);
- rmdir($dir);
- }
- }
-}
{
switch ($cls)
{
- case 'OpenidloginAction':
- case 'FinishopenidloginAction':
- case 'FinishaddopenidAction':
- case 'XrdsAction':
- case 'PublicxrdsAction':
- case 'OpenidsettingsAction':
- case 'OpenidserverAction':
- case 'OpenidtrustAction':
- case 'OpenidadminpanelAction':
- require_once dirname(__FILE__) . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'User_openid':
- case 'User_openid_prefs':
- case 'User_openid_trustroot':
- require_once dirname(__FILE__) . '/' . $cls . '.php';
- return false;
case 'Auth_OpenID_TeamsExtension':
case 'Auth_OpenID_TeamsRequest':
case 'Auth_OpenID_TeamsResponse':
require_once dirname(__FILE__) . '/extlib/teams-extension.php';
return false;
- default:
- return true;
}
+
+ return parent::onAutoload($cls);
}
/**
+++ /dev/null
-<?php
-/**
- * Table Definition for user_openid
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-class User_openid extends Managed_DataObject
-{
- ###START_AUTOCODE
- /* the code below is auto generated do not remove the above tag */
-
- public $__table = 'user_openid'; // table name
- public $canonical; // varchar(255) primary_key not_null
- public $display; // varchar(255) unique_key not_null
- public $user_id; // int(4) not_null
- public $created; // datetime() not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- /* the code above is auto generated do not remove the tag below */
- ###END_AUTOCODE
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'canonical' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID canonical string'),
- 'display' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID display string'),
- 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'User ID for OpenID owner'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('canonical'),
- 'unique keys' => array(
- 'user_openid_display_key' => array('display'),
- ),
- 'indexes' => array(
- 'user_openid_user_id_idx' => array('user_id'),
- ),
- 'foreign keys' => array(
- 'user_openid_user_id_fkey' => array('user', array('user_id' => 'id')),
- ),
- );
- }
-
- static function hasOpenID($user_id)
- {
- $oid = new User_openid();
-
- $oid->user_id = $user_id;
-
- $cnt = $oid->find();
-
- return ($cnt > 0);
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2012, StatusNet, Inc.
- *
- * User_openid_prefs.php
- *
- * PHP version 5
- *
- * 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 OpenID
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Store preferences for OpenID use in StatusNet
- *
- * @category OpenID
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-
-class User_openid_prefs extends Managed_DataObject
-{
- public $__table = 'user_openid_prefs'; // table name
-
- public $user_id; // The User with the prefs
- public $hide_profile_link; // Hide the link on the profile block?
- public $created; // datetime
- public $modified; // datetime
-
- /**
- * The One True Thingy that must be defined and declared.
- */
-
- public static function schemaDef()
- {
- return array(
- 'description' => 'Per-user preferences for OpenID display',
- 'fields' => array('user_id' => array('type' => 'integer',
- 'not null' => true,
- 'description' => 'User whose prefs we are saving'),
- 'hide_profile_link' => array('type' => 'int',
- 'not null' => true,
- 'default' => 0,
- 'description' => 'Whether to hide profile links from profile block'),
- 'created' => array('type' => 'datetime',
- 'not null' => true,
- 'description' => 'date this record was created'),
- 'modified' => array('type' => 'datetime',
- 'not null' => true,
- 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('user_id'),
- 'foreign keys' => array('user_openid_prefs_user_id_fkey' => array('user', array('user_id' => 'id')),
- ),
- 'indexes' => array(),
- );
- }
-}
+++ /dev/null
-<?php
-/**
- * Table Definition for user_openid_trustroot
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-class User_openid_trustroot extends Managed_DataObject
-{
- ###START_AUTOCODE
- /* the code below is auto generated do not remove the above tag */
-
- public $__table = 'user_openid_trustroot'; // table name
- public $trustroot; // varchar(255) primary_key not_null
- public $user_id; // int(4) primary_key not_null
- public $created; // datetime() not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- /* the code above is auto generated do not remove the tag below */
- ###END_AUTOCODE
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'trustroot' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID trustroot string'),
- 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'User ID for OpenID trustroot owner'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('trustroot', 'user_id'),
- );
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Complete adding an OpenID
+ *
+ * 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 Settings
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+/**
+ * Complete adding an OpenID
+ *
+ * Handle the return from an OpenID verification
+ *
+ * @category Settings
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class FinishaddopenidAction extends Action
+{
+ var $msg = null;
+
+ /**
+ * Handle the redirect back from OpenID confirmation
+ *
+ * Check to see if the user's logged in, and then try
+ * to use the OpenID login system.
+ *
+ * @param array $args $_REQUEST arguments
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+ if (!common_logged_in()) {
+ // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
+ $this->clientError(_m('Not logged in.'));
+ } else {
+ $this->tryLogin();
+ }
+ }
+
+ /**
+ * Try to log in using OpenID
+ *
+ * Check the OpenID for validity; potentially store it.
+ *
+ * @return void
+ */
+ function tryLogin()
+ {
+ $consumer = oid_consumer();
+
+ $response = $consumer->complete(common_local_url('finishaddopenid'));
+
+ if ($response->status == Auth_OpenID_CANCEL) {
+ // TRANS: Status message in case the response from the OpenID provider is that the logon attempt was cancelled.
+ $this->message(_m('OpenID authentication cancelled.'));
+ return;
+ } else if ($response->status == Auth_OpenID_FAILURE) {
+ // TRANS: OpenID authentication failed; display the error message.
+ // TRANS: %s is the error message.
+ $this->message(sprintf(_m('OpenID authentication failed: %s.'),
+ $response->message));
+ } else if ($response->status == Auth_OpenID_SUCCESS) {
+
+ $display = $response->getDisplayIdentifier();
+ $canonical = ($response->endpoint && $response->endpoint->canonicalID) ?
+ $response->endpoint->canonicalID : $display;
+
+ $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
+
+ if ($sreg_resp) {
+ $sreg = $sreg_resp->contents();
+ }
+
+ // Launchpad teams extension
+ if (!oid_check_teams($response)) {
+ // TRANS: OpenID authentication error.
+ $this->message(_m('OpenID authentication aborted: You are not allowed to login to this site.'));
+ return;
+ }
+
+ $cur = common_current_user();
+
+ $other = oid_get_user($canonical);
+
+ if ($other) {
+ if ($other->id == $cur->id) {
+ // TRANS: Message in case a user tries to add an OpenID that is already connected to them.
+ $this->message(_m('You already have this OpenID!'));
+ } else {
+ // TRANS: Message in case a user tries to add an OpenID that is already used by another user.
+ $this->message(_m('Someone else already has this OpenID.'));
+ }
+ return;
+ }
+
+ // start a transaction
+
+ $cur->query('BEGIN');
+
+ $result = oid_link_user($cur->id, $canonical, $display);
+
+ if (!$result) {
+ // TRANS: Message in case the OpenID object cannot be connected to the user.
+ $this->message(_m('Error connecting user.'));
+ return;
+ }
+ if (Event::handle('StartOpenIDUpdateUser', array($cur, $canonical, &$sreg))) {
+ if ($sreg) {
+ if (!oid_update_user($cur, $sreg)) {
+ // TRANS: Message in case the user or the user profile cannot be saved in StatusNet.
+ $this->message(_m('Error updating profile.'));
+ return;
+ }
+ }
+ }
+ Event::handle('EndOpenIDUpdateUser', array($cur, $canonical, $sreg));
+
+ // success!
+
+ $cur->query('COMMIT');
+
+ oid_set_last($display);
+
+ common_redirect(common_local_url('openidsettings'), 303);
+ }
+ }
+
+ /**
+ * Show a failure message
+ *
+ * Something went wrong. Save the message, and show the page.
+ *
+ * @param string $msg Error message to show
+ *
+ * @return void
+ */
+ function message($msg)
+ {
+ $this->message = $msg;
+ $this->showPage();
+ }
+
+ /**
+ * Title of the page
+ *
+ * @return string title
+ */
+ function title()
+ {
+ // TRANS: Title after getting the status of the OpenID authorisation request.
+ return _m('OpenID Login');
+ }
+
+ /**
+ * Show error message
+ *
+ * @return void
+ */
+ function showPageNotice()
+ {
+ if ($this->message) {
+ $this->element('p', 'error', $this->message);
+ }
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+class FinishopenidloginAction extends Action
+{
+ var $error = null;
+ var $username = null;
+ var $message = null;
+
+ function handle($args)
+ {
+ parent::handle($args);
+ if (common_is_real_login()) {
+ // TRANS: Client error message trying to log on with OpenID while already logged on.
+ $this->clientError(_m('Already logged in.'));
+ } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $token = $this->trimmed('token');
+ if (!$token || $token != common_session_token()) {
+ // TRANS: Message given when there is a problem with the user's session token.
+ $this->showForm(_m('There was a problem with your session token. Try again, please.'));
+ return;
+ }
+ if ($this->arg('create')) {
+ if (!$this->boolean('license')) {
+ // TRANS: Message given if user does not agree with the site's license.
+ $this->showForm(_m('You cannot register if you do not agree to the license.'),
+ $this->trimmed('newname'));
+ return;
+ }
+ $this->createNewUser();
+ } else if ($this->arg('connect')) {
+ $this->connectUser();
+ } else {
+ // TRANS: Messag given on an unknown error.
+ $this->showForm(_m('An unknown error has occured.'),
+ $this->trimmed('newname'));
+ }
+ } else {
+ $this->tryLogin();
+ }
+ }
+
+ function showPageNotice()
+ {
+ if ($this->error) {
+ $this->element('div', array('class' => 'error'), $this->error);
+ } else {
+ $this->element('div', 'instructions',
+ // TRANS: Instructions given after a first successful logon using OpenID.
+ // TRANS: %s is the site name.
+ sprintf(_m('This is the first time you have logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
+ }
+ }
+
+ function title()
+ {
+ // TRANS: Title
+ return _m('TITLE','OpenID Account Setup');
+ }
+
+ function showForm($error=null, $username=null)
+ {
+ $this->error = $error;
+ $this->username = $username;
+
+ $this->showPage();
+ }
+
+ /**
+ * @fixme much of this duplicates core code, which is very fragile.
+ * Should probably be replaced with an extensible mini version of
+ * the core registration form.
+ */
+ function showContent()
+ {
+ if (!empty($this->message_text)) {
+ $this->element('div', array('class' => 'error'), $this->message_text);
+ return;
+ }
+
+ // We don't recognize this OpenID, so we're going to give the user
+ // two options, each in its own mini-form.
+ //
+ // First, they can create a new account using their OpenID auth
+ // info. The profile will be pre-populated with whatever name,
+ // email, and location we can get from the OpenID provider, so
+ // all we ask for is the license confirmation.
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'account_create',
+ 'class' => 'form_settings',
+ 'action' => common_local_url('finishopenidlogin')));
+ $this->hidden('token', common_session_token());
+ $this->elementStart('fieldset', array('id' => 'form_openid_createaccount'));
+ $this->element('legend', null,
+ // TRANS: Fieldset legend.
+ _m('Create new account'));
+ $this->element('p', null,
+ // TRANS: Form guide.
+ _m('Create a new user with this nickname.'));
+ $this->elementStart('ul', 'form_data');
+
+ // Hook point for captcha etc
+ Event::handle('StartRegistrationFormData', array($this));
+
+ $this->elementStart('li');
+ // TRANS: Field label.
+ $this->input('newname', _m('New nickname'),
+ ($this->username) ? $this->username : '',
+ // TRANS: Field title.
+ _m('1-64 lowercase letters or numbers, no punctuation or spaces.'));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ // TRANS: Field label.
+ $this->input('email', _m('Email'), $this->getEmail(),
+ // TRANS: Field title.
+ _m('Used only for updates, announcements, '.
+ 'and password recovery.'));
+ $this->elementEnd('li');
+
+ // Hook point for captcha etc
+ Event::handle('EndRegistrationFormData', array($this));
+
+ $this->elementStart('li');
+ $this->element('input', array('type' => 'checkbox',
+ 'id' => 'license',
+ 'class' => 'checkbox',
+ 'name' => 'license',
+ 'value' => 'true'));
+ $this->elementStart('label', array('for' => 'license',
+ 'class' => 'checkbox'));
+ // TRANS: OpenID plugin link text.
+ // TRANS: %s is a link to a license with the license name as link text.
+ $message = _m('My text and files are available under %s ' .
+ 'except this private data: password, ' .
+ 'email address, IM address, and phone number.');
+ $link = '<a href="' .
+ htmlspecialchars(common_config('license', 'url')) .
+ '">' .
+ htmlspecialchars(common_config('license', 'title')) .
+ '</a>';
+ $this->raw(sprintf(htmlspecialchars($message), $link));
+ $this->elementEnd('label');
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ // TRANS: Button label in form in which to create a new user on the site for an OpenID.
+ $this->submit('create', _m('BUTTON', 'Create'));
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+
+ // The second option is to attach this OpenID to an existing account
+ // on the local system, which they need to provide a password for.
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'account_connect',
+ 'class' => 'form_settings',
+ 'action' => common_local_url('finishopenidlogin')));
+ $this->hidden('token', common_session_token());
+ $this->elementStart('fieldset', array('id' => 'form_openid_createaccount'));
+ $this->element('legend', null,
+ // TRANS: Used as form legend for form in which to connect an OpenID to an existing user on the site.
+ _m('Connect existing account'));
+ $this->element('p', null,
+ // TRANS: User instructions for form in which to connect an OpenID to an existing user on the site.
+ _m('If you already have an account, login with your username and password to connect it to your OpenID.'));
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ // TRANS: Field label in form in which to connect an OpenID to an existing user on the site.
+ $this->input('nickname', _m('Existing nickname'));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ // TRANS: Field label in form in which to connect an OpenID to an existing user on the site.
+ $this->password('password', _m('Password'));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ // TRANS: Button text in form in which to connect an OpenID to an existing user on the site.
+ $this->submit('connect', _m('BUTTON', 'Connect'));
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+ }
+
+ /**
+ * Get specified e-mail from the form, or the OpenID sreg info, or the
+ * invite code.
+ *
+ * @return string
+ */
+ function getEmail()
+ {
+ $email = $this->trimmed('email');
+ if (!empty($email)) {
+ return $email;
+ }
+
+ // Pull from openid thingy
+ list($display, $canonical, $sreg) = $this->getSavedValues();
+ if (!empty($sreg['email'])) {
+ return $sreg['email'];
+ }
+
+ // Terrible hack for invites...
+ if (common_config('site', 'inviteonly')) {
+ $code = $_SESSION['invitecode'];
+ if ($code) {
+ $invite = Invitation::getKV($code);
+
+ if ($invite && $invite->address_type == 'email') {
+ return $invite->address;
+ }
+ }
+ }
+ return '';
+ }
+
+ function tryLogin()
+ {
+ $consumer = oid_consumer();
+
+ $response = $consumer->complete(common_local_url('finishopenidlogin'));
+
+ if ($response->status == Auth_OpenID_CANCEL) {
+ // TRANS: Status message in case the response from the OpenID provider is that the logon attempt was cancelled.
+ $this->message(_m('OpenID authentication cancelled.'));
+ return;
+ } else if ($response->status == Auth_OpenID_FAILURE) {
+ // TRANS: OpenID authentication failed; display the error message. %s is the error message.
+ $this->message(sprintf(_m('OpenID authentication failed: %s.'), $response->message));
+ } else if ($response->status == Auth_OpenID_SUCCESS) {
+ // This means the authentication succeeded; extract the
+ // identity URL and Simple Registration data (if it was
+ // returned).
+ $display = $response->getDisplayIdentifier();
+ $canonical = ($response->endpoint->canonicalID) ?
+ $response->endpoint->canonicalID : $response->getDisplayIdentifier();
+
+ oid_assert_allowed($display);
+ oid_assert_allowed($canonical);
+
+ $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
+
+ if ($sreg_resp) {
+ $sreg = $sreg_resp->contents();
+ }
+
+ // Launchpad teams extension
+ if (!oid_check_teams($response)) {
+ // TRANS: Message displayed when OpenID authentication is aborted.
+ $this->message(_m('OpenID authentication aborted: You are not allowed to login to this site.'));
+ return;
+ }
+
+ $user = oid_get_user($canonical);
+
+ if ($user) {
+ oid_set_last($display);
+ // XXX: commented out at @edd's request until better
+ // control over how data flows from OpenID provider.
+ // oid_update_user($user, $sreg);
+ common_set_user($user);
+ common_real_login(true);
+ if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
+ common_rememberme($user);
+ }
+ unset($_SESSION['openid_rememberme']);
+ $this->goHome($user->nickname);
+ } else {
+ $this->saveValues($display, $canonical, $sreg);
+ $this->showForm(null, $this->bestNewNickname($display, $sreg));
+ }
+ }
+ }
+
+ function message($msg)
+ {
+ $this->message_text = $msg;
+ $this->showPage();
+ }
+
+ function saveValues($display, $canonical, $sreg)
+ {
+ common_ensure_session();
+ $_SESSION['openid_display'] = $display;
+ $_SESSION['openid_canonical'] = $canonical;
+ $_SESSION['openid_sreg'] = $sreg;
+ }
+
+ function getSavedValues()
+ {
+ return array($_SESSION['openid_display'],
+ $_SESSION['openid_canonical'],
+ $_SESSION['openid_sreg']);
+ }
+
+ function createNewUser()
+ {
+ // FIXME: save invite code before redirect, and check here
+
+ if (!Event::handle('StartRegistrationTry', array($this))) {
+ return;
+ }
+
+ if (common_config('site', 'closed')) {
+ // TRANS: OpenID plugin message. No new user registration is allowed on the site.
+ $this->clientError(_m('Registration not allowed.'));
+ return;
+ }
+
+ $invite = null;
+
+ if (common_config('site', 'inviteonly')) {
+ $code = $_SESSION['invitecode'];
+ if (empty($code)) {
+ // TRANS: OpenID plugin message. No new user registration is allowed on the site without an invitation code, and none was provided.
+ $this->clientError(_m('Registration not allowed.'));
+ return;
+ }
+
+ $invite = Invitation::getKV($code);
+
+ if (empty($invite)) {
+ // TRANS: OpenID plugin message. No new user registration is allowed on the site without an invitation code, and the one provided was not valid.
+ $this->clientError(_m('Not a valid invitation code.'));
+ return;
+ }
+ }
+
+ try {
+ $nickname = Nickname::normalize($this->trimmed('newname'));
+ } catch (NicknameException $e) {
+ $this->showForm($e->getMessage());
+ return;
+ }
+
+ if (!User::allowed_nickname($nickname)) {
+ // TRANS: OpenID plugin message. The entered new user name is blacklisted.
+ $this->showForm(_m('Nickname not allowed.'));
+ return;
+ }
+
+ if (User::getKV('nickname', $nickname)) {
+ // TRANS: OpenID plugin message. The entered new user name is already used.
+ $this->showForm(_m('Nickname already in use. Try another one.'));
+ return;
+ }
+
+ list($display, $canonical, $sreg) = $this->getSavedValues();
+
+ if (!$display || !$canonical) {
+ // TRANS: OpenID plugin server error. A stored OpenID cannot be retrieved.
+ $this->serverError(_m('Stored OpenID not found.'));
+ return;
+ }
+
+ // Possible race condition... let's be paranoid
+
+ $other = oid_get_user($canonical);
+
+ if ($other) {
+ // TRANS: OpenID plugin server error.
+ $this->serverError(_m('Creating new account for OpenID that already has a user.'));
+ return;
+ }
+
+ Event::handle('StartOpenIDCreateNewUser', array($canonical, &$sreg));
+
+ $location = '';
+ if (!empty($sreg['country'])) {
+ if ($sreg['postcode']) {
+ // XXX: use postcode to get city and region
+ // XXX: also, store postcode somewhere -- it's valuable!
+ $location = $sreg['postcode'] . ', ' . $sreg['country'];
+ } else {
+ $location = $sreg['country'];
+ }
+ }
+
+ if (!empty($sreg['fullname']) && mb_strlen($sreg['fullname']) <= 255) {
+ $fullname = $sreg['fullname'];
+ } else {
+ $fullname = '';
+ }
+
+ $email = $this->getEmail();
+
+ // XXX: add language
+ // XXX: add timezone
+
+ $args = array('nickname' => $nickname,
+ 'email' => $email,
+ 'fullname' => $fullname,
+ 'location' => $location);
+
+ if (!empty($invite)) {
+ $args['code'] = $invite->code;
+ }
+
+ $user = User::register($args);
+
+ $result = oid_link_user($user->id, $canonical, $display);
+
+ Event::handle('EndOpenIDCreateNewUser', array($user, $canonical, $sreg));
+
+ oid_set_last($display);
+ common_set_user($user);
+ common_real_login(true);
+ if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
+ common_rememberme($user);
+ }
+ unset($_SESSION['openid_rememberme']);
+
+ Event::handle('EndRegistrationTry', array($this));
+
+ common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
+ 303);
+ }
+
+ function connectUser()
+ {
+ $nickname = $this->trimmed('nickname');
+ $password = $this->trimmed('password');
+
+ if (!common_check_user($nickname, $password)) {
+ // TRANS: OpenID plugin message.
+ $this->showForm(_m('Invalid username or password.'));
+ return;
+ }
+
+ // They're legit!
+
+ $user = User::getKV('nickname', $nickname);
+
+ list($display, $canonical, $sreg) = $this->getSavedValues();
+
+ if (!$display || !$canonical) {
+ // TRANS: OpenID plugin server error. A stored OpenID cannot be found.
+ $this->serverError(_m('Stored OpenID not found.'));
+ return;
+ }
+
+ $result = oid_link_user($user->id, $canonical, $display);
+
+ if (!$result) {
+ // TRANS: OpenID plugin server error. The user or user profile could not be saved.
+ $this->serverError(_m('Error connecting user to OpenID.'));
+ return;
+ }
+
+ if (Event::handle('StartOpenIDUpdateUser', array($user, $canonical, &$sreg))) {
+ oid_update_user($user, $sreg);
+ }
+ Event::handle('EndOpenIDUpdateUser', array($user, $canonical, $sreg));
+
+ oid_set_last($display);
+ common_set_user($user);
+ common_real_login(true);
+ if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
+ common_rememberme($user);
+ }
+ unset($_SESSION['openid_rememberme']);
+ $this->goHome($user->nickname);
+ }
+
+ function goHome($nickname)
+ {
+ $url = common_get_returnto();
+ if ($url) {
+ // We don't have to return to it again
+ common_set_returnto(null);
+ $url = common_inject_session($url);
+ } else {
+ $url = common_local_url('all',
+ array('nickname' =>
+ $nickname));
+ }
+ common_redirect($url, 303);
+ }
+
+ function bestNewNickname($display, $sreg)
+ {
+ // Try the passed-in nickname
+
+ if (!empty($sreg['nickname'])) {
+ $nickname = $this->nicknamize($sreg['nickname']);
+ if ($this->isNewNickname($nickname)) {
+ return $nickname;
+ }
+ }
+
+ // Try the full name
+
+ if (!empty($sreg['fullname'])) {
+ $fullname = $this->nicknamize($sreg['fullname']);
+ if ($this->isNewNickname($fullname)) {
+ return $fullname;
+ }
+ }
+
+ // Try the URL
+
+ $from_url = $this->openidToNickname($display);
+
+ if ($from_url && $this->isNewNickname($from_url)) {
+ return $from_url;
+ }
+
+ // XXX: others?
+
+ return null;
+ }
+
+ function isNewNickname($str)
+ {
+ if (!Nickname::isValid($str)) {
+ return false;
+ }
+ if (!User::allowed_nickname($str)) {
+ return false;
+ }
+ if (User::getKV('nickname', $str)) {
+ return false;
+ }
+ return true;
+ }
+
+ function openidToNickname($openid)
+ {
+ if (Auth_Yadis_identifierScheme($openid) == 'XRI') {
+ return $this->xriToNickname($openid);
+ } else {
+ return $this->urlToNickname($openid);
+ }
+ }
+
+ // We try to use an OpenID URL as a legal StatusNet user name in this order
+ // 1. Plain hostname, like http://evanp.myopenid.com/
+ // 2. One element in path, like http://profile.typekey.com/EvanProdromou/
+ // or http://getopenid.com/evanprodromou
+ function urlToNickname($openid)
+ {
+ return common_url_to_nickname($openid);
+ }
+
+ function xriToNickname($xri)
+ {
+ $base = $this->xriBase($xri);
+
+ if (!$base) {
+ return null;
+ } else {
+ // =evan.prodromou
+ // or @gratis*evan.prodromou
+ $parts = explode('*', substr($base, 1));
+ return $this->nicknamize(array_pop($parts));
+ }
+ }
+
+ function xriBase($xri)
+ {
+ if (substr($xri, 0, 6) == 'xri://') {
+ return substr($xri, 6);
+ } else {
+ return $xri;
+ }
+ }
+
+ // Given a string, try to make it work as a nickname
+ function nicknamize($str)
+ {
+ return common_nicknamize($str);
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * OpenID bridge administration panel
+ *
+ * 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 Settings
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Administer global OpenID settings
+ *
+ * @category Admin
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ */
+class OpenidadminpanelAction extends AdminPanelAction
+{
+ /**
+ * Returns the page title
+ *
+ * @return string page title
+ */
+ function title()
+ {
+ // TRANS: Title for OpenID bridge administration page.
+ return _m('TITLE','OpenID Settings');
+ }
+
+ /**
+ * Instructions for using this form.
+ *
+ * @return string instructions
+ */
+ function getInstructions()
+ {
+ // TRANS: Page instructions.
+ return _m('OpenID settings');
+ }
+
+ /**
+ * Show the OpenID admin panel form
+ *
+ * @return void
+ */
+ function showForm()
+ {
+ $form = new OpenIDAdminPanelForm($this);
+ $form->show();
+ return;
+ }
+
+ /**
+ * Save settings from the form
+ *
+ * @return void
+ */
+ function saveSettings()
+ {
+ static $settings = array(
+ 'openid' => array('trusted_provider', 'required_team')
+ );
+
+ static $booleans = array(
+ 'openid' => array('append_username'),
+ 'site' => array('openidonly')
+ );
+
+ $values = array();
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ $values[$section][$setting]
+ = $this->trimmed($setting);
+ }
+ }
+
+ foreach ($booleans as $section => $parts) {
+ foreach ($parts as $setting) {
+ $values[$section][$setting]
+ = ($this->boolean($setting)) ? 1 : 0;
+ }
+ }
+
+ // This throws an exception on validation errors
+
+ $this->validate($values);
+
+ // assert(all values are valid);
+
+ $config = new Config();
+
+ $config->query('BEGIN');
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ Config::save($section, $setting, $values[$section][$setting]);
+ }
+ }
+
+ foreach ($booleans as $section => $parts) {
+ foreach ($parts as $setting) {
+ Config::save($section, $setting, $values[$section][$setting]);
+ }
+ }
+
+ $config->query('COMMIT');
+
+ return;
+ }
+
+ function validate(&$values)
+ {
+ // Validate consumer key and secret (can't be too long)
+
+ if (mb_strlen($values['openid']['trusted_provider']) > 255) {
+ $this->clientError(
+ // TRANS: Client error displayed when OpenID provider URL is too long.
+ _m('Invalid provider URL. Maximum length is 255 characters.')
+ );
+ }
+
+ if (mb_strlen($values['openid']['required_team']) > 255) {
+ $this->clientError(
+ // TRANS: Client error displayed when Launchpad team name is too long.
+ _m('Invalid team name. Maximum length is 255 characters.')
+ );
+ }
+ }
+}
+
+class OpenIDAdminPanelForm extends AdminForm
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'openidadminpanel';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('openidadminpanel');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ *
+ * @todo Some of the options could prevent users from logging in again.
+ * Make sure that the acting administrator has a valid OpenID matching,
+ * or more carefully warn folks.
+ */
+ function formData()
+ {
+ $this->out->elementStart(
+ 'fieldset',
+ array('id' => 'settings_openid')
+ );
+ // TRANS: Fieldset legend.
+ $this->out->element('legend', null, _m('LEGEND','Trusted provider'));
+ $this->out->element('p', 'form_guide',
+ // TRANS: Form guide.
+ _m('By default, users are allowed to authenticate with any OpenID provider. ' .
+ 'If you are using your own OpenID service for shared sign-in, ' .
+ 'you can restrict access to only your own users here.'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->input(
+ 'trusted_provider',
+ // TRANS: Field label.
+ _m('Provider URL'),
+ // TRANS: Field title.
+ _m('All OpenID logins will be sent to this URL; other providers may not be used.'),
+ 'openid'
+ );
+ $this->unli();
+
+ $this->li();
+ $this->out->checkbox(
+ // TRANS: Checkbox label.
+ 'append_username', _m('Append a username to base URL'),
+ (bool) $this->value('append_username', 'openid'),
+ // TRANS: Checkbox title.
+ _m('Login form will show the base URL and prompt for a username to add at the end. Use when OpenID provider URL should be the profile page for individual users.'),
+ 'true'
+ );
+ $this->unli();
+
+ $this->li();
+ $this->input(
+ 'required_team',
+ // TRANS: Field label.
+ _m('Required team'),
+ // TRANS: Field title.
+ _m('Only allow logins from users in the given team (Launchpad extension).'),
+ 'openid'
+ );
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('fieldset');
+
+ $this->out->elementStart(
+ 'fieldset',
+ array('id' => 'settings_openid-options')
+ );
+ // TRANS: Fieldset legend.
+ $this->out->element('legend', null, _m('LEGEND','Options'));
+
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+
+ $this->out->checkbox(
+ // TRANS: Checkbox label.
+ 'openidonly', _m('Enable OpenID-only mode'),
+ (bool) $this->value('openidonly', 'site'),
+ // TRANS: Checkbox title.
+ _m('Require all users to login via OpenID. Warning: disables password authentication for all users!'),
+ 'true'
+ );
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text to save OpenID settings.
+ $this->out->submit('submit', _m('BUTTON','Save'), 'submit', null,
+ // TRANS: Button title to save OpenID settings.
+ _m('Save OpenID settings.'));
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+class OpenidloginAction extends Action
+{
+ function handle($args)
+ {
+ parent::handle($args);
+ if (common_is_real_login()) {
+ // TRANS: Client error message trying to log on with OpenID while already logged on.
+ $this->clientError(_m('Already logged in.'));
+ } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $provider = common_config('openid', 'trusted_provider');
+ if ($provider) {
+ $openid_url = $provider;
+ if (common_config('openid', 'append_username')) {
+ $openid_url .= $this->trimmed('openid_username');
+ }
+ } else {
+ $openid_url = $this->trimmed('openid_url');
+ }
+
+ oid_assert_allowed($openid_url);
+
+ $rememberme = $this->boolean('rememberme');
+
+ common_ensure_session();
+
+ $_SESSION['openid_rememberme'] = $rememberme;
+
+ $result = oid_authenticate($openid_url,
+ 'finishopenidlogin');
+
+ if (is_string($result)) { # error message
+ unset($_SESSION['openid_rememberme']);
+ $this->showForm($result, $openid_url);
+ }
+ } else {
+ $openid_url = oid_get_last();
+ $this->showForm(null, $openid_url);
+ }
+ }
+
+ function getInstructions()
+ {
+ if (common_logged_in() && !common_is_real_login() &&
+ common_get_returnto()) {
+ // rememberme logins have to reauthenticate before
+ // changing any profile settings (cookie-stealing protection)
+ // TRANS: OpenID plugin message. Rememberme logins have to reauthenticate before changing any profile settings.
+ // TRANS: "OpenID" is the display text for a link with URL "(%%doc.openid%%)".
+ return _m('For security reasons, please re-login with your ' .
+ '[OpenID](%%doc.openid%%) ' .
+ 'before changing your settings.');
+ } else {
+ // TRANS: OpenID plugin message.
+ // TRANS: "OpenID" is the display text for a link with URL "(%%doc.openid%%)".
+ return _m('Login with an [OpenID](%%doc.openid%%) account.');
+ }
+ }
+
+ function showPageNotice()
+ {
+ if ($this->error) {
+ $this->element('div', array('class' => 'error'), $this->error);
+ } else {
+ $instr = $this->getInstructions();
+ $output = common_markup_to_html($instr);
+ $this->elementStart('div', 'instructions');
+ $this->raw($output);
+ $this->elementEnd('div');
+ }
+ }
+
+ function showScripts()
+ {
+ parent::showScripts();
+ if (common_config('openid', 'trusted_provider')) {
+ if (common_config('openid', 'append_username')) {
+ $this->autofocus('openid_username');
+ } else {
+ $this->autofocus('rememberme');
+ }
+ } else {
+ $this->autofocus('openid_url');
+ }
+ }
+
+ function title()
+ {
+ // TRANS: OpenID plugin message. Title.
+ return _m('TITLE','OpenID Login');
+ }
+
+ function showForm($error=null, $openid_url)
+ {
+ $this->error = $error;
+ $this->openid_url = $openid_url;
+ $this->showPage();
+ }
+
+ function showContent() {
+ $formaction = common_local_url('openidlogin');
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'form_openid_login',
+ 'class' => 'form_settings',
+ 'action' => $formaction));
+ $this->elementStart('fieldset');
+ // TRANS: OpenID plugin logon form legend.
+ $this->element('legend', null, _m('LEGEND','OpenID login'));
+
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $provider = common_config('openid', 'trusted_provider');
+ $appendUsername = common_config('openid', 'append_username');
+ if ($provider) {
+ // TRANS: Field label.
+ $this->element('label', array(), _m('LABEL','OpenID provider'));
+ $this->element('span', array(), $provider);
+ if ($appendUsername) {
+ $this->element('input', array('id' => 'openid_username',
+ 'name' => 'openid_username',
+ 'style' => 'float: none'));
+ }
+ $this->element('p', 'form_guide',
+ // TRANS: Form guide.
+ ($appendUsername ? _m('Enter your username.') . ' ' : '') .
+ // TRANS: Form guide.
+ _m('You will be sent to the provider\'s site for authentication.'));
+ $this->hidden('openid_url', $provider);
+ } else {
+ // TRANS: OpenID plugin logon form field label.
+ $this->input('openid_url', _m('OpenID URL'),
+ $this->openid_url,
+ // TRANS: OpenID plugin logon form field title.
+ _m('Your OpenID URL.'));
+ }
+ $this->elementEnd('li');
+ $this->elementStart('li', array('id' => 'settings_rememberme'));
+ // TRANS: OpenID plugin logon form checkbox label for setting to put the OpenID information in a cookie.
+ $this->checkbox('rememberme', _m('Remember me'), false,
+ // TRANS: OpenID plugin logon form field title.
+ _m('Automatically login in the future; ' .
+ 'not for shared computers!'));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ // TRANS: OpenID plugin logon form button label to start logon with the data provided in the logon form.
+ $this->submit('submit', _m('BUTTON', 'Login'));
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+ }
+
+ function showLocalNav()
+ {
+ $nav = new LoginGroupNav($this);
+ $nav->show();
+ }
+
+ function showNoticeForm()
+ {
+ }
+
+ function showProfileBlock()
+ {
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Settings for OpenID
+ *
+ * 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 Settings
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+/**
+ * Settings for OpenID
+ *
+ * Lets users add, edit and delete OpenIDs from their account
+ *
+ * @category Settings
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class OpenidserverAction extends Action
+{
+ var $oserver;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $this->oserver = oid_server();
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $request = $this->oserver->decodeRequest();
+ if (in_array($request->mode, array('checkid_immediate',
+ 'checkid_setup'))) {
+ $user = common_current_user();
+ if(!$user){
+ if($request->immediate){
+ //cannot prompt the user to login in immediate mode, so answer false
+ $response = $this->generateDenyResponse($request);
+ }else{
+ // Go log in, and then come back.
+ //
+ // Note: 303 redirect rather than 307 to avoid
+ // prompting user for form resubmission if we
+ // were POSTed here.
+ common_set_returnto($_SERVER['REQUEST_URI']);
+ common_redirect(common_local_url('login'), 303);
+ return;
+ }
+ }else if(common_profile_url($user->nickname) == $request->identity || $request->idSelect()){
+ $user_openid_trustroot = User_openid_trustroot::pkeyGet(
+ array('user_id'=>$user->id, 'trustroot'=>$request->trust_root));
+ if(empty($user_openid_trustroot)){
+ if($request->immediate){
+ //cannot prompt the user to trust this trust root in immediate mode, so answer false
+ $response = $this->generateDenyResponse($request);
+ }else{
+ common_ensure_session();
+ $_SESSION['openid_trust_root'] = $request->trust_root;
+ $allowResponse = $this->generateAllowResponse($request, $user);
+ $this->oserver->encodeResponse($allowResponse); //sign the response
+ $denyResponse = $this->generateDenyResponse($request);
+ $this->oserver->encodeResponse($denyResponse); //sign the response
+ $_SESSION['openid_allow_url'] = $allowResponse->encodeToUrl();
+ $_SESSION['openid_deny_url'] = $denyResponse->encodeToUrl();
+
+ // Ask the user to trust this trust root...
+ //
+ // Note: 303 redirect rather than 307 to avoid
+ // prompting user for form resubmission if we
+ // were POSTed here.
+ common_redirect(common_local_url('openidtrust'), 303);
+ return;
+ }
+ }else{
+ //user has previously authorized this trust root
+ $response = $this->generateAllowResponse($request, $user);
+ //$response = $request->answer(true, null, common_profile_url($user->nickname));
+ }
+ } else if ($request->immediate) {
+ $response = $this->generateDenyResponse($request);
+ } else {
+ //invalid
+ // TRANS: OpenID plugin client error given trying to add an unauthorised OpenID to a user (403).
+ // TRANS: %s is a request identity.
+ $this->clientError(sprintf(_m('You are not authorized to use the identity %s.'),$request->identity),$code=403);
+ }
+ } else {
+ $response = $this->oserver->handleRequest($request);
+ }
+
+ if($response){
+ $response = $this->oserver->encodeResponse($response);
+ if ($response->code != AUTH_OPENID_HTTP_OK) {
+ header(sprintf("HTTP/1.1 %d ", $response->code),
+ true, $response->code);
+ }
+
+ if($response->headers){
+ foreach ($response->headers as $k => $v) {
+ header("$k: $v");
+ }
+ }
+ $this->raw($response->body);
+ }else{
+ // TRANS: OpenID plugin client error given when not getting a response for a given OpenID provider (500).
+ $this->clientError(_m('Just an OpenID provider. Nothing to see here, move along...'),$code=500);
+ }
+ }
+
+ function generateAllowResponse($request, $user){
+ $response = $request->answer(true, null, common_profile_url($user->nickname));
+
+ $profile = $user->getProfile();
+ $sreg_data = array(
+ 'fullname' => $profile->fullname,
+ 'nickname' => $user->nickname,
+ 'email' => $user->email,
+ 'language' => $user->language,
+ 'timezone' => $user->timezone);
+ $sreg_request = Auth_OpenID_SRegRequest::fromOpenIDRequest($request);
+ $sreg_response = Auth_OpenID_SRegResponse::extractResponse(
+ $sreg_request, $sreg_data);
+ $sreg_response->toMessage($response->fields);
+ return $response;
+ }
+
+ function generateDenyResponse($request){
+ $response = $request->answer(false);
+ return $response;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Settings for OpenID
+ *
+ * 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 Settings
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+/**
+ * Settings for OpenID
+ *
+ * Lets users add, edit and delete OpenIDs from their account
+ *
+ * @category Settings
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class OpenidsettingsAction extends SettingsAction
+{
+ /**
+ * Title of the page
+ *
+ * @return string Page title
+ */
+ function title()
+ {
+ // TRANS: Title of OpenID settings page for a user.
+ return _m('TITLE','OpenID settings');
+ }
+
+ /**
+ * Instructions for use
+ *
+ * @return string Instructions for use
+ */
+ function getInstructions()
+ {
+ // TRANS: Form instructions for OpenID settings.
+ // TRANS: This message contains Markdown links in the form [description](link).
+ return _m('[OpenID](%%doc.openid%%) lets you log into many sites ' .
+ 'with the same user account. '.
+ 'Manage your associated OpenIDs from here.');
+ }
+
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('openid_url');
+ }
+
+ /**
+ * Show the form for OpenID management
+ *
+ * We have one form with a few different submit buttons to do different things.
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $user = common_current_user();
+
+ if (!common_config('openid', 'trusted_provider')) {
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'form_settings_openid_add',
+ 'class' => 'form_settings',
+ 'action' =>
+ common_local_url('openidsettings')));
+ $this->elementStart('fieldset', array('id' => 'settings_openid_add'));
+
+ // TRANS: Fieldset legend.
+ $this->element('legend', null, _m('LEGEND','Add OpenID'));
+ $this->hidden('token', common_session_token());
+ $this->element('p', 'form_guide',
+ // TRANS: Form guide.
+ _m('If you want to add an OpenID to your account, ' .
+ 'enter it in the box below and click "Add".'));
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->element('label', array('for' => 'openid_url'),
+ // TRANS: Field label.
+ _m('OpenID URL'));
+ $this->element('input', array('name' => 'openid_url',
+ 'type' => 'text',
+ 'id' => 'openid_url'));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->element('input', array('type' => 'submit',
+ 'id' => 'settings_openid_add_action-submit',
+ 'name' => 'add',
+ 'class' => 'submit',
+ // TRANS: Button text for adding an OpenID URL.
+ 'value' => _m('BUTTON','Add')));
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+ }
+ $oid = new User_openid();
+
+ $oid->user_id = $user->id;
+
+ $cnt = $oid->find();
+
+ if ($cnt > 0) {
+ // TRANS: Header on OpenID settings page.
+ $this->element('h2', null, _m('HEADER','Remove OpenID'));
+
+ if ($cnt == 1 && !$user->password) {
+
+ $this->element('p', 'form_guide',
+ // TRANS: Form guide.
+ _m('Removing your only OpenID '.
+ 'would make it impossible to log in! ' .
+ 'If you need to remove it, '.
+ 'add another OpenID first.'));
+
+ if ($oid->fetch()) {
+ $this->elementStart('p');
+ $this->element('a', array('href' => $oid->canonical),
+ $oid->display);
+ $this->elementEnd('p');
+ }
+
+ } else {
+
+ $this->element('p', 'form_guide',
+ // TRANS: Form guide.
+ _m('You can remove an OpenID from your account '.
+ 'by clicking the button marked "Remove".'));
+ $idx = 0;
+
+ while ($oid->fetch()) {
+ $this->elementStart('form',
+ array('method' => 'POST',
+ 'id' => 'form_settings_openid_delete' . $idx,
+ 'class' => 'form_settings',
+ 'action' =>
+ common_local_url('openidsettings')));
+ $this->elementStart('fieldset');
+ $this->hidden('token', common_session_token());
+ $this->element('a', array('href' => $oid->canonical),
+ $oid->display);
+ $this->element('input', array('type' => 'hidden',
+ 'id' => 'openid_url'.$idx,
+ 'name' => 'openid_url',
+ 'value' => $oid->canonical));
+ $this->element('input', array('type' => 'submit',
+ 'id' => 'remove'.$idx,
+ 'name' => 'remove',
+ 'class' => 'submit remove',
+ // TRANS: Button text to remove an OpenID.
+ 'value' => _m('BUTTON','Remove')));
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+ $idx++;
+ }
+ }
+ }
+
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'form_settings_openid_trustroots',
+ 'class' => 'form_settings',
+ 'action' =>
+ common_local_url('openidsettings')));
+ $this->elementStart('fieldset', array('id' => 'settings_openid_trustroots'));
+ // TRANS: Fieldset legend.
+ $this->element('legend', null, _m('OpenID Trusted Sites'));
+ $this->hidden('token', common_session_token());
+ $this->element('p', 'form_guide',
+ // TRANS: Form guide.
+ _m('The following sites are allowed to access your ' .
+ 'identity and log you in. You can remove a site from ' .
+ 'this list to deny it access to your OpenID.'));
+ $this->elementStart('ul', 'form_data');
+ $user_openid_trustroot = new User_openid_trustroot();
+ $user_openid_trustroot->user_id=$user->id;
+ if($user_openid_trustroot->find()) {
+ while($user_openid_trustroot->fetch()) {
+ $this->elementStart('li');
+ $this->element('input', array('name' => 'openid_trustroot[]',
+ 'type' => 'checkbox',
+ 'class' => 'checkbox',
+ 'value' => $user_openid_trustroot->trustroot,
+ 'id' => 'openid_trustroot_' . crc32($user_openid_trustroot->trustroot)));
+ $this->element('label', array('class'=>'checkbox', 'for' => 'openid_trustroot_' . crc32($user_openid_trustroot->trustroot)),
+ $user_openid_trustroot->trustroot);
+ $this->elementEnd('li');
+ }
+ }
+ $this->elementEnd('ul');
+ $this->element('input', array('type' => 'submit',
+ 'id' => 'settings_openid_trustroots_action-submit',
+ 'name' => 'remove_trustroots',
+ 'class' => 'submit',
+ // TRANS: Button text to remove an OpenID trustroot.
+ 'value' => _m('BUTTON','Remove')));
+ $this->elementEnd('fieldset');
+
+ $prefs = User_openid_prefs::getKV('user_id', $user->id);
+
+ $this->elementStart('fieldset');
+ $this->element('legend', null, _m('LEGEND','Preferences'));
+ $this->elementStart('ul', 'form_data');
+ $this->checkBox('hide_profile_link', "Hide OpenID links from my profile", !empty($prefs) && $prefs->hide_profile_link);
+ $this->element('input', array('type' => 'submit',
+ 'id' => 'settings_openid_prefs_save',
+ 'name' => 'save_prefs',
+ 'class' => 'submit',
+ // TRANS: Button text to save OpenID prefs
+ 'value' => _m('BUTTON','Save')));
+ $this->elementEnd('ul');
+ $this->elementEnd('fieldset');
+
+ $this->elementEnd('form');
+ }
+
+ /**
+ * Handle a POST request
+ *
+ * Muxes to different sub-functions based on which button was pushed
+ *
+ * @return void
+ */
+ function handlePost()
+ {
+ // CSRF protection
+ $token = $this->trimmed('token');
+ if (!$token || $token != common_session_token()) {
+ // TRANS: Client error displayed when the session token does not match or is not given.
+ $this->showForm(_m('There was a problem with your session token. '.
+ 'Try again, please.'));
+ return;
+ }
+
+ if ($this->arg('add')) {
+ if (common_config('openid', 'trusted_provider')) {
+ // TRANS: Form validation error if no OpenID providers can be added.
+ $this->showForm(_m('Cannot add new providers.'));
+ } else {
+ $result = oid_authenticate($this->trimmed('openid_url'),
+ 'finishaddopenid');
+ if (is_string($result)) { // error message
+ $this->showForm($result);
+ }
+ }
+ } else if ($this->arg('remove')) {
+ $this->removeOpenid();
+ } else if($this->arg('remove_trustroots')) {
+ $this->removeTrustroots();
+ } else if($this->arg('save_prefs')) {
+ $this->savePrefs();
+ } else {
+ // TRANS: Unexpected form validation error.
+ $this->showForm(_m('Something weird happened.'));
+ }
+ }
+
+ /**
+ * Handles a request to remove OpenID trustroots from the user's account
+ *
+ * Validates input and, if everything is OK, deletes the trustroots.
+ * Reloads the form with a success or error notification.
+ *
+ * @return void
+ */
+ function removeTrustroots()
+ {
+ $user = common_current_user();
+ $trustroots = $this->arg('openid_trustroot');
+ if($trustroots) {
+ foreach($trustroots as $trustroot) {
+ $user_openid_trustroot = User_openid_trustroot::pkeyGet(
+ array('user_id'=>$user->id, 'trustroot'=>$trustroot));
+ if($user_openid_trustroot) {
+ $user_openid_trustroot->delete();
+ } else {
+ // TRANS: Form validation error when trying to remove a non-existing trustroot.
+ $this->showForm(_m('No such OpenID trustroot.'));
+ return;
+ }
+ }
+ // TRANS: Success message after removing trustroots.
+ $this->showForm(_m('Trustroots removed.'), true);
+ } else {
+ $this->showForm();
+ }
+ return;
+ }
+
+ /**
+ * Handles a request to remove an OpenID from the user's account
+ *
+ * Validates input and, if everything is OK, deletes the OpenID.
+ * Reloads the form with a success or error notification.
+ *
+ * @return void
+ */
+ function removeOpenid()
+ {
+ $openid_url = $this->trimmed('openid_url');
+
+ $oid = User_openid::getKV('canonical', $openid_url);
+
+ if (!$oid) {
+ // TRANS: Form validation error for a non-existing OpenID.
+ $this->showForm(_m('No such OpenID.'));
+ return;
+ }
+ $cur = common_current_user();
+ if (!$cur || $oid->user_id != $cur->id) {
+ // TRANS: Form validation error if OpenID is connected to another user.
+ $this->showForm(_m('That OpenID does not belong to you.'));
+ return;
+ }
+ $oid->delete();
+ // TRANS: Success message after removing an OpenID.
+ $this->showForm(_m('OpenID removed.'), true);
+ return;
+ }
+
+ /**
+ * Handles a request to save preferences
+ *
+ * Validates input and, if everything is OK, deletes the OpenID.
+ * Reloads the form with a success or error notification.
+ *
+ * @return void
+ */
+ function savePrefs()
+ {
+ $cur = common_current_user();
+
+ if (empty($cur)) {
+ throw new ClientException(_("Not logged in."));
+ }
+
+ $orig = null;
+ $prefs = User_openid_prefs::getKV('user_id', $cur->id);
+
+ if (empty($prefs)) {
+ $prefs = new User_openid_prefs();
+ $prefs->user_id = $cur->id;
+ $prefs->created = common_sql_now();
+ } else {
+ $orig = clone($prefs);
+ }
+
+ $prefs->hide_profile_link = $this->boolean('hide_profile_link');
+
+ if (empty($orig)) {
+ $prefs->insert();
+ } else {
+ $prefs->update($orig);
+ }
+
+ $this->showForm(_m('OpenID preferences saved.'), true);
+ return;
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+class OpenidtrustAction extends Action
+{
+ var $trust_root;
+ var $allowUrl;
+ var $denyUrl;
+ var $user;
+
+ /**
+ * Is this a read-only action?
+ *
+ * @return boolean false
+ */
+ function isReadOnly($args)
+ {
+ return false;
+ }
+
+ /**
+ * Title of the page
+ *
+ * @return string title of the page
+ */
+ function title()
+ {
+ // TRANS: Title for identity verification page.
+ return _m('OpenID Identity Verification');
+ }
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ common_ensure_session();
+ $this->user = common_current_user();
+ if(empty($this->user)){
+ /* Go log in, and then come back. */
+ common_set_returnto($_SERVER['REQUEST_URI']);
+ common_redirect(common_local_url('login'));
+ return;
+ }
+ $this->trust_root = $_SESSION['openid_trust_root'];
+ $this->allowUrl = $_SESSION['openid_allow_url'];
+ $this->denyUrl = $_SESSION['openid_deny_url'];
+ if(empty($this->trust_root) || empty($this->allowUrl) || empty($this->denyUrl)){
+ // TRANS: Client error when visiting page directly.
+ $this->clientError(_m('This page should only be reached during OpenID processing, not directly.'));
+ return;
+ }
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ if($_SERVER['REQUEST_METHOD'] == 'POST'){
+ $this->handleSubmit();
+ }else{
+ $this->showPage();
+ }
+ }
+
+ function handleSubmit()
+ {
+ unset($_SESSION['openid_trust_root']);
+ unset($_SESSION['openid_allow_url']);
+ unset($_SESSION['openid_deny_url']);
+ if($this->arg('allow'))
+ {
+ //save to database
+ $user_openid_trustroot = new User_openid_trustroot();
+ $user_openid_trustroot->user_id = $this->user->id;
+ $user_openid_trustroot->trustroot = $this->trust_root;
+ $user_openid_trustroot->created = DB_DataObject_Cast::dateTime();
+ if (!$user_openid_trustroot->insert()) {
+ $err = PEAR::getStaticProperty('DB_DataObject','lastError');
+ }
+ common_redirect($this->allowUrl, $code=302);
+ }else{
+ common_redirect($this->denyUrl, $code=302);
+ }
+ }
+
+ /**
+ * Show page notice
+ *
+ * Display a notice for how to use the page, or the
+ * error if it exists.
+ *
+ * @return void
+ */
+ function showPageNotice()
+ {
+ // TRANS: Page notice. %s is a trustroot name.
+ $this->element('p',null,sprintf(_m('%s has asked to verify your identity. Click Continue to verify your identity and login without creating a new password.'),$this->trust_root));
+ }
+
+ /**
+ * Core of the display code
+ *
+ * Shows the login form.
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'form_openidtrust',
+ 'class' => 'form_settings',
+ 'action' => common_local_url('openidtrust')));
+ $this->elementStart('fieldset');
+ // TRANS: Button text to continue OpenID identity verification.
+ $this->submit('allow', _m('BUTTON','Continue'));
+ // TRANS: Button text to cancel OpenID identity verification.
+ $this->submit('deny', _m('BUTTON','Cancel'));
+
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+ }
+}
--- /dev/null
+<?php
+/**
+ * Table Definition for user_openid
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class User_openid extends Managed_DataObject
+{
+ ###START_AUTOCODE
+ /* the code below is auto generated do not remove the above tag */
+
+ public $__table = 'user_openid'; // table name
+ public $canonical; // varchar(255) primary_key not_null
+ public $display; // varchar(255) unique_key not_null
+ public $user_id; // int(4) not_null
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ /* the code above is auto generated do not remove the tag below */
+ ###END_AUTOCODE
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'canonical' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID canonical string'),
+ 'display' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID display string'),
+ 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'User ID for OpenID owner'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('canonical'),
+ 'unique keys' => array(
+ 'user_openid_display_key' => array('display'),
+ ),
+ 'indexes' => array(
+ 'user_openid_user_id_idx' => array('user_id'),
+ ),
+ 'foreign keys' => array(
+ 'user_openid_user_id_fkey' => array('user', array('user_id' => 'id')),
+ ),
+ );
+ }
+
+ static function hasOpenID($user_id)
+ {
+ $oid = new User_openid();
+
+ $oid->user_id = $user_id;
+
+ $cnt = $oid->find();
+
+ return ($cnt > 0);
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * User_openid_prefs.php
+ *
+ * PHP version 5
+ *
+ * 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 OpenID
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Store preferences for OpenID use in StatusNet
+ *
+ * @category OpenID
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+
+class User_openid_prefs extends Managed_DataObject
+{
+ public $__table = 'user_openid_prefs'; // table name
+
+ public $user_id; // The User with the prefs
+ public $hide_profile_link; // Hide the link on the profile block?
+ public $created; // datetime
+ public $modified; // datetime
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'Per-user preferences for OpenID display',
+ 'fields' => array('user_id' => array('type' => 'integer',
+ 'not null' => true,
+ 'description' => 'User whose prefs we are saving'),
+ 'hide_profile_link' => array('type' => 'int',
+ 'not null' => true,
+ 'default' => 0,
+ 'description' => 'Whether to hide profile links from profile block'),
+ 'created' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('user_id'),
+ 'foreign keys' => array('user_openid_prefs_user_id_fkey' => array('user', array('user_id' => 'id')),
+ ),
+ 'indexes' => array(),
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * Table Definition for user_openid_trustroot
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class User_openid_trustroot extends Managed_DataObject
+{
+ ###START_AUTOCODE
+ /* the code below is auto generated do not remove the above tag */
+
+ public $__table = 'user_openid_trustroot'; // table name
+ public $trustroot; // varchar(255) primary_key not_null
+ public $user_id; // int(4) primary_key not_null
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ /* the code above is auto generated do not remove the tag below */
+ ###END_AUTOCODE
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'trustroot' => array('type' => 'varchar', 'not null' => true, 'length' => 255, 'description' => 'OpenID trustroot string'),
+ 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'User ID for OpenID trustroot owner'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('trustroot', 'user_id'),
+ );
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Complete adding an OpenID
- *
- * 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 Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/plugins/OpenID/openid.php';
-
-/**
- * Complete adding an OpenID
- *
- * Handle the return from an OpenID verification
- *
- * @category Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class FinishaddopenidAction extends Action
-{
- var $msg = null;
-
- /**
- * Handle the redirect back from OpenID confirmation
- *
- * Check to see if the user's logged in, and then try
- * to use the OpenID login system.
- *
- * @param array $args $_REQUEST arguments
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
- if (!common_logged_in()) {
- // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
- $this->clientError(_m('Not logged in.'));
- } else {
- $this->tryLogin();
- }
- }
-
- /**
- * Try to log in using OpenID
- *
- * Check the OpenID for validity; potentially store it.
- *
- * @return void
- */
- function tryLogin()
- {
- $consumer = oid_consumer();
-
- $response = $consumer->complete(common_local_url('finishaddopenid'));
-
- if ($response->status == Auth_OpenID_CANCEL) {
- // TRANS: Status message in case the response from the OpenID provider is that the logon attempt was cancelled.
- $this->message(_m('OpenID authentication cancelled.'));
- return;
- } else if ($response->status == Auth_OpenID_FAILURE) {
- // TRANS: OpenID authentication failed; display the error message.
- // TRANS: %s is the error message.
- $this->message(sprintf(_m('OpenID authentication failed: %s.'),
- $response->message));
- } else if ($response->status == Auth_OpenID_SUCCESS) {
-
- $display = $response->getDisplayIdentifier();
- $canonical = ($response->endpoint && $response->endpoint->canonicalID) ?
- $response->endpoint->canonicalID : $display;
-
- $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
-
- if ($sreg_resp) {
- $sreg = $sreg_resp->contents();
- }
-
- // Launchpad teams extension
- if (!oid_check_teams($response)) {
- // TRANS: OpenID authentication error.
- $this->message(_m('OpenID authentication aborted: You are not allowed to login to this site.'));
- return;
- }
-
- $cur = common_current_user();
-
- $other = oid_get_user($canonical);
-
- if ($other) {
- if ($other->id == $cur->id) {
- // TRANS: Message in case a user tries to add an OpenID that is already connected to them.
- $this->message(_m('You already have this OpenID!'));
- } else {
- // TRANS: Message in case a user tries to add an OpenID that is already used by another user.
- $this->message(_m('Someone else already has this OpenID.'));
- }
- return;
- }
-
- // start a transaction
-
- $cur->query('BEGIN');
-
- $result = oid_link_user($cur->id, $canonical, $display);
-
- if (!$result) {
- // TRANS: Message in case the OpenID object cannot be connected to the user.
- $this->message(_m('Error connecting user.'));
- return;
- }
- if (Event::handle('StartOpenIDUpdateUser', array($cur, $canonical, &$sreg))) {
- if ($sreg) {
- if (!oid_update_user($cur, $sreg)) {
- // TRANS: Message in case the user or the user profile cannot be saved in StatusNet.
- $this->message(_m('Error updating profile.'));
- return;
- }
- }
- }
- Event::handle('EndOpenIDUpdateUser', array($cur, $canonical, $sreg));
-
- // success!
-
- $cur->query('COMMIT');
-
- oid_set_last($display);
-
- common_redirect(common_local_url('openidsettings'), 303);
- }
- }
-
- /**
- * Show a failure message
- *
- * Something went wrong. Save the message, and show the page.
- *
- * @param string $msg Error message to show
- *
- * @return void
- */
- function message($msg)
- {
- $this->message = $msg;
- $this->showPage();
- }
-
- /**
- * Title of the page
- *
- * @return string title
- */
- function title()
- {
- // TRANS: Title after getting the status of the OpenID authorisation request.
- return _m('OpenID Login');
- }
-
- /**
- * Show error message
- *
- * @return void
- */
- function showPageNotice()
- {
- if ($this->message) {
- $this->element('p', 'error', $this->message);
- }
- }
-}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/plugins/OpenID/openid.php';
-
-class FinishopenidloginAction extends Action
-{
- var $error = null;
- var $username = null;
- var $message = null;
-
- function handle($args)
- {
- parent::handle($args);
- if (common_is_real_login()) {
- // TRANS: Client error message trying to log on with OpenID while already logged on.
- $this->clientError(_m('Already logged in.'));
- } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- $token = $this->trimmed('token');
- if (!$token || $token != common_session_token()) {
- // TRANS: Message given when there is a problem with the user's session token.
- $this->showForm(_m('There was a problem with your session token. Try again, please.'));
- return;
- }
- if ($this->arg('create')) {
- if (!$this->boolean('license')) {
- // TRANS: Message given if user does not agree with the site's license.
- $this->showForm(_m('You cannot register if you do not agree to the license.'),
- $this->trimmed('newname'));
- return;
- }
- $this->createNewUser();
- } else if ($this->arg('connect')) {
- $this->connectUser();
- } else {
- // TRANS: Messag given on an unknown error.
- $this->showForm(_m('An unknown error has occured.'),
- $this->trimmed('newname'));
- }
- } else {
- $this->tryLogin();
- }
- }
-
- function showPageNotice()
- {
- if ($this->error) {
- $this->element('div', array('class' => 'error'), $this->error);
- } else {
- $this->element('div', 'instructions',
- // TRANS: Instructions given after a first successful logon using OpenID.
- // TRANS: %s is the site name.
- sprintf(_m('This is the first time you have logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
- }
- }
-
- function title()
- {
- // TRANS: Title
- return _m('TITLE','OpenID Account Setup');
- }
-
- function showForm($error=null, $username=null)
- {
- $this->error = $error;
- $this->username = $username;
-
- $this->showPage();
- }
-
- /**
- * @fixme much of this duplicates core code, which is very fragile.
- * Should probably be replaced with an extensible mini version of
- * the core registration form.
- */
- function showContent()
- {
- if (!empty($this->message_text)) {
- $this->element('div', array('class' => 'error'), $this->message_text);
- return;
- }
-
- // We don't recognize this OpenID, so we're going to give the user
- // two options, each in its own mini-form.
- //
- // First, they can create a new account using their OpenID auth
- // info. The profile will be pre-populated with whatever name,
- // email, and location we can get from the OpenID provider, so
- // all we ask for is the license confirmation.
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'account_create',
- 'class' => 'form_settings',
- 'action' => common_local_url('finishopenidlogin')));
- $this->hidden('token', common_session_token());
- $this->elementStart('fieldset', array('id' => 'form_openid_createaccount'));
- $this->element('legend', null,
- // TRANS: Fieldset legend.
- _m('Create new account'));
- $this->element('p', null,
- // TRANS: Form guide.
- _m('Create a new user with this nickname.'));
- $this->elementStart('ul', 'form_data');
-
- // Hook point for captcha etc
- Event::handle('StartRegistrationFormData', array($this));
-
- $this->elementStart('li');
- // TRANS: Field label.
- $this->input('newname', _m('New nickname'),
- ($this->username) ? $this->username : '',
- // TRANS: Field title.
- _m('1-64 lowercase letters or numbers, no punctuation or spaces.'));
- $this->elementEnd('li');
- $this->elementStart('li');
- // TRANS: Field label.
- $this->input('email', _m('Email'), $this->getEmail(),
- // TRANS: Field title.
- _m('Used only for updates, announcements, '.
- 'and password recovery.'));
- $this->elementEnd('li');
-
- // Hook point for captcha etc
- Event::handle('EndRegistrationFormData', array($this));
-
- $this->elementStart('li');
- $this->element('input', array('type' => 'checkbox',
- 'id' => 'license',
- 'class' => 'checkbox',
- 'name' => 'license',
- 'value' => 'true'));
- $this->elementStart('label', array('for' => 'license',
- 'class' => 'checkbox'));
- // TRANS: OpenID plugin link text.
- // TRANS: %s is a link to a license with the license name as link text.
- $message = _m('My text and files are available under %s ' .
- 'except this private data: password, ' .
- 'email address, IM address, and phone number.');
- $link = '<a href="' .
- htmlspecialchars(common_config('license', 'url')) .
- '">' .
- htmlspecialchars(common_config('license', 'title')) .
- '</a>';
- $this->raw(sprintf(htmlspecialchars($message), $link));
- $this->elementEnd('label');
- $this->elementEnd('li');
- $this->elementEnd('ul');
- // TRANS: Button label in form in which to create a new user on the site for an OpenID.
- $this->submit('create', _m('BUTTON', 'Create'));
- $this->elementEnd('fieldset');
- $this->elementEnd('form');
-
- // The second option is to attach this OpenID to an existing account
- // on the local system, which they need to provide a password for.
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'account_connect',
- 'class' => 'form_settings',
- 'action' => common_local_url('finishopenidlogin')));
- $this->hidden('token', common_session_token());
- $this->elementStart('fieldset', array('id' => 'form_openid_createaccount'));
- $this->element('legend', null,
- // TRANS: Used as form legend for form in which to connect an OpenID to an existing user on the site.
- _m('Connect existing account'));
- $this->element('p', null,
- // TRANS: User instructions for form in which to connect an OpenID to an existing user on the site.
- _m('If you already have an account, login with your username and password to connect it to your OpenID.'));
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li');
- // TRANS: Field label in form in which to connect an OpenID to an existing user on the site.
- $this->input('nickname', _m('Existing nickname'));
- $this->elementEnd('li');
- $this->elementStart('li');
- // TRANS: Field label in form in which to connect an OpenID to an existing user on the site.
- $this->password('password', _m('Password'));
- $this->elementEnd('li');
- $this->elementEnd('ul');
- // TRANS: Button text in form in which to connect an OpenID to an existing user on the site.
- $this->submit('connect', _m('BUTTON', 'Connect'));
- $this->elementEnd('fieldset');
- $this->elementEnd('form');
- }
-
- /**
- * Get specified e-mail from the form, or the OpenID sreg info, or the
- * invite code.
- *
- * @return string
- */
- function getEmail()
- {
- $email = $this->trimmed('email');
- if (!empty($email)) {
- return $email;
- }
-
- // Pull from openid thingy
- list($display, $canonical, $sreg) = $this->getSavedValues();
- if (!empty($sreg['email'])) {
- return $sreg['email'];
- }
-
- // Terrible hack for invites...
- if (common_config('site', 'inviteonly')) {
- $code = $_SESSION['invitecode'];
- if ($code) {
- $invite = Invitation::getKV($code);
-
- if ($invite && $invite->address_type == 'email') {
- return $invite->address;
- }
- }
- }
- return '';
- }
-
- function tryLogin()
- {
- $consumer = oid_consumer();
-
- $response = $consumer->complete(common_local_url('finishopenidlogin'));
-
- if ($response->status == Auth_OpenID_CANCEL) {
- // TRANS: Status message in case the response from the OpenID provider is that the logon attempt was cancelled.
- $this->message(_m('OpenID authentication cancelled.'));
- return;
- } else if ($response->status == Auth_OpenID_FAILURE) {
- // TRANS: OpenID authentication failed; display the error message. %s is the error message.
- $this->message(sprintf(_m('OpenID authentication failed: %s.'), $response->message));
- } else if ($response->status == Auth_OpenID_SUCCESS) {
- // This means the authentication succeeded; extract the
- // identity URL and Simple Registration data (if it was
- // returned).
- $display = $response->getDisplayIdentifier();
- $canonical = ($response->endpoint->canonicalID) ?
- $response->endpoint->canonicalID : $response->getDisplayIdentifier();
-
- oid_assert_allowed($display);
- oid_assert_allowed($canonical);
-
- $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
-
- if ($sreg_resp) {
- $sreg = $sreg_resp->contents();
- }
-
- // Launchpad teams extension
- if (!oid_check_teams($response)) {
- // TRANS: Message displayed when OpenID authentication is aborted.
- $this->message(_m('OpenID authentication aborted: You are not allowed to login to this site.'));
- return;
- }
-
- $user = oid_get_user($canonical);
-
- if ($user) {
- oid_set_last($display);
- // XXX: commented out at @edd's request until better
- // control over how data flows from OpenID provider.
- // oid_update_user($user, $sreg);
- common_set_user($user);
- common_real_login(true);
- if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
- common_rememberme($user);
- }
- unset($_SESSION['openid_rememberme']);
- $this->goHome($user->nickname);
- } else {
- $this->saveValues($display, $canonical, $sreg);
- $this->showForm(null, $this->bestNewNickname($display, $sreg));
- }
- }
- }
-
- function message($msg)
- {
- $this->message_text = $msg;
- $this->showPage();
- }
-
- function saveValues($display, $canonical, $sreg)
- {
- common_ensure_session();
- $_SESSION['openid_display'] = $display;
- $_SESSION['openid_canonical'] = $canonical;
- $_SESSION['openid_sreg'] = $sreg;
- }
-
- function getSavedValues()
- {
- return array($_SESSION['openid_display'],
- $_SESSION['openid_canonical'],
- $_SESSION['openid_sreg']);
- }
-
- function createNewUser()
- {
- // FIXME: save invite code before redirect, and check here
-
- if (!Event::handle('StartRegistrationTry', array($this))) {
- return;
- }
-
- if (common_config('site', 'closed')) {
- // TRANS: OpenID plugin message. No new user registration is allowed on the site.
- $this->clientError(_m('Registration not allowed.'));
- return;
- }
-
- $invite = null;
-
- if (common_config('site', 'inviteonly')) {
- $code = $_SESSION['invitecode'];
- if (empty($code)) {
- // TRANS: OpenID plugin message. No new user registration is allowed on the site without an invitation code, and none was provided.
- $this->clientError(_m('Registration not allowed.'));
- return;
- }
-
- $invite = Invitation::getKV($code);
-
- if (empty($invite)) {
- // TRANS: OpenID plugin message. No new user registration is allowed on the site without an invitation code, and the one provided was not valid.
- $this->clientError(_m('Not a valid invitation code.'));
- return;
- }
- }
-
- try {
- $nickname = Nickname::normalize($this->trimmed('newname'));
- } catch (NicknameException $e) {
- $this->showForm($e->getMessage());
- return;
- }
-
- if (!User::allowed_nickname($nickname)) {
- // TRANS: OpenID plugin message. The entered new user name is blacklisted.
- $this->showForm(_m('Nickname not allowed.'));
- return;
- }
-
- if (User::getKV('nickname', $nickname)) {
- // TRANS: OpenID plugin message. The entered new user name is already used.
- $this->showForm(_m('Nickname already in use. Try another one.'));
- return;
- }
-
- list($display, $canonical, $sreg) = $this->getSavedValues();
-
- if (!$display || !$canonical) {
- // TRANS: OpenID plugin server error. A stored OpenID cannot be retrieved.
- $this->serverError(_m('Stored OpenID not found.'));
- return;
- }
-
- // Possible race condition... let's be paranoid
-
- $other = oid_get_user($canonical);
-
- if ($other) {
- // TRANS: OpenID plugin server error.
- $this->serverError(_m('Creating new account for OpenID that already has a user.'));
- return;
- }
-
- Event::handle('StartOpenIDCreateNewUser', array($canonical, &$sreg));
-
- $location = '';
- if (!empty($sreg['country'])) {
- if ($sreg['postcode']) {
- // XXX: use postcode to get city and region
- // XXX: also, store postcode somewhere -- it's valuable!
- $location = $sreg['postcode'] . ', ' . $sreg['country'];
- } else {
- $location = $sreg['country'];
- }
- }
-
- if (!empty($sreg['fullname']) && mb_strlen($sreg['fullname']) <= 255) {
- $fullname = $sreg['fullname'];
- } else {
- $fullname = '';
- }
-
- $email = $this->getEmail();
-
- // XXX: add language
- // XXX: add timezone
-
- $args = array('nickname' => $nickname,
- 'email' => $email,
- 'fullname' => $fullname,
- 'location' => $location);
-
- if (!empty($invite)) {
- $args['code'] = $invite->code;
- }
-
- $user = User::register($args);
-
- $result = oid_link_user($user->id, $canonical, $display);
-
- Event::handle('EndOpenIDCreateNewUser', array($user, $canonical, $sreg));
-
- oid_set_last($display);
- common_set_user($user);
- common_real_login(true);
- if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
- common_rememberme($user);
- }
- unset($_SESSION['openid_rememberme']);
-
- Event::handle('EndRegistrationTry', array($this));
-
- common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
- 303);
- }
-
- function connectUser()
- {
- $nickname = $this->trimmed('nickname');
- $password = $this->trimmed('password');
-
- if (!common_check_user($nickname, $password)) {
- // TRANS: OpenID plugin message.
- $this->showForm(_m('Invalid username or password.'));
- return;
- }
-
- // They're legit!
-
- $user = User::getKV('nickname', $nickname);
-
- list($display, $canonical, $sreg) = $this->getSavedValues();
-
- if (!$display || !$canonical) {
- // TRANS: OpenID plugin server error. A stored OpenID cannot be found.
- $this->serverError(_m('Stored OpenID not found.'));
- return;
- }
-
- $result = oid_link_user($user->id, $canonical, $display);
-
- if (!$result) {
- // TRANS: OpenID plugin server error. The user or user profile could not be saved.
- $this->serverError(_m('Error connecting user to OpenID.'));
- return;
- }
-
- if (Event::handle('StartOpenIDUpdateUser', array($user, $canonical, &$sreg))) {
- oid_update_user($user, $sreg);
- }
- Event::handle('EndOpenIDUpdateUser', array($user, $canonical, $sreg));
-
- oid_set_last($display);
- common_set_user($user);
- common_real_login(true);
- if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
- common_rememberme($user);
- }
- unset($_SESSION['openid_rememberme']);
- $this->goHome($user->nickname);
- }
-
- function goHome($nickname)
- {
- $url = common_get_returnto();
- if ($url) {
- // We don't have to return to it again
- common_set_returnto(null);
- $url = common_inject_session($url);
- } else {
- $url = common_local_url('all',
- array('nickname' =>
- $nickname));
- }
- common_redirect($url, 303);
- }
-
- function bestNewNickname($display, $sreg)
- {
- // Try the passed-in nickname
-
- if (!empty($sreg['nickname'])) {
- $nickname = $this->nicknamize($sreg['nickname']);
- if ($this->isNewNickname($nickname)) {
- return $nickname;
- }
- }
-
- // Try the full name
-
- if (!empty($sreg['fullname'])) {
- $fullname = $this->nicknamize($sreg['fullname']);
- if ($this->isNewNickname($fullname)) {
- return $fullname;
- }
- }
-
- // Try the URL
-
- $from_url = $this->openidToNickname($display);
-
- if ($from_url && $this->isNewNickname($from_url)) {
- return $from_url;
- }
-
- // XXX: others?
-
- return null;
- }
-
- function isNewNickname($str)
- {
- if (!Nickname::isValid($str)) {
- return false;
- }
- if (!User::allowed_nickname($str)) {
- return false;
- }
- if (User::getKV('nickname', $str)) {
- return false;
- }
- return true;
- }
-
- function openidToNickname($openid)
- {
- if (Auth_Yadis_identifierScheme($openid) == 'XRI') {
- return $this->xriToNickname($openid);
- } else {
- return $this->urlToNickname($openid);
- }
- }
-
- // We try to use an OpenID URL as a legal StatusNet user name in this order
- // 1. Plain hostname, like http://evanp.myopenid.com/
- // 2. One element in path, like http://profile.typekey.com/EvanProdromou/
- // or http://getopenid.com/evanprodromou
- function urlToNickname($openid)
- {
- return common_url_to_nickname($openid);
- }
-
- function xriToNickname($xri)
- {
- $base = $this->xriBase($xri);
-
- if (!$base) {
- return null;
- } else {
- // =evan.prodromou
- // or @gratis*evan.prodromou
- $parts = explode('*', substr($base, 1));
- return $this->nicknamize(array_pop($parts));
- }
- }
-
- function xriBase($xri)
- {
- if (substr($xri, 0, 6) == 'xri://') {
- return substr($xri, 6);
- } else {
- return $xri;
- }
- }
-
- // Given a string, try to make it work as a nickname
- function nicknamize($str)
- {
- return common_nicknamize($str);
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * OpenID bridge administration panel
- *
- * 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 Settings
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Administer global OpenID settings
- *
- * @category Admin
- * @package StatusNet
- * @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
- * @link http://status.net/
- */
-class OpenidadminpanelAction extends AdminPanelAction
-{
- /**
- * Returns the page title
- *
- * @return string page title
- */
- function title()
- {
- // TRANS: Title for OpenID bridge administration page.
- return _m('TITLE','OpenID Settings');
- }
-
- /**
- * Instructions for using this form.
- *
- * @return string instructions
- */
- function getInstructions()
- {
- // TRANS: Page instructions.
- return _m('OpenID settings');
- }
-
- /**
- * Show the OpenID admin panel form
- *
- * @return void
- */
- function showForm()
- {
- $form = new OpenIDAdminPanelForm($this);
- $form->show();
- return;
- }
-
- /**
- * Save settings from the form
- *
- * @return void
- */
- function saveSettings()
- {
- static $settings = array(
- 'openid' => array('trusted_provider', 'required_team')
- );
-
- static $booleans = array(
- 'openid' => array('append_username'),
- 'site' => array('openidonly')
- );
-
- $values = array();
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- $values[$section][$setting]
- = $this->trimmed($setting);
- }
- }
-
- foreach ($booleans as $section => $parts) {
- foreach ($parts as $setting) {
- $values[$section][$setting]
- = ($this->boolean($setting)) ? 1 : 0;
- }
- }
-
- // This throws an exception on validation errors
-
- $this->validate($values);
-
- // assert(all values are valid);
-
- $config = new Config();
-
- $config->query('BEGIN');
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- Config::save($section, $setting, $values[$section][$setting]);
- }
- }
-
- foreach ($booleans as $section => $parts) {
- foreach ($parts as $setting) {
- Config::save($section, $setting, $values[$section][$setting]);
- }
- }
-
- $config->query('COMMIT');
-
- return;
- }
-
- function validate(&$values)
- {
- // Validate consumer key and secret (can't be too long)
-
- if (mb_strlen($values['openid']['trusted_provider']) > 255) {
- $this->clientError(
- // TRANS: Client error displayed when OpenID provider URL is too long.
- _m('Invalid provider URL. Maximum length is 255 characters.')
- );
- }
-
- if (mb_strlen($values['openid']['required_team']) > 255) {
- $this->clientError(
- // TRANS: Client error displayed when Launchpad team name is too long.
- _m('Invalid team name. Maximum length is 255 characters.')
- );
- }
- }
-}
-
-class OpenIDAdminPanelForm extends AdminForm
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'openidadminpanel';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('openidadminpanel');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- *
- * @todo Some of the options could prevent users from logging in again.
- * Make sure that the acting administrator has a valid OpenID matching,
- * or more carefully warn folks.
- */
- function formData()
- {
- $this->out->elementStart(
- 'fieldset',
- array('id' => 'settings_openid')
- );
- // TRANS: Fieldset legend.
- $this->out->element('legend', null, _m('LEGEND','Trusted provider'));
- $this->out->element('p', 'form_guide',
- // TRANS: Form guide.
- _m('By default, users are allowed to authenticate with any OpenID provider. ' .
- 'If you are using your own OpenID service for shared sign-in, ' .
- 'you can restrict access to only your own users here.'));
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->input(
- 'trusted_provider',
- // TRANS: Field label.
- _m('Provider URL'),
- // TRANS: Field title.
- _m('All OpenID logins will be sent to this URL; other providers may not be used.'),
- 'openid'
- );
- $this->unli();
-
- $this->li();
- $this->out->checkbox(
- // TRANS: Checkbox label.
- 'append_username', _m('Append a username to base URL'),
- (bool) $this->value('append_username', 'openid'),
- // TRANS: Checkbox title.
- _m('Login form will show the base URL and prompt for a username to add at the end. Use when OpenID provider URL should be the profile page for individual users.'),
- 'true'
- );
- $this->unli();
-
- $this->li();
- $this->input(
- 'required_team',
- // TRANS: Field label.
- _m('Required team'),
- // TRANS: Field title.
- _m('Only allow logins from users in the given team (Launchpad extension).'),
- 'openid'
- );
- $this->unli();
-
- $this->out->elementEnd('ul');
- $this->out->elementEnd('fieldset');
-
- $this->out->elementStart(
- 'fieldset',
- array('id' => 'settings_openid-options')
- );
- // TRANS: Fieldset legend.
- $this->out->element('legend', null, _m('LEGEND','Options'));
-
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
-
- $this->out->checkbox(
- // TRANS: Checkbox label.
- 'openidonly', _m('Enable OpenID-only mode'),
- (bool) $this->value('openidonly', 'site'),
- // TRANS: Checkbox title.
- _m('Require all users to login via OpenID. Warning: disables password authentication for all users!'),
- 'true'
- );
- $this->unli();
-
- $this->out->elementEnd('ul');
-
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text to save OpenID settings.
- $this->out->submit('submit', _m('BUTTON','Save'), 'submit', null,
- // TRANS: Button title to save OpenID settings.
- _m('Save OpenID settings.'));
- }
-}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/plugins/OpenID/openid.php';
-
-class OpenidloginAction extends Action
-{
- function handle($args)
- {
- parent::handle($args);
- if (common_is_real_login()) {
- // TRANS: Client error message trying to log on with OpenID while already logged on.
- $this->clientError(_m('Already logged in.'));
- } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- $provider = common_config('openid', 'trusted_provider');
- if ($provider) {
- $openid_url = $provider;
- if (common_config('openid', 'append_username')) {
- $openid_url .= $this->trimmed('openid_username');
- }
- } else {
- $openid_url = $this->trimmed('openid_url');
- }
-
- oid_assert_allowed($openid_url);
-
- $rememberme = $this->boolean('rememberme');
-
- common_ensure_session();
-
- $_SESSION['openid_rememberme'] = $rememberme;
-
- $result = oid_authenticate($openid_url,
- 'finishopenidlogin');
-
- if (is_string($result)) { # error message
- unset($_SESSION['openid_rememberme']);
- $this->showForm($result, $openid_url);
- }
- } else {
- $openid_url = oid_get_last();
- $this->showForm(null, $openid_url);
- }
- }
-
- function getInstructions()
- {
- if (common_logged_in() && !common_is_real_login() &&
- common_get_returnto()) {
- // rememberme logins have to reauthenticate before
- // changing any profile settings (cookie-stealing protection)
- // TRANS: OpenID plugin message. Rememberme logins have to reauthenticate before changing any profile settings.
- // TRANS: "OpenID" is the display text for a link with URL "(%%doc.openid%%)".
- return _m('For security reasons, please re-login with your ' .
- '[OpenID](%%doc.openid%%) ' .
- 'before changing your settings.');
- } else {
- // TRANS: OpenID plugin message.
- // TRANS: "OpenID" is the display text for a link with URL "(%%doc.openid%%)".
- return _m('Login with an [OpenID](%%doc.openid%%) account.');
- }
- }
-
- function showPageNotice()
- {
- if ($this->error) {
- $this->element('div', array('class' => 'error'), $this->error);
- } else {
- $instr = $this->getInstructions();
- $output = common_markup_to_html($instr);
- $this->elementStart('div', 'instructions');
- $this->raw($output);
- $this->elementEnd('div');
- }
- }
-
- function showScripts()
- {
- parent::showScripts();
- if (common_config('openid', 'trusted_provider')) {
- if (common_config('openid', 'append_username')) {
- $this->autofocus('openid_username');
- } else {
- $this->autofocus('rememberme');
- }
- } else {
- $this->autofocus('openid_url');
- }
- }
-
- function title()
- {
- // TRANS: OpenID plugin message. Title.
- return _m('TITLE','OpenID Login');
- }
-
- function showForm($error=null, $openid_url)
- {
- $this->error = $error;
- $this->openid_url = $openid_url;
- $this->showPage();
- }
-
- function showContent() {
- $formaction = common_local_url('openidlogin');
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'form_openid_login',
- 'class' => 'form_settings',
- 'action' => $formaction));
- $this->elementStart('fieldset');
- // TRANS: OpenID plugin logon form legend.
- $this->element('legend', null, _m('LEGEND','OpenID login'));
-
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li');
- $provider = common_config('openid', 'trusted_provider');
- $appendUsername = common_config('openid', 'append_username');
- if ($provider) {
- // TRANS: Field label.
- $this->element('label', array(), _m('LABEL','OpenID provider'));
- $this->element('span', array(), $provider);
- if ($appendUsername) {
- $this->element('input', array('id' => 'openid_username',
- 'name' => 'openid_username',
- 'style' => 'float: none'));
- }
- $this->element('p', 'form_guide',
- // TRANS: Form guide.
- ($appendUsername ? _m('Enter your username.') . ' ' : '') .
- // TRANS: Form guide.
- _m('You will be sent to the provider\'s site for authentication.'));
- $this->hidden('openid_url', $provider);
- } else {
- // TRANS: OpenID plugin logon form field label.
- $this->input('openid_url', _m('OpenID URL'),
- $this->openid_url,
- // TRANS: OpenID plugin logon form field title.
- _m('Your OpenID URL.'));
- }
- $this->elementEnd('li');
- $this->elementStart('li', array('id' => 'settings_rememberme'));
- // TRANS: OpenID plugin logon form checkbox label for setting to put the OpenID information in a cookie.
- $this->checkbox('rememberme', _m('Remember me'), false,
- // TRANS: OpenID plugin logon form field title.
- _m('Automatically login in the future; ' .
- 'not for shared computers!'));
- $this->elementEnd('li');
- $this->elementEnd('ul');
- // TRANS: OpenID plugin logon form button label to start logon with the data provided in the logon form.
- $this->submit('submit', _m('BUTTON', 'Login'));
- $this->elementEnd('fieldset');
- $this->elementEnd('form');
- }
-
- function showLocalNav()
- {
- $nav = new LoginGroupNav($this);
- $nav->show();
- }
-
- function showNoticeForm()
- {
- }
-
- function showProfileBlock()
- {
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Settings for OpenID
- *
- * 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 Settings
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2008-2009 StatusNet, Inc.
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/plugins/OpenID/openid.php';
-
-/**
- * Settings for OpenID
- *
- * Lets users add, edit and delete OpenIDs from their account
- *
- * @category Settings
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class OpenidserverAction extends Action
-{
- var $oserver;
-
- function prepare($args)
- {
- parent::prepare($args);
- $this->oserver = oid_server();
- return true;
- }
-
- function handle($args)
- {
- parent::handle($args);
- $request = $this->oserver->decodeRequest();
- if (in_array($request->mode, array('checkid_immediate',
- 'checkid_setup'))) {
- $user = common_current_user();
- if(!$user){
- if($request->immediate){
- //cannot prompt the user to login in immediate mode, so answer false
- $response = $this->generateDenyResponse($request);
- }else{
- // Go log in, and then come back.
- //
- // Note: 303 redirect rather than 307 to avoid
- // prompting user for form resubmission if we
- // were POSTed here.
- common_set_returnto($_SERVER['REQUEST_URI']);
- common_redirect(common_local_url('login'), 303);
- return;
- }
- }else if(common_profile_url($user->nickname) == $request->identity || $request->idSelect()){
- $user_openid_trustroot = User_openid_trustroot::pkeyGet(
- array('user_id'=>$user->id, 'trustroot'=>$request->trust_root));
- if(empty($user_openid_trustroot)){
- if($request->immediate){
- //cannot prompt the user to trust this trust root in immediate mode, so answer false
- $response = $this->generateDenyResponse($request);
- }else{
- common_ensure_session();
- $_SESSION['openid_trust_root'] = $request->trust_root;
- $allowResponse = $this->generateAllowResponse($request, $user);
- $this->oserver->encodeResponse($allowResponse); //sign the response
- $denyResponse = $this->generateDenyResponse($request);
- $this->oserver->encodeResponse($denyResponse); //sign the response
- $_SESSION['openid_allow_url'] = $allowResponse->encodeToUrl();
- $_SESSION['openid_deny_url'] = $denyResponse->encodeToUrl();
-
- // Ask the user to trust this trust root...
- //
- // Note: 303 redirect rather than 307 to avoid
- // prompting user for form resubmission if we
- // were POSTed here.
- common_redirect(common_local_url('openidtrust'), 303);
- return;
- }
- }else{
- //user has previously authorized this trust root
- $response = $this->generateAllowResponse($request, $user);
- //$response = $request->answer(true, null, common_profile_url($user->nickname));
- }
- } else if ($request->immediate) {
- $response = $this->generateDenyResponse($request);
- } else {
- //invalid
- // TRANS: OpenID plugin client error given trying to add an unauthorised OpenID to a user (403).
- // TRANS: %s is a request identity.
- $this->clientError(sprintf(_m('You are not authorized to use the identity %s.'),$request->identity),$code=403);
- }
- } else {
- $response = $this->oserver->handleRequest($request);
- }
-
- if($response){
- $response = $this->oserver->encodeResponse($response);
- if ($response->code != AUTH_OPENID_HTTP_OK) {
- header(sprintf("HTTP/1.1 %d ", $response->code),
- true, $response->code);
- }
-
- if($response->headers){
- foreach ($response->headers as $k => $v) {
- header("$k: $v");
- }
- }
- $this->raw($response->body);
- }else{
- // TRANS: OpenID plugin client error given when not getting a response for a given OpenID provider (500).
- $this->clientError(_m('Just an OpenID provider. Nothing to see here, move along...'),$code=500);
- }
- }
-
- function generateAllowResponse($request, $user){
- $response = $request->answer(true, null, common_profile_url($user->nickname));
-
- $profile = $user->getProfile();
- $sreg_data = array(
- 'fullname' => $profile->fullname,
- 'nickname' => $user->nickname,
- 'email' => $user->email,
- 'language' => $user->language,
- 'timezone' => $user->timezone);
- $sreg_request = Auth_OpenID_SRegRequest::fromOpenIDRequest($request);
- $sreg_response = Auth_OpenID_SRegResponse::extractResponse(
- $sreg_request, $sreg_data);
- $sreg_response->toMessage($response->fields);
- return $response;
- }
-
- function generateDenyResponse($request){
- $response = $request->answer(false);
- return $response;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Settings for OpenID
- *
- * 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 Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/plugins/OpenID/openid.php';
-
-/**
- * Settings for OpenID
- *
- * Lets users add, edit and delete OpenIDs from their account
- *
- * @category Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class OpenidsettingsAction extends SettingsAction
-{
- /**
- * Title of the page
- *
- * @return string Page title
- */
- function title()
- {
- // TRANS: Title of OpenID settings page for a user.
- return _m('TITLE','OpenID settings');
- }
-
- /**
- * Instructions for use
- *
- * @return string Instructions for use
- */
- function getInstructions()
- {
- // TRANS: Form instructions for OpenID settings.
- // TRANS: This message contains Markdown links in the form [description](link).
- return _m('[OpenID](%%doc.openid%%) lets you log into many sites ' .
- 'with the same user account. '.
- 'Manage your associated OpenIDs from here.');
- }
-
- function showScripts()
- {
- parent::showScripts();
- $this->autofocus('openid_url');
- }
-
- /**
- * Show the form for OpenID management
- *
- * We have one form with a few different submit buttons to do different things.
- *
- * @return void
- */
- function showContent()
- {
- $user = common_current_user();
-
- if (!common_config('openid', 'trusted_provider')) {
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'form_settings_openid_add',
- 'class' => 'form_settings',
- 'action' =>
- common_local_url('openidsettings')));
- $this->elementStart('fieldset', array('id' => 'settings_openid_add'));
-
- // TRANS: Fieldset legend.
- $this->element('legend', null, _m('LEGEND','Add OpenID'));
- $this->hidden('token', common_session_token());
- $this->element('p', 'form_guide',
- // TRANS: Form guide.
- _m('If you want to add an OpenID to your account, ' .
- 'enter it in the box below and click "Add".'));
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li');
- $this->element('label', array('for' => 'openid_url'),
- // TRANS: Field label.
- _m('OpenID URL'));
- $this->element('input', array('name' => 'openid_url',
- 'type' => 'text',
- 'id' => 'openid_url'));
- $this->elementEnd('li');
- $this->elementEnd('ul');
- $this->element('input', array('type' => 'submit',
- 'id' => 'settings_openid_add_action-submit',
- 'name' => 'add',
- 'class' => 'submit',
- // TRANS: Button text for adding an OpenID URL.
- 'value' => _m('BUTTON','Add')));
- $this->elementEnd('fieldset');
- $this->elementEnd('form');
- }
- $oid = new User_openid();
-
- $oid->user_id = $user->id;
-
- $cnt = $oid->find();
-
- if ($cnt > 0) {
- // TRANS: Header on OpenID settings page.
- $this->element('h2', null, _m('HEADER','Remove OpenID'));
-
- if ($cnt == 1 && !$user->password) {
-
- $this->element('p', 'form_guide',
- // TRANS: Form guide.
- _m('Removing your only OpenID '.
- 'would make it impossible to log in! ' .
- 'If you need to remove it, '.
- 'add another OpenID first.'));
-
- if ($oid->fetch()) {
- $this->elementStart('p');
- $this->element('a', array('href' => $oid->canonical),
- $oid->display);
- $this->elementEnd('p');
- }
-
- } else {
-
- $this->element('p', 'form_guide',
- // TRANS: Form guide.
- _m('You can remove an OpenID from your account '.
- 'by clicking the button marked "Remove".'));
- $idx = 0;
-
- while ($oid->fetch()) {
- $this->elementStart('form',
- array('method' => 'POST',
- 'id' => 'form_settings_openid_delete' . $idx,
- 'class' => 'form_settings',
- 'action' =>
- common_local_url('openidsettings')));
- $this->elementStart('fieldset');
- $this->hidden('token', common_session_token());
- $this->element('a', array('href' => $oid->canonical),
- $oid->display);
- $this->element('input', array('type' => 'hidden',
- 'id' => 'openid_url'.$idx,
- 'name' => 'openid_url',
- 'value' => $oid->canonical));
- $this->element('input', array('type' => 'submit',
- 'id' => 'remove'.$idx,
- 'name' => 'remove',
- 'class' => 'submit remove',
- // TRANS: Button text to remove an OpenID.
- 'value' => _m('BUTTON','Remove')));
- $this->elementEnd('fieldset');
- $this->elementEnd('form');
- $idx++;
- }
- }
- }
-
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'form_settings_openid_trustroots',
- 'class' => 'form_settings',
- 'action' =>
- common_local_url('openidsettings')));
- $this->elementStart('fieldset', array('id' => 'settings_openid_trustroots'));
- // TRANS: Fieldset legend.
- $this->element('legend', null, _m('OpenID Trusted Sites'));
- $this->hidden('token', common_session_token());
- $this->element('p', 'form_guide',
- // TRANS: Form guide.
- _m('The following sites are allowed to access your ' .
- 'identity and log you in. You can remove a site from ' .
- 'this list to deny it access to your OpenID.'));
- $this->elementStart('ul', 'form_data');
- $user_openid_trustroot = new User_openid_trustroot();
- $user_openid_trustroot->user_id=$user->id;
- if($user_openid_trustroot->find()) {
- while($user_openid_trustroot->fetch()) {
- $this->elementStart('li');
- $this->element('input', array('name' => 'openid_trustroot[]',
- 'type' => 'checkbox',
- 'class' => 'checkbox',
- 'value' => $user_openid_trustroot->trustroot,
- 'id' => 'openid_trustroot_' . crc32($user_openid_trustroot->trustroot)));
- $this->element('label', array('class'=>'checkbox', 'for' => 'openid_trustroot_' . crc32($user_openid_trustroot->trustroot)),
- $user_openid_trustroot->trustroot);
- $this->elementEnd('li');
- }
- }
- $this->elementEnd('ul');
- $this->element('input', array('type' => 'submit',
- 'id' => 'settings_openid_trustroots_action-submit',
- 'name' => 'remove_trustroots',
- 'class' => 'submit',
- // TRANS: Button text to remove an OpenID trustroot.
- 'value' => _m('BUTTON','Remove')));
- $this->elementEnd('fieldset');
-
- $prefs = User_openid_prefs::getKV('user_id', $user->id);
-
- $this->elementStart('fieldset');
- $this->element('legend', null, _m('LEGEND','Preferences'));
- $this->elementStart('ul', 'form_data');
- $this->checkBox('hide_profile_link', "Hide OpenID links from my profile", !empty($prefs) && $prefs->hide_profile_link);
- $this->element('input', array('type' => 'submit',
- 'id' => 'settings_openid_prefs_save',
- 'name' => 'save_prefs',
- 'class' => 'submit',
- // TRANS: Button text to save OpenID prefs
- 'value' => _m('BUTTON','Save')));
- $this->elementEnd('ul');
- $this->elementEnd('fieldset');
-
- $this->elementEnd('form');
- }
-
- /**
- * Handle a POST request
- *
- * Muxes to different sub-functions based on which button was pushed
- *
- * @return void
- */
- function handlePost()
- {
- // CSRF protection
- $token = $this->trimmed('token');
- if (!$token || $token != common_session_token()) {
- // TRANS: Client error displayed when the session token does not match or is not given.
- $this->showForm(_m('There was a problem with your session token. '.
- 'Try again, please.'));
- return;
- }
-
- if ($this->arg('add')) {
- if (common_config('openid', 'trusted_provider')) {
- // TRANS: Form validation error if no OpenID providers can be added.
- $this->showForm(_m('Cannot add new providers.'));
- } else {
- $result = oid_authenticate($this->trimmed('openid_url'),
- 'finishaddopenid');
- if (is_string($result)) { // error message
- $this->showForm($result);
- }
- }
- } else if ($this->arg('remove')) {
- $this->removeOpenid();
- } else if($this->arg('remove_trustroots')) {
- $this->removeTrustroots();
- } else if($this->arg('save_prefs')) {
- $this->savePrefs();
- } else {
- // TRANS: Unexpected form validation error.
- $this->showForm(_m('Something weird happened.'));
- }
- }
-
- /**
- * Handles a request to remove OpenID trustroots from the user's account
- *
- * Validates input and, if everything is OK, deletes the trustroots.
- * Reloads the form with a success or error notification.
- *
- * @return void
- */
- function removeTrustroots()
- {
- $user = common_current_user();
- $trustroots = $this->arg('openid_trustroot');
- if($trustroots) {
- foreach($trustroots as $trustroot) {
- $user_openid_trustroot = User_openid_trustroot::pkeyGet(
- array('user_id'=>$user->id, 'trustroot'=>$trustroot));
- if($user_openid_trustroot) {
- $user_openid_trustroot->delete();
- } else {
- // TRANS: Form validation error when trying to remove a non-existing trustroot.
- $this->showForm(_m('No such OpenID trustroot.'));
- return;
- }
- }
- // TRANS: Success message after removing trustroots.
- $this->showForm(_m('Trustroots removed.'), true);
- } else {
- $this->showForm();
- }
- return;
- }
-
- /**
- * Handles a request to remove an OpenID from the user's account
- *
- * Validates input and, if everything is OK, deletes the OpenID.
- * Reloads the form with a success or error notification.
- *
- * @return void
- */
- function removeOpenid()
- {
- $openid_url = $this->trimmed('openid_url');
-
- $oid = User_openid::getKV('canonical', $openid_url);
-
- if (!$oid) {
- // TRANS: Form validation error for a non-existing OpenID.
- $this->showForm(_m('No such OpenID.'));
- return;
- }
- $cur = common_current_user();
- if (!$cur || $oid->user_id != $cur->id) {
- // TRANS: Form validation error if OpenID is connected to another user.
- $this->showForm(_m('That OpenID does not belong to you.'));
- return;
- }
- $oid->delete();
- // TRANS: Success message after removing an OpenID.
- $this->showForm(_m('OpenID removed.'), true);
- return;
- }
-
- /**
- * Handles a request to save preferences
- *
- * Validates input and, if everything is OK, deletes the OpenID.
- * Reloads the form with a success or error notification.
- *
- * @return void
- */
- function savePrefs()
- {
- $cur = common_current_user();
-
- if (empty($cur)) {
- throw new ClientException(_("Not logged in."));
- }
-
- $orig = null;
- $prefs = User_openid_prefs::getKV('user_id', $cur->id);
-
- if (empty($prefs)) {
- $prefs = new User_openid_prefs();
- $prefs->user_id = $cur->id;
- $prefs->created = common_sql_now();
- } else {
- $orig = clone($prefs);
- }
-
- $prefs->hide_profile_link = $this->boolean('hide_profile_link');
-
- if (empty($orig)) {
- $prefs->insert();
- } else {
- $prefs->update($orig);
- }
-
- $this->showForm(_m('OpenID preferences saved.'), true);
- return;
- }
-}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/plugins/OpenID/openid.php';
-
-class OpenidtrustAction extends Action
-{
- var $trust_root;
- var $allowUrl;
- var $denyUrl;
- var $user;
-
- /**
- * Is this a read-only action?
- *
- * @return boolean false
- */
- function isReadOnly($args)
- {
- return false;
- }
-
- /**
- * Title of the page
- *
- * @return string title of the page
- */
- function title()
- {
- // TRANS: Title for identity verification page.
- return _m('OpenID Identity Verification');
- }
-
- function prepare($args)
- {
- parent::prepare($args);
- common_ensure_session();
- $this->user = common_current_user();
- if(empty($this->user)){
- /* Go log in, and then come back. */
- common_set_returnto($_SERVER['REQUEST_URI']);
- common_redirect(common_local_url('login'));
- return;
- }
- $this->trust_root = $_SESSION['openid_trust_root'];
- $this->allowUrl = $_SESSION['openid_allow_url'];
- $this->denyUrl = $_SESSION['openid_deny_url'];
- if(empty($this->trust_root) || empty($this->allowUrl) || empty($this->denyUrl)){
- // TRANS: Client error when visiting page directly.
- $this->clientError(_m('This page should only be reached during OpenID processing, not directly.'));
- return;
- }
- return true;
- }
-
- function handle($args)
- {
- parent::handle($args);
- if($_SERVER['REQUEST_METHOD'] == 'POST'){
- $this->handleSubmit();
- }else{
- $this->showPage();
- }
- }
-
- function handleSubmit()
- {
- unset($_SESSION['openid_trust_root']);
- unset($_SESSION['openid_allow_url']);
- unset($_SESSION['openid_deny_url']);
- if($this->arg('allow'))
- {
- //save to database
- $user_openid_trustroot = new User_openid_trustroot();
- $user_openid_trustroot->user_id = $this->user->id;
- $user_openid_trustroot->trustroot = $this->trust_root;
- $user_openid_trustroot->created = DB_DataObject_Cast::dateTime();
- if (!$user_openid_trustroot->insert()) {
- $err = PEAR::getStaticProperty('DB_DataObject','lastError');
- }
- common_redirect($this->allowUrl, $code=302);
- }else{
- common_redirect($this->denyUrl, $code=302);
- }
- }
-
- /**
- * Show page notice
- *
- * Display a notice for how to use the page, or the
- * error if it exists.
- *
- * @return void
- */
- function showPageNotice()
- {
- // TRANS: Page notice. %s is a trustroot name.
- $this->element('p',null,sprintf(_m('%s has asked to verify your identity. Click Continue to verify your identity and login without creating a new password.'),$this->trust_root));
- }
-
- /**
- * Core of the display code
- *
- * Shows the login form.
- *
- * @return void
- */
- function showContent()
- {
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'form_openidtrust',
- 'class' => 'form_settings',
- 'action' => common_local_url('openidtrust')));
- $this->elementStart('fieldset');
- // TRANS: Button text to continue OpenID identity verification.
- $this->submit('allow', _m('BUTTON','Continue'));
- // TRANS: Button text to cancel OpenID identity verification.
- $this->submit('deny', _m('BUTTON','Cancel'));
-
- $this->elementEnd('fieldset');
- $this->elementEnd('form');
- }
-}
return true;
}
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'OpenxadminpanelAction':
- require_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- default:
- return true;
- }
- }
-
function onEndAdminPanelNav($menu) {
if (AdminPanelAction::canAdmin('openx')) {
// TRANS: Menu item title.
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * OpenX administration panel
+ *
+ * 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 OpenX
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Administer openx settings
+ *
+ * @category OpenX
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class OpenXadminpanelAction extends AdminPanelAction
+{
+ /**
+ * Returns the page title
+ *
+ * @return string page title
+ */
+ function title()
+ {
+ // TRANS: Page title for OpenX admin panel.
+ return _m('TITLE', 'OpenX');
+ }
+
+ /**
+ * Instructions for using this form.
+ *
+ * @return string instructions
+ */
+ function getInstructions()
+ {
+ // TRANS: Instructions for OpenX admin panel.
+ return _m('OpenX settings for this StatusNet site');
+ }
+
+ /**
+ * Show the site admin panel form
+ *
+ * @return void
+ */
+ function showForm()
+ {
+ $form = new OpenXAdminPanelForm($this);
+ $form->show();
+ return;
+ }
+
+ /**
+ * Save settings from the form
+ *
+ * @return void
+ */
+ function saveSettings()
+ {
+ static $settings = array('openx' => array('adScript', 'mediumRectangle', 'rectangle', 'leaderboard', 'wideSkyscraper'));
+
+ $values = array();
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ $values[$section][$setting] = $this->trimmed($setting);
+ }
+ }
+
+ // This throws an exception on validation errors
+ $this->validate($values);
+
+ // assert(all values are valid);
+ $config = new Config();
+
+ $config->query('BEGIN');
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ Config::save($section, $setting, $values[$section][$setting]);
+ }
+ }
+
+ $config->query('COMMIT');
+
+ return;
+ }
+
+ function validate(&$values)
+ {
+ }
+}
+
+/**
+ * Form for the openx admin panel
+ */
+class OpenXAdminPanelForm extends AdminForm
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'form_openx_admin_panel';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_openx';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('openxadminpanel');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'openx_admin'));
+ $this->out->elementStart('ul', 'form_data');
+ $this->li();
+ $this->input('adScript',
+ // TRANS: Form label in OpenX admin panel.
+ _m('Ad script URL'),
+ // TRANS: Tooltip for form label in OpenX admin panel.
+ _m('Script URL'),
+ 'openx');
+ $this->unli();
+ $this->li();
+ $this->input('mediumRectangle',
+ // TRANS: Form label in OpenX admin panel. Refers to advertisement format.
+ _m('Medium rectangle'),
+ // TRANS: Tooltip for form label in OpenX admin panel. Refers to advertisement format.
+ _m('Medium rectangle zone'),
+ 'openx');
+ $this->unli();
+ $this->li();
+ $this->input('rectangle',
+ // TRANS: Form label in OpenX admin panel. Refers to advertisement format.
+ _m('Rectangle'),
+ // TRANS: Tooltip for form label in OpenX admin panel. Refers to advertisement format.
+ _m('Rectangle zone'),
+ 'openx');
+ $this->unli();
+ $this->li();
+ $this->input('leaderboard',
+ // TRANS: Form label in OpenX admin panel. Refers to advertisement format.
+ _m('Leaderboard'),
+ // TRANS: Tooltip for form label in OpenX admin panel. Refers to advertisement format.
+ _m('Leaderboard zone'),
+ 'openx');
+ $this->unli();
+ $this->li();
+ $this->input('wideSkyscraper',
+ // TRANS: Form label in OpenX admin panel. Refers to advertisement format.
+ _m('Skyscraper'),
+ // TRANS: Tooltip for form label in OpenX admin panel. Refers to advertisement format.
+ _m('Wide skyscraper zone'),
+ 'openx');
+ $this->unli();
+ $this->out->elementEnd('ul');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $this->out->submit('submit',
+ // TRANS: Submit button text in OpenX admin panel.
+ _m('BUTTON','Save'),
+ 'submit',
+ null,
+ // TRANS: Submit button title in OpenX admin panel.
+ _m('Save OpenX settings.'));
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * OpenX administration panel
- *
- * 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 OpenX
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Administer openx settings
- *
- * @category OpenX
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class OpenXadminpanelAction extends AdminPanelAction
-{
- /**
- * Returns the page title
- *
- * @return string page title
- */
- function title()
- {
- // TRANS: Page title for OpenX admin panel.
- return _m('TITLE', 'OpenX');
- }
-
- /**
- * Instructions for using this form.
- *
- * @return string instructions
- */
- function getInstructions()
- {
- // TRANS: Instructions for OpenX admin panel.
- return _m('OpenX settings for this StatusNet site');
- }
-
- /**
- * Show the site admin panel form
- *
- * @return void
- */
- function showForm()
- {
- $form = new OpenXAdminPanelForm($this);
- $form->show();
- return;
- }
-
- /**
- * Save settings from the form
- *
- * @return void
- */
- function saveSettings()
- {
- static $settings = array('openx' => array('adScript', 'mediumRectangle', 'rectangle', 'leaderboard', 'wideSkyscraper'));
-
- $values = array();
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- $values[$section][$setting] = $this->trimmed($setting);
- }
- }
-
- // This throws an exception on validation errors
- $this->validate($values);
-
- // assert(all values are valid);
- $config = new Config();
-
- $config->query('BEGIN');
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- Config::save($section, $setting, $values[$section][$setting]);
- }
- }
-
- $config->query('COMMIT');
-
- return;
- }
-
- function validate(&$values)
- {
- }
-}
-
-/**
- * Form for the openx admin panel
- */
-class OpenXAdminPanelForm extends AdminForm
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'form_openx_admin_panel';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_openx';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('openxadminpanel');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'openx_admin'));
- $this->out->elementStart('ul', 'form_data');
- $this->li();
- $this->input('adScript',
- // TRANS: Form label in OpenX admin panel.
- _m('Ad script URL'),
- // TRANS: Tooltip for form label in OpenX admin panel.
- _m('Script URL'),
- 'openx');
- $this->unli();
- $this->li();
- $this->input('mediumRectangle',
- // TRANS: Form label in OpenX admin panel. Refers to advertisement format.
- _m('Medium rectangle'),
- // TRANS: Tooltip for form label in OpenX admin panel. Refers to advertisement format.
- _m('Medium rectangle zone'),
- 'openx');
- $this->unli();
- $this->li();
- $this->input('rectangle',
- // TRANS: Form label in OpenX admin panel. Refers to advertisement format.
- _m('Rectangle'),
- // TRANS: Tooltip for form label in OpenX admin panel. Refers to advertisement format.
- _m('Rectangle zone'),
- 'openx');
- $this->unli();
- $this->li();
- $this->input('leaderboard',
- // TRANS: Form label in OpenX admin panel. Refers to advertisement format.
- _m('Leaderboard'),
- // TRANS: Tooltip for form label in OpenX admin panel. Refers to advertisement format.
- _m('Leaderboard zone'),
- 'openx');
- $this->unli();
- $this->li();
- $this->input('wideSkyscraper',
- // TRANS: Form label in OpenX admin panel. Refers to advertisement format.
- _m('Skyscraper'),
- // TRANS: Tooltip for form label in OpenX admin panel. Refers to advertisement format.
- _m('Wide skyscraper zone'),
- 'openx');
- $this->unli();
- $this->out->elementEnd('ul');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $this->out->submit('submit',
- // TRANS: Submit button text in OpenX admin panel.
- _m('BUTTON','Save'),
- 'submit',
- null,
- // TRANS: Submit button title in OpenX admin panel.
- _m('Save OpenX settings.'));
- }
-}
+++ /dev/null
-<?php
-/**
- * Data class to mark notices as bookmarks
- *
- * PHP version 5
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * For storing the poll options and such
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-
-class Poll extends Managed_DataObject
-{
- public $__table = 'poll'; // table name
- public $id; // char(36) primary key not null -> UUID
- public $uri;
- public $profile_id; // int -> profile.id
- public $question; // text
- public $options; // text; newline(?)-delimited
- public $created; // datetime
-
- /**
- * The One True Thingy that must be defined and declared.
- */
- public static function schemaDef()
- {
- return array(
- 'description' => 'Per-notice poll data for Poll plugin',
- 'fields' => array(
- 'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true),
- 'profile_id' => array('type' => 'int'),
- 'question' => array('type' => 'text'),
- 'options' => array('type' => 'text'),
- 'created' => array('type' => 'datetime', 'not null' => true),
- ),
- 'primary key' => array('id'),
- 'unique keys' => array(
- 'poll_uri_key' => array('uri'),
- ),
- );
- }
-
- /**
- * Get a bookmark based on a notice
- *
- * @param Notice $notice Notice to check for
- *
- * @return Poll found poll or null
- */
- static function getByNotice($notice)
- {
- return self::getKV('uri', $notice->uri);
- }
-
- function getOptions()
- {
- return explode("\n", $this->options);
- }
-
- /**
- * Is this a valid selection index?
- *
- * @param numeric $selection (1-based)
- * @return boolean
- */
- function isValidSelection($selection)
- {
- if ($selection != intval($selection)) {
- return false;
- }
- if ($selection < 1 || $selection > count($this->getOptions())) {
- return false;
- }
- return true;
- }
-
- function getNotice()
- {
- return Notice::getKV('uri', $this->uri);
- }
-
- function bestUrl()
- {
- return $this->getNotice()->bestUrl();
- }
-
- /**
- * Get the response of a particular user to this poll, if any.
- *
- * @param Profile $profile
- * @return Poll_response object or null
- */
- function getResponse(Profile $profile)
- {
- $pr = Poll_response::pkeyGet(array('poll_id' => $this->id,
- 'profile_id' => $profile->id));
- return $pr;
- }
-
- function countResponses()
- {
- $pr = new Poll_response();
- $pr->poll_id = $this->id;
- $pr->groupBy('selection');
- $pr->selectAdd('count(profile_id) as votes');
- $pr->find();
-
- $raw = array();
- while ($pr->fetch()) {
- // Votes list 1-based
- // Array stores 0-based
- $raw[$pr->selection - 1] = $pr->votes;
- }
-
- $counts = array();
- foreach (array_keys($this->getOptions()) as $key) {
- if (isset($raw[$key])) {
- $counts[$key] = $raw[$key];
- } else {
- $counts[$key] = 0;
- }
- }
- return $counts;
- }
-
- /**
- * Save a new poll notice
- *
- * @param Profile $profile
- * @param string $question
- * @param array $opts (poll responses)
- *
- * @return Notice saved notice
- */
- static function saveNew($profile, $question, $opts, $options=null)
- {
- if (empty($options)) {
- $options = array();
- }
-
- $p = new Poll();
-
- $p->id = UUID::gen();
- $p->profile_id = $profile->id;
- $p->question = $question;
- $p->options = implode("\n", $opts);
-
- if (array_key_exists('created', $options)) {
- $p->created = $options['created'];
- } else {
- $p->created = common_sql_now();
- }
-
- if (array_key_exists('uri', $options)) {
- $p->uri = $options['uri'];
- } else {
- $p->uri = common_local_url('showpoll',
- array('id' => $p->id));
- }
-
- common_log(LOG_DEBUG, "Saving poll: $p->id $p->uri");
- $p->insert();
-
- // TRANS: Notice content creating a poll.
- // TRANS: %1$s is the poll question, %2$s is a link to the poll.
- $content = sprintf(_m('Poll: %1$s %2$s'),
- $question,
- $p->uri);
- $link = '<a href="' . htmlspecialchars($p->uri) . '">' . htmlspecialchars($question) . '</a>';
- // TRANS: Rendered version of the notice content creating a poll.
- // TRANS: %s is a link to the poll with the question as link description.
- $rendered = sprintf(_m('Poll: %s'), $link);
-
- $tags = array('poll');
- $replies = array();
-
- $options = array_merge(array('urls' => array(),
- 'rendered' => $rendered,
- 'tags' => $tags,
- 'replies' => $replies,
- 'object_type' => PollPlugin::POLL_OBJECT),
- $options);
-
- if (!array_key_exists('uri', $options)) {
- $options['uri'] = $p->uri;
- }
-
- $saved = Notice::saveNew($profile->id,
- $content,
- array_key_exists('source', $options) ?
- $options['source'] : 'web',
- $options);
-
- return $saved;
- }
-}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'ShowpollAction':
- case 'NewpollAction':
- case 'RespondpollAction':
- case 'PollsettingsAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'Poll':
- case 'Poll_response':
- case 'User_poll_prefs':
- include_once $dir.'/'.$cls.'.php';
- return false;
- case 'NewPollForm':
- case 'PollResponseForm':
- case 'PollResultForm':
- include_once $dir.'/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Map URLs to actions
*
+++ /dev/null
-<?php
-/**
- * Data class to record responses to polls
- *
- * PHP version 5
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * For storing the poll options and such
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Poll_response extends Managed_DataObject
-{
- public $__table = 'poll_response'; // table name
- public $id; // char(36) primary key not null -> UUID
- public $uri; // varchar(255)
- public $poll_id; // char(36) -> poll.id UUID
- public $profile_id; // int -> profile.id
- public $selection; // int -> choice #
- public $created; // datetime
-
- /**
- * The One True Thingy that must be defined and declared.
- */
- public static function schemaDef()
- {
- return array(
- 'description' => 'Record of responses to polls',
- 'fields' => array(
- 'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID of the response'),
- 'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'UUID to the response notice'),
- 'poll_id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID of poll being responded to'),
- 'profile_id' => array('type' => 'int'),
- 'selection' => array('type' => 'int'),
- 'created' => array('type' => 'datetime', 'not null' => true),
- ),
- 'primary key' => array('id'),
- 'unique keys' => array(
- 'poll_uri_key' => array('uri'),
- 'poll_response_poll_id_profile_id_key' => array('poll_id', 'profile_id'),
- ),
- 'indexes' => array(
- 'poll_response_profile_id_poll_id_index' => array('profile_id', 'poll_id'),
- )
- );
- }
-
- /**
- * Get a poll response based on a notice
- *
- * @param Notice $notice Notice to check for
- *
- * @return Poll_response found response or null
- */
- static function getByNotice($notice)
- {
- return self::getKV('uri', $notice->uri);
- }
-
- /**
- * Get the notice that belongs to this response...
- *
- * @return Notice
- */
- function getNotice()
- {
- return Notice::getKV('uri', $this->uri);
- }
-
- function bestUrl()
- {
- return $this->getNotice()->bestUrl();
- }
-
- /**
- *
- * @return Poll
- */
- function getPoll()
- {
- return Poll::getKV('id', $this->poll_id);
- }
- /**
- * Save a new poll notice
- *
- * @param Profile $profile
- * @param Poll $poll the poll being responded to
- * @param int $selection (1-based)
- * @param array $opts (poll responses)
- *
- * @return Notice saved notice
- */
- static function saveNew($profile, $poll, $selection, $options=null)
- {
- if (empty($options)) {
- $options = array();
- }
-
- if (!$poll->isValidSelection($selection)) {
- // TRANS: Client exception thrown when responding to a poll with an invalid option.
- throw new ClientException(_m('Invalid poll selection.'));
- }
- $opts = $poll->getOptions();
- $answer = $opts[$selection - 1];
-
- $pr = new Poll_response();
- $pr->id = UUID::gen();
- $pr->profile_id = $profile->id;
- $pr->poll_id = $poll->id;
- $pr->selection = $selection;
-
- if (array_key_exists('created', $options)) {
- $pr->created = $options['created'];
- } else {
- $pr->created = common_sql_now();
- }
-
- if (array_key_exists('uri', $options)) {
- $pr->uri = $options['uri'];
- } else {
- $pr->uri = common_local_url('showpollresponse',
- array('id' => $pr->id));
- }
-
- common_log(LOG_DEBUG, "Saving poll response: $pr->id $pr->uri");
- $pr->insert();
-
- // TRANS: Notice content voting for a poll.
- // TRANS: %s is the chosen option in the poll.
- $content = sprintf(_m('voted for "%s"'),
- $answer);
- $link = '<a href="' . htmlspecialchars($poll->uri) . '">' . htmlspecialchars($answer) . '</a>';
- // TRANS: Rendered version of the notice content voting for a poll.
- // TRANS: %s a link to the poll with the chosen option as link description.
- $rendered = sprintf(_m('voted for "%s"'), $link);
-
- $tags = array();
-
- $options = array_merge(array('urls' => array(),
- 'rendered' => $rendered,
- 'tags' => $tags,
- 'reply_to' => $poll->getNotice()->id,
- 'object_type' => PollPlugin::POLL_RESPONSE_OBJECT),
- $options);
-
- if (!array_key_exists('uri', $options)) {
- $options['uri'] = $pr->uri;
- }
-
- $saved = Notice::saveNew($profile->id,
- $content,
- array_key_exists('source', $options) ?
- $options['source'] : 'web',
- $options);
-
- return $saved;
- }
-}
+++ /dev/null
-<?php
-/**
- * Data class to record user prefs for polls
- *
- * PHP version 5
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2012, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * For storing the poll prefs
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class User_poll_prefs extends Managed_DataObject
-{
- public $__table = 'user_poll_prefs'; // table name
- public $user_id; // int id
- public $hide_responses; // boolean
- public $created; // datetime
- public $modified; // datetime
-
- /**
- * The One True Thingy that must be defined and declared.
- */
- public static function schemaDef()
- {
- return array(
- 'description' => 'Record of user preferences for polls',
- 'fields' => array(
- 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
- 'hide_responses' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'Hide all poll responses'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('user_id')
- );
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Add a new Poll
+ *
+ * PHP version 5
+ *
+ * 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 Poll
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Add a new Poll
+ *
+ * @category Poll
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class NewPollAction extends Action
+{
+ protected $user = null;
+ protected $error = null;
+ protected $complete = null;
+
+ protected $question = null;
+ protected $options = array();
+
+ /**
+ * Returns the title of the action
+ *
+ * @return string Action title
+ */
+ function title()
+ {
+ // TRANS: Title for poll page.
+ return _m('New poll');
+ }
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown trying to create a poll while not logged in.
+ throw new ClientException(_m('You must be logged in to post a poll.'),
+ 403);
+ }
+
+ if ($this->isPost()) {
+ $this->checkSessionToken();
+ }
+
+ $this->question = $this->trimmed('question');
+ for ($i = 1; $i < 20; $i++) {
+ $opt = $this->trimmed('option' . $i);
+ if ($opt != '') {
+ $this->options[] = $opt;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ parent::handle($argarray);
+
+ if ($this->isPost()) {
+ $this->newPoll();
+ } else {
+ $this->showPage();
+ }
+
+ return;
+ }
+
+ /**
+ * Add a new Poll
+ *
+ * @return void
+ */
+ function newPoll()
+ {
+ if ($this->boolean('ajax')) {
+ StatusNet::setApi(true);
+ }
+ try {
+ if (empty($this->question)) {
+ // TRANS: Client exception thrown trying to create a poll without a question.
+ throw new ClientException(_m('Poll must have a question.'));
+ }
+
+ if (count($this->options) < 2) {
+ // TRANS: Client exception thrown trying to create a poll with fewer than two options.
+ throw new ClientException(_m('Poll must have at least two options.'));
+ }
+
+ // Notice options; distinct from choices for the poll
+
+ $options = array();
+
+ // Does the heavy-lifting for getting "To:" information
+
+ ToSelector::fillOptions($this, $options);
+
+ $saved = Poll::saveNew($this->user->getProfile(),
+ $this->question,
+ $this->options,
+ $options);
+
+ } catch (ClientException $ce) {
+ $this->error = $ce->getMessage();
+ $this->showPage();
+ return;
+ }
+
+ if ($this->boolean('ajax')) {
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Page title after sending a notice.
+ $this->element('title', null, _m('Notice posted'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->showNotice($saved);
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect($saved->bestUrl(), 303);
+ }
+ }
+
+ /**
+ * Output a notice
+ *
+ * Used to generate the notice code for Ajax results.
+ *
+ * @param Notice $notice Notice that was saved
+ *
+ * @return void
+ */
+ function showNotice($notice)
+ {
+ class_exists('NoticeList'); // @fixme hack for autoloader
+ $nli = new NoticeListItem($notice, $this);
+ $nli->show();
+ }
+
+ /**
+ * Show the Poll form
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ if (!empty($this->error)) {
+ $this->element('p', 'error', $this->error);
+ }
+
+ $form = new NewPollForm($this,
+ $this->question,
+ $this->options);
+
+ $form->show();
+
+ return;
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
+ $_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Form to set your personal poll settings
+ *
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * 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 Plugins
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2012 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class PollSettingsAction extends SettingsAction
+{
+ /**
+ * Title of the page
+ *
+ * @return string Page title
+ */
+ function title()
+ {
+ // TRANS: Page title.
+ return _m('Poll settings');
+ }
+
+ /**
+ * Instructions for use
+ *
+ * @return string Instructions for use
+ */
+
+ function getInstructions()
+ {
+ // TRANS: Page instructions.
+ return _m('Set your poll preferences');
+ }
+
+ /**
+ * Show the form for Poll
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $user = common_current_user();
+
+ $prefs = User_poll_prefs::getKV('user_id', $user->id);
+
+ $form = new PollPrefsForm($this, $prefs);
+
+ $form->show();
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+
+ function handlePost()
+ {
+ $user = common_current_user();
+
+ $upp = User_poll_prefs::getKV('user_id', $user->id);
+ $orig = null;
+
+ if (!empty($upp)) {
+ $orig = clone($upp);
+ } else {
+ $upp = new User_poll_prefs();
+ $upp->user_id = $user->id;
+ $upp->created = common_sql_now();
+ }
+
+ $upp->hide_responses = $this->boolean('hide_responses');
+ $upp->modified = common_sql_now();
+
+ if (!empty($orig)) {
+ $upp->update($orig);
+ } else {
+ $upp->insert();
+ }
+
+ // TRANS: Confirmation shown when user profile settings are saved.
+ $this->showForm(_('Settings saved.'), true);
+
+ return;
+ }
+}
+
+class PollPrefsForm extends Form
+{
+ var $prefs;
+
+ function __construct($out, $prefs)
+ {
+ parent::__construct($out);
+ $this->prefs = $prefs;
+ }
+
+ /**
+ * Visible or invisible data elements
+ *
+ * Display the form fields that make up the data of the form.
+ * Sub-classes should overload this to show their data.
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->elementStart('fieldset');
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->checkbox('hide_responses',
+ _('Do not deliver poll responses to my home timeline'),
+ (!empty($this->prefs) && $this->prefs->hide_responses));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->elementEnd('fieldset');
+ }
+
+ /**
+ * Buttons for form actions
+ *
+ * Submit and cancel buttons (or whatever)
+ * Sub-classes should overload this to show their own buttons.
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->submit('submit', _('Save'));
+ }
+
+ /**
+ * ID of the form
+ *
+ * Should be unique on the page. Sub-classes should overload this
+ * to show their own IDs.
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'form_poll_prefs';
+ }
+
+ /**
+ * Action of the form.
+ *
+ * URL to post to. Should be overloaded by subclasses to give
+ * somewhere to post to.
+ *
+ * @return string URL to post to
+ */
+
+ function action()
+ {
+ return common_local_url('pollsettings');
+ }
+
+ /**
+ * Class of the form. May include space-separated list of multiple classes.
+ *
+ * @return string the form's class
+ */
+
+ function formClass()
+ {
+ return 'form_settings';
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Respond to a Poll
+ *
+ * PHP version 5
+ *
+ * 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 Poll
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Respond to a Poll
+ *
+ * @category Poll
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class RespondPollAction extends Action
+{
+ protected $user = null;
+ protected $error = null;
+ protected $complete = null;
+
+ protected $poll = null;
+ protected $selection = null;
+
+ /**
+ * Returns the title of the action
+ *
+ * @return string Action title
+ */
+ function title()
+ {
+ // TRANS: Page title for poll response.
+ return _m('Poll response');
+ }
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+ if ($this->boolean('ajax')) {
+ StatusNet::setApi(true);
+ }
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown trying to respond to a poll while not logged in.
+ throw new ClientException(_m('You must be logged in to respond to a poll.'),
+ 403);
+ }
+
+ if ($this->isPost()) {
+ $this->checkSessionToken();
+ }
+
+ $id = $this->trimmed('id');
+ $this->poll = Poll::getKV('id', $id);
+ if (empty($this->poll)) {
+ // TRANS: Client exception thrown trying to respond to a non-existing poll.
+ throw new ClientException(_m('Invalid or missing poll.'), 404);
+ }
+
+ $selection = intval($this->trimmed('pollselection'));
+ if ($selection < 1 || $selection > count($this->poll->getOptions())) {
+ // TRANS: Client exception thrown responding to a poll with an invalid answer.
+ throw new ClientException(_m('Invalid poll selection.'));
+ }
+ $this->selection = $selection;
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ parent::handle($argarray);
+
+ if ($this->isPost()) {
+ $this->respondPoll();
+ } else {
+ $this->showPage();
+ }
+
+ return;
+ }
+
+ /**
+ * Add a new Poll
+ *
+ * @return void
+ */
+ function respondPoll()
+ {
+ try {
+ $notice = Poll_response::saveNew($this->user->getProfile(),
+ $this->poll,
+ $this->selection);
+ } catch (ClientException $ce) {
+ $this->error = $ce->getMessage();
+ $this->showPage();
+ return;
+ }
+
+ if ($this->boolean('ajax')) {
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Page title after sending a poll response.
+ $this->element('title', null, _m('Poll results'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $form = new PollResultForm($this->poll, $this);
+ $form->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect($this->poll->bestUrl(), 303);
+ }
+ }
+
+ /**
+ * Show the Poll form
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ if (!empty($this->error)) {
+ $this->element('p', 'error', $this->error);
+ }
+
+ $form = new PollResponseForm($this->poll, $this);
+
+ $form->show();
+
+ return;
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
+ $_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Show a single Poll
+ *
+ * PHP version 5
+ *
+ * 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 PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Show a single Poll, with associated information
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ShowPollAction extends ShownoticeAction
+{
+ protected $poll = null;
+
+ function getNotice()
+ {
+ $this->id = $this->trimmed('id');
+
+ $this->poll = Poll::getKV('id', $this->id);
+
+ if (empty($this->poll)) {
+ // TRANS: Client exception thrown trying to view a non-existing poll.
+ throw new ClientException(_m('No such poll.'), 404);
+ }
+
+ $notice = $this->poll->getNotice();
+
+ if (empty($notice)) {
+ // Did we used to have it, and it got deleted?
+ // TRANS: Client exception thrown trying to view a non-existing poll notice.
+ throw new ClientException(_m('No such poll notice.'), 404);
+ }
+
+ return $notice;
+ }
+
+ /**
+ * Title of the page
+ *
+ * Used by Action class for layout.
+ *
+ * @return string page tile
+ */
+ function title()
+ {
+ // TRANS: Page title for a poll.
+ // TRANS: %1$s is the nickname of the user that created the poll, %2$s is the poll question.
+ return sprintf(_m('%1$s\'s poll: %2$s'),
+ $this->user->nickname,
+ $this->poll->question);
+ }
+
+ /**
+ * @fixme combine the notice time with poll update time
+ */
+ function lastModified()
+ {
+ return Action::lastModified();
+ }
+
+
+ /**
+ * @fixme combine the notice time with poll update time
+ */
+ function etag()
+ {
+ return Action::etag();
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class to mark notices as bookmarks
+ *
+ * PHP version 5
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * For storing the poll options and such
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+
+class Poll extends Managed_DataObject
+{
+ public $__table = 'poll'; // table name
+ public $id; // char(36) primary key not null -> UUID
+ public $uri;
+ public $profile_id; // int -> profile.id
+ public $question; // text
+ public $options; // text; newline(?)-delimited
+ public $created; // datetime
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'Per-notice poll data for Poll plugin',
+ 'fields' => array(
+ 'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID'),
+ 'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true),
+ 'profile_id' => array('type' => 'int'),
+ 'question' => array('type' => 'text'),
+ 'options' => array('type' => 'text'),
+ 'created' => array('type' => 'datetime', 'not null' => true),
+ ),
+ 'primary key' => array('id'),
+ 'unique keys' => array(
+ 'poll_uri_key' => array('uri'),
+ ),
+ );
+ }
+
+ /**
+ * Get a bookmark based on a notice
+ *
+ * @param Notice $notice Notice to check for
+ *
+ * @return Poll found poll or null
+ */
+ static function getByNotice($notice)
+ {
+ return self::getKV('uri', $notice->uri);
+ }
+
+ function getOptions()
+ {
+ return explode("\n", $this->options);
+ }
+
+ /**
+ * Is this a valid selection index?
+ *
+ * @param numeric $selection (1-based)
+ * @return boolean
+ */
+ function isValidSelection($selection)
+ {
+ if ($selection != intval($selection)) {
+ return false;
+ }
+ if ($selection < 1 || $selection > count($this->getOptions())) {
+ return false;
+ }
+ return true;
+ }
+
+ function getNotice()
+ {
+ return Notice::getKV('uri', $this->uri);
+ }
+
+ function bestUrl()
+ {
+ return $this->getNotice()->bestUrl();
+ }
+
+ /**
+ * Get the response of a particular user to this poll, if any.
+ *
+ * @param Profile $profile
+ * @return Poll_response object or null
+ */
+ function getResponse(Profile $profile)
+ {
+ $pr = Poll_response::pkeyGet(array('poll_id' => $this->id,
+ 'profile_id' => $profile->id));
+ return $pr;
+ }
+
+ function countResponses()
+ {
+ $pr = new Poll_response();
+ $pr->poll_id = $this->id;
+ $pr->groupBy('selection');
+ $pr->selectAdd('count(profile_id) as votes');
+ $pr->find();
+
+ $raw = array();
+ while ($pr->fetch()) {
+ // Votes list 1-based
+ // Array stores 0-based
+ $raw[$pr->selection - 1] = $pr->votes;
+ }
+
+ $counts = array();
+ foreach (array_keys($this->getOptions()) as $key) {
+ if (isset($raw[$key])) {
+ $counts[$key] = $raw[$key];
+ } else {
+ $counts[$key] = 0;
+ }
+ }
+ return $counts;
+ }
+
+ /**
+ * Save a new poll notice
+ *
+ * @param Profile $profile
+ * @param string $question
+ * @param array $opts (poll responses)
+ *
+ * @return Notice saved notice
+ */
+ static function saveNew($profile, $question, $opts, $options=null)
+ {
+ if (empty($options)) {
+ $options = array();
+ }
+
+ $p = new Poll();
+
+ $p->id = UUID::gen();
+ $p->profile_id = $profile->id;
+ $p->question = $question;
+ $p->options = implode("\n", $opts);
+
+ if (array_key_exists('created', $options)) {
+ $p->created = $options['created'];
+ } else {
+ $p->created = common_sql_now();
+ }
+
+ if (array_key_exists('uri', $options)) {
+ $p->uri = $options['uri'];
+ } else {
+ $p->uri = common_local_url('showpoll',
+ array('id' => $p->id));
+ }
+
+ common_log(LOG_DEBUG, "Saving poll: $p->id $p->uri");
+ $p->insert();
+
+ // TRANS: Notice content creating a poll.
+ // TRANS: %1$s is the poll question, %2$s is a link to the poll.
+ $content = sprintf(_m('Poll: %1$s %2$s'),
+ $question,
+ $p->uri);
+ $link = '<a href="' . htmlspecialchars($p->uri) . '">' . htmlspecialchars($question) . '</a>';
+ // TRANS: Rendered version of the notice content creating a poll.
+ // TRANS: %s is a link to the poll with the question as link description.
+ $rendered = sprintf(_m('Poll: %s'), $link);
+
+ $tags = array('poll');
+ $replies = array();
+
+ $options = array_merge(array('urls' => array(),
+ 'rendered' => $rendered,
+ 'tags' => $tags,
+ 'replies' => $replies,
+ 'object_type' => PollPlugin::POLL_OBJECT),
+ $options);
+
+ if (!array_key_exists('uri', $options)) {
+ $options['uri'] = $p->uri;
+ }
+
+ $saved = Notice::saveNew($profile->id,
+ $content,
+ array_key_exists('source', $options) ?
+ $options['source'] : 'web',
+ $options);
+
+ return $saved;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class to record responses to polls
+ *
+ * PHP version 5
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * For storing the poll options and such
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Poll_response extends Managed_DataObject
+{
+ public $__table = 'poll_response'; // table name
+ public $id; // char(36) primary key not null -> UUID
+ public $uri; // varchar(255)
+ public $poll_id; // char(36) -> poll.id UUID
+ public $profile_id; // int -> profile.id
+ public $selection; // int -> choice #
+ public $created; // datetime
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'Record of responses to polls',
+ 'fields' => array(
+ 'id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID of the response'),
+ 'uri' => array('type' => 'varchar', 'length' => 255, 'not null' => true, 'description' => 'UUID to the response notice'),
+ 'poll_id' => array('type' => 'char', 'length' => 36, 'not null' => true, 'description' => 'UUID of poll being responded to'),
+ 'profile_id' => array('type' => 'int'),
+ 'selection' => array('type' => 'int'),
+ 'created' => array('type' => 'datetime', 'not null' => true),
+ ),
+ 'primary key' => array('id'),
+ 'unique keys' => array(
+ 'poll_uri_key' => array('uri'),
+ 'poll_response_poll_id_profile_id_key' => array('poll_id', 'profile_id'),
+ ),
+ 'indexes' => array(
+ 'poll_response_profile_id_poll_id_index' => array('profile_id', 'poll_id'),
+ )
+ );
+ }
+
+ /**
+ * Get a poll response based on a notice
+ *
+ * @param Notice $notice Notice to check for
+ *
+ * @return Poll_response found response or null
+ */
+ static function getByNotice($notice)
+ {
+ return self::getKV('uri', $notice->uri);
+ }
+
+ /**
+ * Get the notice that belongs to this response...
+ *
+ * @return Notice
+ */
+ function getNotice()
+ {
+ return Notice::getKV('uri', $this->uri);
+ }
+
+ function bestUrl()
+ {
+ return $this->getNotice()->bestUrl();
+ }
+
+ /**
+ *
+ * @return Poll
+ */
+ function getPoll()
+ {
+ return Poll::getKV('id', $this->poll_id);
+ }
+ /**
+ * Save a new poll notice
+ *
+ * @param Profile $profile
+ * @param Poll $poll the poll being responded to
+ * @param int $selection (1-based)
+ * @param array $opts (poll responses)
+ *
+ * @return Notice saved notice
+ */
+ static function saveNew($profile, $poll, $selection, $options=null)
+ {
+ if (empty($options)) {
+ $options = array();
+ }
+
+ if (!$poll->isValidSelection($selection)) {
+ // TRANS: Client exception thrown when responding to a poll with an invalid option.
+ throw new ClientException(_m('Invalid poll selection.'));
+ }
+ $opts = $poll->getOptions();
+ $answer = $opts[$selection - 1];
+
+ $pr = new Poll_response();
+ $pr->id = UUID::gen();
+ $pr->profile_id = $profile->id;
+ $pr->poll_id = $poll->id;
+ $pr->selection = $selection;
+
+ if (array_key_exists('created', $options)) {
+ $pr->created = $options['created'];
+ } else {
+ $pr->created = common_sql_now();
+ }
+
+ if (array_key_exists('uri', $options)) {
+ $pr->uri = $options['uri'];
+ } else {
+ $pr->uri = common_local_url('showpollresponse',
+ array('id' => $pr->id));
+ }
+
+ common_log(LOG_DEBUG, "Saving poll response: $pr->id $pr->uri");
+ $pr->insert();
+
+ // TRANS: Notice content voting for a poll.
+ // TRANS: %s is the chosen option in the poll.
+ $content = sprintf(_m('voted for "%s"'),
+ $answer);
+ $link = '<a href="' . htmlspecialchars($poll->uri) . '">' . htmlspecialchars($answer) . '</a>';
+ // TRANS: Rendered version of the notice content voting for a poll.
+ // TRANS: %s a link to the poll with the chosen option as link description.
+ $rendered = sprintf(_m('voted for "%s"'), $link);
+
+ $tags = array();
+
+ $options = array_merge(array('urls' => array(),
+ 'rendered' => $rendered,
+ 'tags' => $tags,
+ 'reply_to' => $poll->getNotice()->id,
+ 'object_type' => PollPlugin::POLL_RESPONSE_OBJECT),
+ $options);
+
+ if (!array_key_exists('uri', $options)) {
+ $options['uri'] = $pr->uri;
+ }
+
+ $saved = Notice::saveNew($profile->id,
+ $content,
+ array_key_exists('source', $options) ?
+ $options['source'] : 'web',
+ $options);
+
+ return $saved;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class to record user prefs for polls
+ *
+ * PHP version 5
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2012, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * For storing the poll prefs
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class User_poll_prefs extends Managed_DataObject
+{
+ public $__table = 'user_poll_prefs'; // table name
+ public $user_id; // int id
+ public $hide_responses; // boolean
+ public $created; // datetime
+ public $modified; // datetime
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'Record of user preferences for polls',
+ 'fields' => array(
+ 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
+ 'hide_responses' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'Hide all poll responses'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('user_id')
+ );
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for adding a new poll
+ *
+ * PHP version 5
+ *
+ * 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 PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form to add a new poll thingy
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class NewpollForm extends Form
+{
+ protected $question = null;
+ protected $options = array();
+
+ /**
+ * Construct a new poll form
+ *
+ * @param HTMLOutputter $out output channel
+ *
+ * @return void
+ */
+ function __construct($out=null, $question=null, $options=null)
+ {
+ parent::__construct($out);
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'newpoll-form';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings ajax-notice';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('newpoll');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'newpoll-data'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('question',
+ // TRANS: Field label on the page to create a poll.
+ _m('Question'),
+ $this->question,
+ // TRANS: Field title on the page to create a poll.
+ _m('What question are people answering?'));
+ $this->unli();
+
+ $max = 5;
+ if (count($this->options) + 1 > $max) {
+ $max = count($this->options) + 2;
+ }
+ for ($i = 0; $i < $max; $i++) {
+ // @fixme make extensible
+ if (isset($this->options[$i])) {
+ $default = $this->options[$i];
+ } else {
+ $default = '';
+ }
+ $this->li();
+ $this->out->input('poll-option' . ($i + 1),
+ // TRANS: Field label for an answer option on the page to create a poll.
+ // TRANS: %d is the option number.
+ sprintf(_m('Option %d'), $i + 1),
+ $default,
+ null,
+ 'option' . ($i + 1));
+ $this->unli();
+ }
+
+ $this->out->elementEnd('ul');
+
+ $toWidget = new ToSelector($this->out,
+ common_current_user(),
+ null);
+ $toWidget->show();
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text for saving a new poll.
+ $this->out->submit('poll-submit', _m('BUTTON', 'Save'), 'submit', 'submit');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for adding a new poll
+ *
+ * PHP version 5
+ *
+ * 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 PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form to add a new poll thingy
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class PollResponseForm extends Form
+{
+ protected $poll;
+
+ /**
+ * Construct a new poll form
+ *
+ * @param Poll $poll
+ * @param HTMLOutputter $out output channel
+ *
+ * @return void
+ */
+ function __construct(Poll $poll, HTMLOutputter $out)
+ {
+ parent::__construct($out);
+ $this->poll = $poll;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'pollresponse-form';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('respondpoll', array('id' => $this->poll->id));
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $poll = $this->poll;
+ $out = $this->out;
+ $id = "poll-" . $poll->id;
+
+ $out->element('p', 'poll-question', $poll->question);
+ $out->elementStart('ul', 'poll-options');
+ foreach ($poll->getOptions() as $i => $opt) {
+ $out->elementStart('li');
+ $out->elementStart('label');
+ $out->element('input', array('type' => 'radio', 'name' => 'pollselection', 'value' => $i + 1), '');
+ $out->text(' ' . $opt);
+ $out->elementEnd('label');
+ $out->elementEnd('li');
+ }
+ $out->elementEnd('ul');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text for submitting a poll response.
+ $this->out->submit('poll-response-submit', _m('BUTTON', 'Submit'), 'submit', 'submit');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for adding a new poll
+ *
+ * PHP version 5
+ *
+ * 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 PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form to add a new poll thingy
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class PollResultForm extends Form
+{
+ protected $poll;
+
+ /**
+ * Construct a new poll form
+ *
+ * @param Poll $poll
+ * @param HTMLOutputter $out output channel
+ *
+ * @return void
+ */
+ function __construct(Poll $poll, HTMLOutputter $out)
+ {
+ parent::__construct($out);
+ $this->poll = $poll;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'pollresult-form';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('respondpoll', array('id' => $this->poll->id));
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $poll = $this->poll;
+ $out = $this->out;
+ $counts = $poll->countResponses();
+
+ $width = 200;
+ $max = max($counts);
+ if ($max == 0) {
+ $max = 1; // quick hack :D
+ }
+
+ $out->element('p', 'poll-question', $poll->question);
+ $out->elementStart('table', 'poll-results');
+ foreach ($poll->getOptions() as $i => $opt) {
+ $w = intval($counts[$i] * $width / $max) + 1;
+
+ $out->elementStart('tr');
+
+ $out->elementStart('td');
+ $out->text($opt);
+ $out->elementEnd('td');
+
+ $out->elementStart('td');
+ $out->element('span', array('class' => 'poll-block',
+ 'style' => "width: {$w}px"),
+ "\xc2\xa0"); // nbsp
+ $out->text($counts[$i]);
+ $out->elementEnd('td');
+
+ $out->elementEnd('tr');
+ }
+ $out->elementEnd('table');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Add a new Poll
- *
- * PHP version 5
- *
- * 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 Poll
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Add a new Poll
- *
- * @category Poll
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class NewPollAction extends Action
-{
- protected $user = null;
- protected $error = null;
- protected $complete = null;
-
- protected $question = null;
- protected $options = array();
-
- /**
- * Returns the title of the action
- *
- * @return string Action title
- */
- function title()
- {
- // TRANS: Title for poll page.
- return _m('New poll');
- }
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Client exception thrown trying to create a poll while not logged in.
- throw new ClientException(_m('You must be logged in to post a poll.'),
- 403);
- }
-
- if ($this->isPost()) {
- $this->checkSessionToken();
- }
-
- $this->question = $this->trimmed('question');
- for ($i = 1; $i < 20; $i++) {
- $opt = $this->trimmed('option' . $i);
- if ($opt != '') {
- $this->options[] = $opt;
- }
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- parent::handle($argarray);
-
- if ($this->isPost()) {
- $this->newPoll();
- } else {
- $this->showPage();
- }
-
- return;
- }
-
- /**
- * Add a new Poll
- *
- * @return void
- */
- function newPoll()
- {
- if ($this->boolean('ajax')) {
- StatusNet::setApi(true);
- }
- try {
- if (empty($this->question)) {
- // TRANS: Client exception thrown trying to create a poll without a question.
- throw new ClientException(_m('Poll must have a question.'));
- }
-
- if (count($this->options) < 2) {
- // TRANS: Client exception thrown trying to create a poll with fewer than two options.
- throw new ClientException(_m('Poll must have at least two options.'));
- }
-
- // Notice options; distinct from choices for the poll
-
- $options = array();
-
- // Does the heavy-lifting for getting "To:" information
-
- ToSelector::fillOptions($this, $options);
-
- $saved = Poll::saveNew($this->user->getProfile(),
- $this->question,
- $this->options,
- $options);
-
- } catch (ClientException $ce) {
- $this->error = $ce->getMessage();
- $this->showPage();
- return;
- }
-
- if ($this->boolean('ajax')) {
- header('Content-Type: text/xml;charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: Page title after sending a notice.
- $this->element('title', null, _m('Notice posted'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $this->showNotice($saved);
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- common_redirect($saved->bestUrl(), 303);
- }
- }
-
- /**
- * Output a notice
- *
- * Used to generate the notice code for Ajax results.
- *
- * @param Notice $notice Notice that was saved
- *
- * @return void
- */
- function showNotice($notice)
- {
- class_exists('NoticeList'); // @fixme hack for autoloader
- $nli = new NoticeListItem($notice, $this);
- $nli->show();
- }
-
- /**
- * Show the Poll form
- *
- * @return void
- */
- function showContent()
- {
- if (!empty($this->error)) {
- $this->element('p', 'error', $this->error);
- }
-
- $form = new NewPollForm($this,
- $this->question,
- $this->options);
-
- $form->show();
-
- return;
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
- $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- return true;
- } else {
- return false;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form for adding a new poll
- *
- * PHP version 5
- *
- * 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 PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form to add a new poll thingy
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class NewpollForm extends Form
-{
- protected $question = null;
- protected $options = array();
-
- /**
- * Construct a new poll form
- *
- * @param HTMLOutputter $out output channel
- *
- * @return void
- */
- function __construct($out=null, $question=null, $options=null)
- {
- parent::__construct($out);
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'newpoll-form';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings ajax-notice';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('newpoll');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'newpoll-data'));
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->out->input('question',
- // TRANS: Field label on the page to create a poll.
- _m('Question'),
- $this->question,
- // TRANS: Field title on the page to create a poll.
- _m('What question are people answering?'));
- $this->unli();
-
- $max = 5;
- if (count($this->options) + 1 > $max) {
- $max = count($this->options) + 2;
- }
- for ($i = 0; $i < $max; $i++) {
- // @fixme make extensible
- if (isset($this->options[$i])) {
- $default = $this->options[$i];
- } else {
- $default = '';
- }
- $this->li();
- $this->out->input('poll-option' . ($i + 1),
- // TRANS: Field label for an answer option on the page to create a poll.
- // TRANS: %d is the option number.
- sprintf(_m('Option %d'), $i + 1),
- $default,
- null,
- 'option' . ($i + 1));
- $this->unli();
- }
-
- $this->out->elementEnd('ul');
-
- $toWidget = new ToSelector($this->out,
- common_current_user(),
- null);
- $toWidget->show();
-
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text for saving a new poll.
- $this->out->submit('poll-submit', _m('BUTTON', 'Save'), 'submit', 'submit');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form for adding a new poll
- *
- * PHP version 5
- *
- * 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 PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form to add a new poll thingy
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class PollResponseForm extends Form
-{
- protected $poll;
-
- /**
- * Construct a new poll form
- *
- * @param Poll $poll
- * @param HTMLOutputter $out output channel
- *
- * @return void
- */
- function __construct(Poll $poll, HTMLOutputter $out)
- {
- parent::__construct($out);
- $this->poll = $poll;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'pollresponse-form';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings ajax';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('respondpoll', array('id' => $this->poll->id));
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $poll = $this->poll;
- $out = $this->out;
- $id = "poll-" . $poll->id;
-
- $out->element('p', 'poll-question', $poll->question);
- $out->elementStart('ul', 'poll-options');
- foreach ($poll->getOptions() as $i => $opt) {
- $out->elementStart('li');
- $out->elementStart('label');
- $out->element('input', array('type' => 'radio', 'name' => 'pollselection', 'value' => $i + 1), '');
- $out->text(' ' . $opt);
- $out->elementEnd('label');
- $out->elementEnd('li');
- }
- $out->elementEnd('ul');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text for submitting a poll response.
- $this->out->submit('poll-response-submit', _m('BUTTON', 'Submit'), 'submit', 'submit');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form for adding a new poll
- *
- * PHP version 5
- *
- * 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 PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form to add a new poll thingy
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class PollResultForm extends Form
-{
- protected $poll;
-
- /**
- * Construct a new poll form
- *
- * @param Poll $poll
- * @param HTMLOutputter $out output channel
- *
- * @return void
- */
- function __construct(Poll $poll, HTMLOutputter $out)
- {
- parent::__construct($out);
- $this->poll = $poll;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'pollresult-form';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings ajax';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('respondpoll', array('id' => $this->poll->id));
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $poll = $this->poll;
- $out = $this->out;
- $counts = $poll->countResponses();
-
- $width = 200;
- $max = max($counts);
- if ($max == 0) {
- $max = 1; // quick hack :D
- }
-
- $out->element('p', 'poll-question', $poll->question);
- $out->elementStart('table', 'poll-results');
- foreach ($poll->getOptions() as $i => $opt) {
- $w = intval($counts[$i] * $width / $max) + 1;
-
- $out->elementStart('tr');
-
- $out->elementStart('td');
- $out->text($opt);
- $out->elementEnd('td');
-
- $out->elementStart('td');
- $out->element('span', array('class' => 'poll-block',
- 'style' => "width: {$w}px"),
- "\xc2\xa0"); // nbsp
- $out->text($counts[$i]);
- $out->elementEnd('td');
-
- $out->elementEnd('tr');
- }
- $out->elementEnd('table');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- }
-}
+++ /dev/null
-<?php
-/**
- * Form to set your personal poll settings
- *
- * StatusNet, the distributed open-source microblogging tool
- *
- * 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 Plugins
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2012 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-class PollSettingsAction extends SettingsAction
-{
- /**
- * Title of the page
- *
- * @return string Page title
- */
- function title()
- {
- // TRANS: Page title.
- return _m('Poll settings');
- }
-
- /**
- * Instructions for use
- *
- * @return string Instructions for use
- */
-
- function getInstructions()
- {
- // TRANS: Page instructions.
- return _m('Set your poll preferences');
- }
-
- /**
- * Show the form for Poll
- *
- * @return void
- */
- function showContent()
- {
- $user = common_current_user();
-
- $prefs = User_poll_prefs::getKV('user_id', $user->id);
-
- $form = new PollPrefsForm($this, $prefs);
-
- $form->show();
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
-
- function handlePost()
- {
- $user = common_current_user();
-
- $upp = User_poll_prefs::getKV('user_id', $user->id);
- $orig = null;
-
- if (!empty($upp)) {
- $orig = clone($upp);
- } else {
- $upp = new User_poll_prefs();
- $upp->user_id = $user->id;
- $upp->created = common_sql_now();
- }
-
- $upp->hide_responses = $this->boolean('hide_responses');
- $upp->modified = common_sql_now();
-
- if (!empty($orig)) {
- $upp->update($orig);
- } else {
- $upp->insert();
- }
-
- // TRANS: Confirmation shown when user profile settings are saved.
- $this->showForm(_('Settings saved.'), true);
-
- return;
- }
-}
-
-class PollPrefsForm extends Form
-{
- var $prefs;
-
- function __construct($out, $prefs)
- {
- parent::__construct($out);
- $this->prefs = $prefs;
- }
-
- /**
- * Visible or invisible data elements
- *
- * Display the form fields that make up the data of the form.
- * Sub-classes should overload this to show their data.
- *
- * @return void
- */
-
- function formData()
- {
- $this->elementStart('fieldset');
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li');
- $this->checkbox('hide_responses',
- _('Do not deliver poll responses to my home timeline'),
- (!empty($this->prefs) && $this->prefs->hide_responses));
- $this->elementEnd('li');
- $this->elementEnd('ul');
- $this->elementEnd('fieldset');
- }
-
- /**
- * Buttons for form actions
- *
- * Submit and cancel buttons (or whatever)
- * Sub-classes should overload this to show their own buttons.
- *
- * @return void
- */
-
- function formActions()
- {
- $this->submit('submit', _('Save'));
- }
-
- /**
- * ID of the form
- *
- * Should be unique on the page. Sub-classes should overload this
- * to show their own IDs.
- *
- * @return int ID of the form
- */
-
- function id()
- {
- return 'form_poll_prefs';
- }
-
- /**
- * Action of the form.
- *
- * URL to post to. Should be overloaded by subclasses to give
- * somewhere to post to.
- *
- * @return string URL to post to
- */
-
- function action()
- {
- return common_local_url('pollsettings');
- }
-
- /**
- * Class of the form. May include space-separated list of multiple classes.
- *
- * @return string the form's class
- */
-
- function formClass()
- {
- return 'form_settings';
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Respond to a Poll
- *
- * PHP version 5
- *
- * 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 Poll
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Respond to a Poll
- *
- * @category Poll
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class RespondPollAction extends Action
-{
- protected $user = null;
- protected $error = null;
- protected $complete = null;
-
- protected $poll = null;
- protected $selection = null;
-
- /**
- * Returns the title of the action
- *
- * @return string Action title
- */
- function title()
- {
- // TRANS: Page title for poll response.
- return _m('Poll response');
- }
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
- if ($this->boolean('ajax')) {
- StatusNet::setApi(true);
- }
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Client exception thrown trying to respond to a poll while not logged in.
- throw new ClientException(_m('You must be logged in to respond to a poll.'),
- 403);
- }
-
- if ($this->isPost()) {
- $this->checkSessionToken();
- }
-
- $id = $this->trimmed('id');
- $this->poll = Poll::getKV('id', $id);
- if (empty($this->poll)) {
- // TRANS: Client exception thrown trying to respond to a non-existing poll.
- throw new ClientException(_m('Invalid or missing poll.'), 404);
- }
-
- $selection = intval($this->trimmed('pollselection'));
- if ($selection < 1 || $selection > count($this->poll->getOptions())) {
- // TRANS: Client exception thrown responding to a poll with an invalid answer.
- throw new ClientException(_m('Invalid poll selection.'));
- }
- $this->selection = $selection;
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- parent::handle($argarray);
-
- if ($this->isPost()) {
- $this->respondPoll();
- } else {
- $this->showPage();
- }
-
- return;
- }
-
- /**
- * Add a new Poll
- *
- * @return void
- */
- function respondPoll()
- {
- try {
- $notice = Poll_response::saveNew($this->user->getProfile(),
- $this->poll,
- $this->selection);
- } catch (ClientException $ce) {
- $this->error = $ce->getMessage();
- $this->showPage();
- return;
- }
-
- if ($this->boolean('ajax')) {
- header('Content-Type: text/xml;charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: Page title after sending a poll response.
- $this->element('title', null, _m('Poll results'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $form = new PollResultForm($this->poll, $this);
- $form->show();
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- common_redirect($this->poll->bestUrl(), 303);
- }
- }
-
- /**
- * Show the Poll form
- *
- * @return void
- */
- function showContent()
- {
- if (!empty($this->error)) {
- $this->element('p', 'error', $this->error);
- }
-
- $form = new PollResponseForm($this->poll, $this);
-
- $form->show();
-
- return;
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- if ($_SERVER['REQUEST_METHOD'] == 'GET' ||
- $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- return true;
- } else {
- return false;
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Show a single Poll
- *
- * PHP version 5
- *
- * 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 PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Show a single Poll, with associated information
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ShowPollAction extends ShownoticeAction
-{
- protected $poll = null;
-
- function getNotice()
- {
- $this->id = $this->trimmed('id');
-
- $this->poll = Poll::getKV('id', $this->id);
-
- if (empty($this->poll)) {
- // TRANS: Client exception thrown trying to view a non-existing poll.
- throw new ClientException(_m('No such poll.'), 404);
- }
-
- $notice = $this->poll->getNotice();
-
- if (empty($notice)) {
- // Did we used to have it, and it got deleted?
- // TRANS: Client exception thrown trying to view a non-existing poll notice.
- throw new ClientException(_m('No such poll notice.'), 404);
- }
-
- return $notice;
- }
-
- /**
- * Title of the page
- *
- * Used by Action class for layout.
- *
- * @return string page tile
- */
- function title()
- {
- // TRANS: Page title for a poll.
- // TRANS: %1$s is the nickname of the user that created the poll, %2$s is the poll question.
- return sprintf(_m('%1$s\'s poll: %2$s'),
- $this->user->nickname,
- $this->poll->question);
- }
-
- /**
- * @fixme combine the notice time with poll update time
- */
- function lastModified()
- {
- return Action::lastModified();
- }
-
-
- /**
- * @fixme combine the notice time with poll update time
- */
- function etag()
- {
- return Action::etag();
- }
-}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'QnanewquestionAction':
- case 'QnanewanswerAction':
- case 'QnashowquestionAction':
- case 'QnaclosequestionAction':
- case 'QnashowanswerAction':
- case 'QnareviseanswerAction':
- case 'QnavoteAction':
- include_once $dir . '/actions/'
- . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'QnanewquestionForm':
- case 'QnashowquestionForm':
- case 'QnanewanswerForm':
- case 'QnashowanswerForm':
- case 'QnareviseanswerForm':
- case 'QnavoteForm':
- include_once $dir . '/lib/' . strtolower($cls).'.php';
- break;
- case 'QnA_Question':
- case 'QnA_Answer':
- case 'QnA_Vote':
- include_once $dir . '/classes/' . $cls.'.php';
- return false;
- break;
- default:
- return true;
- }
- }
-
/**
* Map URLs to actions
*
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for answering a question
+ *
+ * PHP version 5
+ *
+ * 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 QnA
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form to add a new answer to a question
+ *
+ * @category QnA
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class QnanewanswerForm extends Form
+{
+ protected $question;
+ protected $showQuestion;
+
+ /**
+ * Construct a new answer form
+ *
+ * @param QnA_Question $question
+ * @param HTMLOutputter $out output channel
+ *
+ * @return void
+ */
+ function __construct(HTMLOutputter $out, QnA_Question $question, $showQuestion = false)
+ {
+ parent::__construct($out);
+ $this->question = $question;
+ $this->showQuestion = $showQuestion;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'answer-form';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings qna_answer_form ajax-notice';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('qnanewanswer');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $question = $this->question;
+ $out = $this->out;
+ $id = "question-" . $question->id;
+
+ if ($this->showQuestion) {
+ $out->raw($this->question->asHTML());
+ }
+
+ $out->hidden('qna-question-id', $id, 'id');
+ // TRANS: Field label.
+ $out->textarea('qna-answer', _m('Enter your answer'), null, null, 'answer');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text for submitting a poll response.
+ $this->out->submit('qna-answer-submit', _m('BUTTON', 'Answer'), 'submit', 'submit');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for adding a new question
+ *
+ * PHP version 5
+ *
+ * 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 QnA
+ * @package StatusNet
+ * @author Zach Copley <zach@copley.name>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form to add a new question
+ *
+ * @category QnA
+ * @package StatusNet
+ * @author Zach Copley <zach@copley.name>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class QnanewquestionForm extends Form
+{
+ protected $title;
+ protected $description;
+
+ /**
+ * Construct a new question form
+ *
+ * @param HTMLOutputter $out output channel
+ *
+ * @return void
+ */
+ function __construct($out = null, $title = null, $description = null, $options = null)
+ {
+ parent::__construct($out);
+ $this->title = $title;
+ $this->description = $description;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'newquestion-form';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings ajax-notice';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('qnanewquestion');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'newquestion-data'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input(
+ 'qna-question-title',
+ // TRANS: Field label for a new question.
+ _m('LABEL','Title'),
+ $this->title,
+ // TRANS: Field title for a new question.
+ _m('The title of your question.'),
+ 'title'
+ );
+ $this->unli();
+ $this->li();
+ $this->out->textarea(
+ 'qna-question-description',
+ // TRANS: Field label for question details.
+ _m('LABEL','Description'),
+ $this->description,
+ // TRANS: Field title for question details.
+ _m('Your question in detail.'),
+ 'description'
+ );
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+ $toWidget = new ToSelector(
+ $this->out,
+ common_current_user(),
+ null
+ );
+ $toWidget->show();
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text for saving a new question.
+ $this->out->submit('qna-question-submit', _m('BUTTON', 'Save'), 'submit', 'submit');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for revising a question
+ *
+ * PHP version 5
+ *
+ * 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 QnA
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form to revise a question
+ *
+ * @category QnA
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class QnareviseanswerForm extends Form
+{
+ protected $question;
+ protected $answer;
+
+ /**
+ * Construct a new answer form
+ *
+ * @param QnA_Answer $answer
+ * @param HTMLOutputter $out output channel
+ *
+ * @return void
+ */
+ function __construct(QnA_Answer $answer, HTMLOutputter $out)
+ {
+ parent::__construct($out);
+ $this->question = $answer->getQuestion();
+ $this->answer = $answer;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'answered-form';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('qnareviseanswer');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $out = $this->out;
+ $out->element('p', 'revise-answer', 'Your answer');
+ $id = "answer-" . $this->answer->id;
+ $out->hidden('id', $id);
+ $out->textarea('answer', 'answer', $this->answer->content);
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text for submitting a revised answer.
+ $this->out->submit('submit', _m('BUTTON', 'Submit'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for showing / revising an answer
+ *
+ * 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 Form
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/lib/form.php';
+
+/**
+ * Form for showing / revising an answer
+ *
+ * @category Form
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ *
+ */
+class QnashowanswerForm extends Form
+{
+ /**
+ * The answer to show
+ */
+ protected $answer = null;
+
+ /**
+ * The question this is an answer to
+ */
+ protected $question = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param QnA_Answer $answer answer to revise
+ */
+ function __construct($out = null, $answer = null)
+ {
+ parent::__construct($out);
+
+ $this->answer = $answer;
+ $this->question = $answer->getQuestion();
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'show-' . $this->answer->id;
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('qnareviseanswer');
+ }
+
+ /**
+ * Include a session token for CSRF protection
+ *
+ * @return void
+ */
+ function sessionToken()
+ {
+ $this->out->hidden(
+ 'token',
+ common_session_token()
+ );
+ }
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend for showing the answer.
+ $this->out->element('legend', null, _m('Answer'));
+ }
+
+ /**
+ * Data elements
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->hidden(
+ 'qna-answer-id',
+ 'answer-' . $this->answer->id,
+ 'id'
+ );
+
+ $this->out->raw($this->answer->asHTML());
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $user = common_current_user();
+ if (empty($user)) {
+ return;
+ }
+
+ if (empty($this->question->closed)) {
+ if ($user->id == $this->question->profile_id) {
+ if (empty($this->answer->best)) {
+ $this->out->submit(
+ 'qna-best-answer',
+ // TRANS: Button text for marking an answer as "best".
+ _m('BUTTON', 'Best'),
+ 'submit',
+ 'best',
+ // TRANS: Title for button text marking an answer as "best".
+ _m('Mark this answer as the best answer.')
+ );
+
+ }
+ }
+
+ /*
+ * @todo FIXME: Revise is disabled until we figure out the
+ * Ostatus bits This comment is just a reminder
+ * that the UI for this works.
+ */
+ /*
+ if ($user->id == $this->answer->profile_id) {
+ $this->out->submit(
+ 'revise',
+ // TRANS: Button text for revising an answer.
+ _m('BUTTON', 'Revise'),
+ 'submit',
+ null,
+ // TRANS: Title for button text for revising an answer.
+ _m('Revise your answer.')
+ );
+ }
+ */
+ }
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+ function formClass()
+ {
+ return 'form_answer_show ajax';
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for showing / revising an answer
+ *
+ * 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 Form
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/lib/form.php';
+
+/**
+ * Form for showing a question
+ *
+ * @category Form
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ *
+ */
+class QnashowquestionForm extends Form
+{
+ /**
+ * The question to show
+ */
+ var $question = null;
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param QnA_Question $question the question to show
+ */
+ function __construct($out = null, $question = null)
+ {
+ parent::__construct($out);
+ $this->question = $question;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'question-' . $this->question->id;
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('qnaclosequestion');
+ }
+
+ /**
+ * Include a session token for CSRF protection
+ *
+ * @return void
+ */
+ function sessionToken()
+ {
+ $this->out->hidden(
+ 'token',
+ common_session_token()
+ );
+ }
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend for revising the answer.
+ $this->out->element('legend', null, _m('LEGEND','Question'));
+ }
+
+ /**
+ * Data elements
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->hidden(
+ 'qna-question-id',
+ 'question-' . $this->question->id,
+ 'id'
+ );
+
+ $this->out->hidden(
+ 'answer-action',
+ common_local_url(
+ 'qnanewanswer',
+ null,
+ array('id' => 'question-' . $this->question->id)
+ )
+ );
+
+ $this->out->raw($this->question->asHTML());
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $user = common_current_user();
+ if (empty($user)) {
+ return;
+ }
+
+ if (empty($this->question->closed)) {
+ if ($user->id == $this->question->profile_id) {
+ $this->out->submit(
+ 'qna-question-close',
+ // TRANS: Button text for closing a question.
+ _m('BUTTON', 'Close'),
+ 'submit',
+ 'submit',
+ // TRANS: Title for button text for closing a question.
+ _m('Close the question to no one can answer it anymore.')
+ );
+ }
+ }
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+ function formClass()
+ {
+ return 'form_question_show ajax';
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for answering a question
+ *
+ * PHP version 5
+ *
+ * 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 QnA
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form to add a new answer to a question
+ *
+ * @category QnA
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class QnavoteForm extends Form
+{
+ protected $question;
+
+ /**
+ * Construct a new answer form
+ *
+ * @param QnA_Question $question
+ * @param HTMLOutputter $out output channel
+ *
+ * @return void
+ */
+ function __construct(QnA_Question $question, HTMLOutputter $out)
+ {
+ parent::__construct($out);
+ $this->question = $question;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'answer-form';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('qnavote', array('id' => $this->question->id));
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $question = $this->question;
+ $out = $this->out;
+ $id = "question-" . $question->id;
+
+ $out->element('p', 'answer', $question->question);
+ $out->element('input', array('type' => 'text', 'name' => 'vote'));
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text for submitting a poll response.
+ $this->out->submit('submit', _m('BUTTON', 'Submit'));
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form for answering a question
- *
- * PHP version 5
- *
- * 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 QnA
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form to add a new answer to a question
- *
- * @category QnA
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class QnanewanswerForm extends Form
-{
- protected $question;
- protected $showQuestion;
-
- /**
- * Construct a new answer form
- *
- * @param QnA_Question $question
- * @param HTMLOutputter $out output channel
- *
- * @return void
- */
- function __construct(HTMLOutputter $out, QnA_Question $question, $showQuestion = false)
- {
- parent::__construct($out);
- $this->question = $question;
- $this->showQuestion = $showQuestion;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'answer-form';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings qna_answer_form ajax-notice';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('qnanewanswer');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $question = $this->question;
- $out = $this->out;
- $id = "question-" . $question->id;
-
- if ($this->showQuestion) {
- $out->raw($this->question->asHTML());
- }
-
- $out->hidden('qna-question-id', $id, 'id');
- // TRANS: Field label.
- $out->textarea('qna-answer', _m('Enter your answer'), null, null, 'answer');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text for submitting a poll response.
- $this->out->submit('qna-answer-submit', _m('BUTTON', 'Answer'), 'submit', 'submit');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form for adding a new question
- *
- * PHP version 5
- *
- * 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 QnA
- * @package StatusNet
- * @author Zach Copley <zach@copley.name>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form to add a new question
- *
- * @category QnA
- * @package StatusNet
- * @author Zach Copley <zach@copley.name>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class QnanewquestionForm extends Form
-{
- protected $title;
- protected $description;
-
- /**
- * Construct a new question form
- *
- * @param HTMLOutputter $out output channel
- *
- * @return void
- */
- function __construct($out = null, $title = null, $description = null, $options = null)
- {
- parent::__construct($out);
- $this->title = $title;
- $this->description = $description;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'newquestion-form';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings ajax-notice';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('qnanewquestion');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('fieldset', array('id' => 'newquestion-data'));
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->out->input(
- 'qna-question-title',
- // TRANS: Field label for a new question.
- _m('LABEL','Title'),
- $this->title,
- // TRANS: Field title for a new question.
- _m('The title of your question.'),
- 'title'
- );
- $this->unli();
- $this->li();
- $this->out->textarea(
- 'qna-question-description',
- // TRANS: Field label for question details.
- _m('LABEL','Description'),
- $this->description,
- // TRANS: Field title for question details.
- _m('Your question in detail.'),
- 'description'
- );
- $this->unli();
-
- $this->out->elementEnd('ul');
- $toWidget = new ToSelector(
- $this->out,
- common_current_user(),
- null
- );
- $toWidget->show();
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text for saving a new question.
- $this->out->submit('qna-question-submit', _m('BUTTON', 'Save'), 'submit', 'submit');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form for revising a question
- *
- * PHP version 5
- *
- * 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 QnA
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form to revise a question
- *
- * @category QnA
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class QnareviseanswerForm extends Form
-{
- protected $question;
- protected $answer;
-
- /**
- * Construct a new answer form
- *
- * @param QnA_Answer $answer
- * @param HTMLOutputter $out output channel
- *
- * @return void
- */
- function __construct(QnA_Answer $answer, HTMLOutputter $out)
- {
- parent::__construct($out);
- $this->question = $answer->getQuestion();
- $this->answer = $answer;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'answered-form';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings ajax';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('qnareviseanswer');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $out = $this->out;
- $out->element('p', 'revise-answer', 'Your answer');
- $id = "answer-" . $this->answer->id;
- $out->hidden('id', $id);
- $out->textarea('answer', 'answer', $this->answer->content);
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text for submitting a revised answer.
- $this->out->submit('submit', _m('BUTTON', 'Submit'));
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for showing / revising an answer
- *
- * 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 Form
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/lib/form.php';
-
-/**
- * Form for showing / revising an answer
- *
- * @category Form
- * @package StatusNet
- * @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
- * @link http://status.net/
- *
- */
-class QnashowanswerForm extends Form
-{
- /**
- * The answer to show
- */
- protected $answer = null;
-
- /**
- * The question this is an answer to
- */
- protected $question = null;
-
- /**
- * Constructor
- *
- * @param HTMLOutputter $out output channel
- * @param QnA_Answer $answer answer to revise
- */
- function __construct($out = null, $answer = null)
- {
- parent::__construct($out);
-
- $this->answer = $answer;
- $this->question = $answer->getQuestion();
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'show-' . $this->answer->id;
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('qnareviseanswer');
- }
-
- /**
- * Include a session token for CSRF protection
- *
- * @return void
- */
- function sessionToken()
- {
- $this->out->hidden(
- 'token',
- common_session_token()
- );
- }
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend for showing the answer.
- $this->out->element('legend', null, _m('Answer'));
- }
-
- /**
- * Data elements
- *
- * @return void
- */
- function formData()
- {
- $this->out->hidden(
- 'qna-answer-id',
- 'answer-' . $this->answer->id,
- 'id'
- );
-
- $this->out->raw($this->answer->asHTML());
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $user = common_current_user();
- if (empty($user)) {
- return;
- }
-
- if (empty($this->question->closed)) {
- if ($user->id == $this->question->profile_id) {
- if (empty($this->answer->best)) {
- $this->out->submit(
- 'qna-best-answer',
- // TRANS: Button text for marking an answer as "best".
- _m('BUTTON', 'Best'),
- 'submit',
- 'best',
- // TRANS: Title for button text marking an answer as "best".
- _m('Mark this answer as the best answer.')
- );
-
- }
- }
-
- /*
- * @todo FIXME: Revise is disabled until we figure out the
- * Ostatus bits This comment is just a reminder
- * that the UI for this works.
- */
- /*
- if ($user->id == $this->answer->profile_id) {
- $this->out->submit(
- 'revise',
- // TRANS: Button text for revising an answer.
- _m('BUTTON', 'Revise'),
- 'submit',
- null,
- // TRANS: Title for button text for revising an answer.
- _m('Revise your answer.')
- );
- }
- */
- }
- }
-
- /**
- * Class of the form.
- *
- * @return string the form's class
- */
- function formClass()
- {
- return 'form_answer_show ajax';
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for showing / revising an answer
- *
- * 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 Form
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/lib/form.php';
-
-/**
- * Form for showing a question
- *
- * @category Form
- * @package StatusNet
- * @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
- * @link http://status.net/
- *
- */
-class QnashowquestionForm extends Form
-{
- /**
- * The question to show
- */
- var $question = null;
-
- /**
- * Constructor
- *
- * @param HTMLOutputter $out output channel
- * @param QnA_Question $question the question to show
- */
- function __construct($out = null, $question = null)
- {
- parent::__construct($out);
- $this->question = $question;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'question-' . $this->question->id;
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('qnaclosequestion');
- }
-
- /**
- * Include a session token for CSRF protection
- *
- * @return void
- */
- function sessionToken()
- {
- $this->out->hidden(
- 'token',
- common_session_token()
- );
- }
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend for revising the answer.
- $this->out->element('legend', null, _m('LEGEND','Question'));
- }
-
- /**
- * Data elements
- *
- * @return void
- */
- function formData()
- {
- $this->out->hidden(
- 'qna-question-id',
- 'question-' . $this->question->id,
- 'id'
- );
-
- $this->out->hidden(
- 'answer-action',
- common_local_url(
- 'qnanewanswer',
- null,
- array('id' => 'question-' . $this->question->id)
- )
- );
-
- $this->out->raw($this->question->asHTML());
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $user = common_current_user();
- if (empty($user)) {
- return;
- }
-
- if (empty($this->question->closed)) {
- if ($user->id == $this->question->profile_id) {
- $this->out->submit(
- 'qna-question-close',
- // TRANS: Button text for closing a question.
- _m('BUTTON', 'Close'),
- 'submit',
- 'submit',
- // TRANS: Title for button text for closing a question.
- _m('Close the question to no one can answer it anymore.')
- );
- }
- }
- }
-
- /**
- * Class of the form.
- *
- * @return string the form's class
- */
- function formClass()
- {
- return 'form_question_show ajax';
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Form for answering a question
- *
- * PHP version 5
- *
- * 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 QnA
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Form to add a new answer to a question
- *
- * @category QnA
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class QnavoteForm extends Form
-{
- protected $question;
-
- /**
- * Construct a new answer form
- *
- * @param QnA_Question $question
- * @param HTMLOutputter $out output channel
- *
- * @return void
- */
- function __construct(QnA_Question $question, HTMLOutputter $out)
- {
- parent::__construct($out);
- $this->question = $question;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'answer-form';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings ajax';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('qnavote', array('id' => $this->question->id));
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $question = $this->question;
- $out = $this->out;
- $id = "question-" . $question->id;
-
- $out->element('p', 'answer', $question->question);
- $out->element('input', array('type' => 'text', 'name' => 'vote'));
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text for submitting a poll response.
- $this->out->submit('submit', _m('BUTTON', 'Submit'));
- }
-}
+++ /dev/null
-<?php
-/**
- * This test class pretends to be an RSS aggregator. It logs notifications
- * from the cloud.
- *
- * PHP version 5
- *
- * @category Plugin
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Dummy aggregator that acts as a proper notification handler. It
- * doesn't do anything but respond correctly when notified via
- * REST. Mostly, this is just and action I used to develop the plugin
- * and easily test things end-to-end. I'm leaving it in here as it
- * may be useful for developing the plugin further.
- *
- * @category Plugin
- * @package StatusNet
- * @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
- * @link http://status.net/
- */
-class LoggingAggregatorAction extends Action
-{
- var $challenge = null;
- var $url = null;
-
- /**
- * Initialization.
- *
- * @param array $args Web and URL arguments
- *
- * @return boolean false if user doesn't exist
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $this->url = $this->arg('url');
- $this->challenge = $this->arg('challenge');
-
- common_debug("args = " . var_export($this->args, true));
- common_debug('url = ' . $this->url . ' challenge = ' . $this->challenge);
-
- return true;
- }
-
- /**
- * Handle the request
- *
- * @param array $args $_REQUEST data (unused)
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- if (empty($this->url)) {
- // TRANS: Form validation error displayed when a URL parameter is missing.
- $this->showError(_m('A URL parameter is required.'));
- return;
- }
-
- if (!empty($this->challenge)) {
- // must be a GET
- if ($_SERVER['REQUEST_METHOD'] != 'GET') {
- // TRANS: Form validation error displayed when HTTP GET is not used.
- $this->showError(_m('This resource requires an HTTP GET.'));
- return;
- }
-
- header('Content-Type: text/xml');
- echo $this->challenge;
- } else {
- // must be a POST
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- // TRANS: Form validation error displayed when HTTP POST is not used.
- $this->showError(_m('This resource requires an HTTP POST.'));
- return;
- }
-
- header('Content-Type: text/xml');
- Echo "<notifyResult success='true' msg='Thanks for the update.' />\n";
- }
-
- $this->ip = $_SERVER['REMOTE_ADDR'];
-
- common_log(LOG_INFO, 'RSSCloud Logging Aggregator - ' .
- $this->ip . ' claims the feed at ' .
- $this->url . ' has been updated.');
- }
-
- /**
- * Show an XML error when things go badly
- *
- * @param string $msg the error message
- *
- * @return void
- */
- function showError($msg)
- {
- header('HTTP/1.1 400 Bad Request');
- header('Content-Type: text/xml');
- echo "<?xml version='1.0'?>\n";
- echo "<notifyResult success='false' msg='$msg' />\n";
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Class to ping an rssCloud endpoint when a feed has been updated
- *
- * 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
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Class for notifying cloud-enabled RSS aggregators that StatusNet
- * feeds have been updated.
- *
- * @category Plugin
- * @package StatusNet
- * @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
- * @link http://status.net/
- */
-class RSSCloudNotifier
-{
- const MAX_FAILURES = 3;
-
- /**
- * Send an HTTP GET to the notification handler with a
- * challenge string to see if it repsonds correctly.
- *
- * @param string $endpoint URL of the notification handler
- * @param string $feed the feed being subscribed to
- *
- * @return boolean success
- */
- function challenge($endpoint, $feed)
- {
- $code = common_confirmation_code(128);
- $params = array('url' => $feed, 'challenge' => $code);
- $url = $endpoint . '?' . http_build_query($params);
-
- try {
- $client = new HTTPClient();
- $response = $client->get($url);
- } catch (HTTP_Request2_Exception $e) {
- common_log(LOG_INFO,
- 'RSSCloud plugin - failure testing notify handler ' .
- $endpoint . ' - ' . $e->getMessage());
- return false;
- }
-
- // Check response is betweet 200 and 299 and body contains challenge data
-
- $status = $response->getStatus();
- $body = $response->getBody();
-
- if ($status >= 200 && $status < 300) {
- // NOTE: the spec says that the body must contain the string
- // challenge. It doesn't say that the body must contain the
- // challenge string ONLY, although that seems to be the way
- // the other implementors have interpreted it.
-
- if (strpos($body, $code) !== false) {
- common_log(LOG_INFO, 'RSSCloud plugin - ' .
- "success testing notify handler: $endpoint");
- return true;
- } else {
- common_log(LOG_INFO, 'RSSCloud plugin - ' .
- 'challenge/repsonse failed for notify handler ' .
- $endpoint);
- common_debug('body = ' . var_export($body, true));
- return false;
- }
- } else {
- common_log(LOG_INFO, 'RSSCloud plugin - ' .
- "failure testing notify handler: $endpoint " .
- ' - got HTTP ' . $status);
- common_debug('body = ' . var_export($body, true));
- return false;
- }
- }
-
- /**
- * HTTP POST a notification that a feed has been updated
- * ('ping the cloud').
- *
- * @param String $endpoint URL of the notification handler
- * @param String $feed the feed being subscribed to
- *
- * @return boolean success
- */
- function postUpdate($endpoint, $feed)
- {
- $headers = array();
- $postdata = array('url' => $feed);
-
- try {
- $client = new HTTPClient();
- $response = $client->post($endpoint, $headers, $postdata);
- } catch (HTTP_Request2_Exception $e) {
- common_log(LOG_INFO, 'RSSCloud plugin - failure notifying ' .
- $endpoint . ' that feed ' . $feed .
- ' has changed: ' . $e->getMessage());
- return false;
- }
-
- $status = $response->getStatus();
-
- if ($status >= 200 && $status < 300) {
- common_log(LOG_INFO, 'RSSCloud plugin - success notifying ' .
- $endpoint . ' that feed ' . $feed . ' has changed.');
- return true;
- } else {
- common_log(LOG_INFO, 'RSSCloud plugin - failure notifying ' .
- $endpoint . ' that feed ' . $feed .
- ' has changed: got HTTP ' . $status);
- return false;
- }
- }
-
- /**
- * Notify all subscribers to a profile feed that it has changed.
- *
- * @param Profile $profile the profile whose feed has been
- * updated
- *
- * @return boolean success
- */
- function notify($profile)
- {
- $feed = common_path('api/statuses/user_timeline/') .
- $profile->id . '.rss';
-
- $cloudSub = new RSSCloudSubscription();
-
- $cloudSub->subscribed = $profile->id;
-
- if ($cloudSub->find()) {
- while ($cloudSub->fetch()) {
- $result = $this->postUpdate($cloudSub->url, $feed);
- if ($result == false) {
- $this->handleFailure($cloudSub);
- }
- }
- }
-
- return true;
- }
-
- /**
- * Handle problems posting cloud notifications. Increment the failure
- * count, or delete the subscription if the maximum number of failures
- * is exceeded.
- *
- * XXX: Redo with proper DB_DataObject methods once I figure out what
- * what the problem is with pluginized DB_DataObjects. -Z
- *
- * @param RSSCloudSubscription $cloudSub the subscription in question
- *
- * @return boolean success
- */
- function handleFailure($cloudSub)
- {
- $failCnt = $cloudSub->failures + 1;
-
- if ($failCnt == self::MAX_FAILURES) {
-
- common_log(LOG_INFO,
- 'Deleting RSSCloud subcription ' .
- '(max failure count reached), profile: ' .
- $cloudSub->subscribed .
- ' handler: ' .
- $cloudSub->url);
-
- // XXX: WTF! ->delete() doesn't work. Clearly, there are some issues with
- // the DB_DataObject, or my understanding of it. Have to drop into SQL.
-
- // $result = $cloudSub->delete();
-
- $qry = 'DELETE from rsscloud_subscription' .
- ' WHERE subscribed = ' . $cloudSub->subscribed .
- ' AND url = \'' . $cloudSub->url . '\'';
-
- $result = $cloudSub->query($qry);
-
- if (!$result) {
- common_log_db_error($cloudSub, 'DELETE', __FILE__);
- common_log(LOG_ERR, 'Could not delete RSSCloud subscription.');
- }
- } else {
- common_debug('Updating failure count on RSSCloud subscription. ' .
- $failCnt);
-
- $failCnt = $cloudSub->failures + 1;
-
- // XXX: ->update() not working either, gar!
-
- $qry = 'UPDATE rsscloud_subscription' .
- ' SET failures = ' . $failCnt .
- ' WHERE subscribed = ' . $cloudSub->subscribed .
- ' AND url = \'' . $cloudSub->url . '\'';
-
- $result = $cloudSub->query($qry);
-
- if (!$result) {
- common_log_db_error($cloudsub, 'UPDATE', __FILE__);
- common_log(LOG_ERR,
- 'Could not update failure ' .
- 'count on RSSCloud subscription');
- }
- }
- }
-}
return true;
}
- /**
- * Automatically load the actions and libraries used by
- * the RSSCloud plugin
- *
- * @param Class $cls the class
- *
- * @return boolean hook return
- *
- */
- function onAutoload($cls)
- {
- switch ($cls)
- {
- case 'RSSCloudSubscription':
- include_once INSTALLDIR . '/plugins/RSSCloud/RSSCloudSubscription.php';
- return false;
- case 'RSSCloudNotifier':
- include_once INSTALLDIR . '/plugins/RSSCloud/RSSCloudNotifier.php';
- return false;
- case 'RSSCloudQueueHandler':
- include_once INSTALLDIR . '/plugins/RSSCloud/RSSCloudQueueHandler.php';
- return false;
- case 'RSSCloudRequestNotifyAction':
- case 'LoggingAggregatorAction':
- include_once INSTALLDIR . '/plugins/RSSCloud/' .
- mb_substr($cls, 0, -6) . '.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Add a <cloud> element to the RSS feed (after the rss <channel>
* element is started).
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-class RSSCloudQueueHandler extends QueueHandler
-{
- function transport()
- {
- return 'rsscloud';
- }
-
- function handle($notice)
- {
- try {
- $profile = $notice->getProfile();
- } catch (Exception $e) {
- common_log(LOG_ERR, "Dropping RSSCloud item for notice with bogus profile: " . $e->getMessage());
- return true;
- }
- $notifier = new RSSCloudNotifier();
- return $notifier->notify($profile);
- }
-}
+++ /dev/null
-<?php
-/**
- * Action to let RSSCloud aggregators request update notification when
- * user profile feeds change.
- *
- * PHP version 5
- *
- * @category Plugin
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Action class to handle RSSCloud notification (subscription) requests
- *
- * @category Plugin
- * @package StatusNet
- * @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
- * @link http://status.net/
- */
-class RSSCloudRequestNotifyAction extends Action
-{
- /**
- * Initialization.
- *
- * @param array $args Web and URL arguments
- *
- * @return boolean false if user doesn't exist
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $this->ip = $_SERVER['REMOTE_ADDR'];
- $this->port = $this->arg('port');
- $this->path = $this->arg('path');
-
- if ($this->path[0] != '/') {
- $this->path = '/' . $this->path;
- }
-
- $this->protocol = $this->arg('protocol');
- $this->procedure = $this->arg('notifyProcedure');
- $this->domain = $this->arg('domain');
-
- $this->feeds = $this->getFeeds();
-
- return true;
- }
-
- /**
- * Handle the request
- *
- * Checks for all the required parameters for a subscription,
- * validates that the feed being subscribed to is real, and then
- * saves the subsctiption.
- *
- * @param array $args $_REQUEST data (unused)
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- // TRANS: Form validation error displayed when POST is not used.
- $this->showResult(false, _m('Request must be POST.'));
- return;
- }
-
- $missing = array();
-
- if (empty($this->port)) {
- $missing[] = 'port';
- }
-
- if (empty($this->path)) {
- $missing[] = 'path';
- }
-
- if (empty($this->protocol)) {
- $missing[] = 'protocol';
- } else if (strtolower($this->protocol) != 'http-post') {
- // TRANS: Form validation error displayed when HTTP POST is not used.
- $msg = _m('Only HTTP POST notifications are supported at this time.');
- $this->showResult(false, $msg);
- return;
- }
-
- if (!isset($this->procedure)) {
- $missing[] = 'notifyProcedure';
- }
-
- if (!empty($missing)) {
- // TRANS: List separator.
- $separator = _m('SEPARATOR',', ');
- // TRANS: Form validation error displayed when a request body is missing expected parameters.
- // TRANS: %s is a list of parameters separated by a list separator (default: ", ").
- $msg = sprintf(_m('The following parameters were missing from the request body: %s.'),implode($separator, $missing));
- $this->showResult(false, $msg);
- return;
- }
-
- if (empty($this->feeds)) {
- // TRANS: Form validation error displayed when not providing any valid profile feed URLs.
- $msg = _m('You must provide at least one valid profile feed URL ' .
- '(url1, url2, url3 ... urlN).');
- $this->showResult(false, $msg);
- return;
- }
-
- // We have to validate everything before saving anything.
- // We only return one success or failure no matter how
- // many feeds the subscriber is trying to subscribe to
- foreach ($this->feeds as $feed) {
- if (!$this->validateFeed($feed)) {
- $nh = $this->getNotifyUrl();
- common_log(LOG_WARNING,
- "RSSCloud plugin - $nh tried to subscribe to invalid feed: $feed");
-
- // TRANS: Form validation error displayed when not providing a valid feed URL.
- $msg = _m('Feed subscription failed: Not a valid feed.');
- $this->showResult(false, $msg);
- return;
- }
-
- if (!$this->testNotificationHandler($feed)) {
- // TRANS: Form validation error displayed when feed subscription failed.
- $msg = _m('Feed subscription failed: ' .
- 'Notification handler does not respond correctly.');
- $this->showResult(false, $msg);
- return;
- }
- }
-
- foreach ($this->feeds as $feed) {
- $this->saveSubscription($feed);
- }
-
- // XXX: What to do about deleting stale subscriptions?
- // 25 hours seems harsh. WordPress doesn't ever remove
- // subscriptions.
- // TRANS: Success message after subscribing to one or more feeds.
- $msg = _m('Thanks for the subscription. ' .
- 'When the feed(s) update(s), you will be notified.');
-
- $this->showResult(true, $msg);
- }
-
- /**
- * Validate that the requested feed is one we serve
- * up via RSSCloud.
- *
- * @param string $feed the feed in question
- *
- * @return void
- */
- function validateFeed($feed)
- {
- $user = $this->userFromFeed($feed);
-
- if (empty($user)) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Pull all of the urls (url1, url2, url3...urlN) that
- * the subscriber wants to subscribe to.
- *
- * @return array $feeds the list of feeds
- */
- function getFeeds()
- {
- $feeds = array();
-
- while (list($key, $feed) = each($this->args)) {
- if (preg_match('/^url\d*$/', $key)) {
- $feeds[] = $feed;
- }
- }
-
- return $feeds;
- }
-
- /**
- * Test that a notification handler is there and is reponding
- * correctly. This is called before adding a subscription.
- *
- * @param string $feed the feed to verify
- *
- * @return boolean success result
- */
- function testNotificationHandler($feed)
- {
- $notifyUrl = $this->getNotifyUrl();
-
- $notifier = new RSSCloudNotifier();
-
- if (isset($this->domain)) {
- // 'domain' param set, so we have to use GET and send a challenge
- common_log(LOG_INFO,
- 'RSSCloud plugin - Testing notification handler with challenge: ' .
- $notifyUrl);
- return $notifier->challenge($notifyUrl, $feed);
- } else {
- common_log(LOG_INFO, 'RSSCloud plugin - Testing notification handler: ' .
- $notifyUrl);
-
- return $notifier->postUpdate($notifyUrl, $feed);
- }
- }
-
- /**
- * Build the URL for the notification handler based on the
- * parameters passed in with the subscription request.
- *
- * @return string notification handler url
- */
- function getNotifyUrl()
- {
- if (isset($this->domain)) {
- return 'http://' . $this->domain . ':' . $this->port . $this->path;
- } else {
- return 'http://' . $this->ip . ':' . $this->port . $this->path;
- }
- }
-
- /**
- * Uses the nickname part of the subscribed feed URL to figure out
- * whethere there's really a user with such a feed. Used to
- * validate feeds before adding a subscription.
- *
- * @param string $feed the feed in question
- *
- * @return boolean success
- */
- function userFromFeed($feed)
- {
- // We only do canonical RSS2 profile feeds (specified by ID), e.g.:
- // http://www.example.com/api/statuses/user_timeline/2.rss
- $path = common_path('api/statuses/user_timeline/');
- $valid = '%^' . $path . '(?<id>.*)\.rss$%';
-
- if (preg_match($valid, $feed, $matches)) {
- $user = User::getKV('id', $matches['id']);
- if (!empty($user)) {
- return $user;
- }
- }
-
- return false;
- }
-
- /**
- * Save an RSSCloud subscription
- *
- * @param string $feed a valid profile feed
- *
- * @return boolean success result
- */
- function saveSubscription($feed)
- {
- $user = $this->userFromFeed($feed);
-
- $notifyUrl = $this->getNotifyUrl();
-
- $sub = RSSCloudSubscription::getSubscription($user->id, $notifyUrl);
-
- if ($sub) {
- common_log(LOG_INFO, "RSSCloud plugin - $notifyUrl refreshed subscription" .
- " to user $user->nickname (id: $user->id).");
- } else {
- $sub = new RSSCloudSubscription();
-
- $sub->subscribed = $user->id;
- $sub->url = $notifyUrl;
- $sub->created = common_sql_now();
-
- if (!$sub->insert()) {
- common_log_db_error($sub, 'INSERT', __FILE__);
- return false;
- }
-
- common_log(LOG_INFO, "RSSCloud plugin - $notifyUrl subscribed" .
- " to user $user->nickname (id: $user->id)");
- }
-
- return true;
- }
-
- /**
- * Show an XML message indicating the subscription
- * was successful or failed.
- *
- * @param boolean $success whether it was good or bad
- * @param string $msg the message to output
- *
- * @return boolean success result
- */
- function showResult($success, $msg)
- {
- $this->startXML();
- $this->elementStart('notifyResult',
- array('success' => ($success) ? 'true' : 'false',
- 'msg' => $msg));
- $this->endXML();
- }
-}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * Table Definition for rsscloud_subscription
- */
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-class RSSCloudSubscription extends Memcached_DataObject {
-
- var $__table='rsscloud_subscription'; // table name
- 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()
- {
-
- $db = $this->getDatabaseConnection();
- $dbtype = $db->phptype;
-
- $cols = array('subscribed' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
- 'url' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
- 'failures' => DB_DATAOBJECT_INT,
- 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL,
- 'modified' => ($dbtype == 'mysql' || $dbtype == 'mysqli') ?
- DB_DATAOBJECT_MYSQLTIMESTAMP + DB_DATAOBJECT_NOTNULL :
- DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME
- );
-
- return $cols;
- }
-
- function keys()
- {
- return array('subscribed' => 'N', 'url' => 'N');
- }
-
- static function getSubscription($subscribed, $url)
- {
- $sub = new RSSCloudSubscription();
- $sub->whereAdd("subscribed = $subscribed");
- $sub->whereAdd("url = '$url'");
- $sub->limit(1);
-
- if ($sub->find()) {
- $sub->fetch();
- return $sub;
- }
-
- return false;
- }
-}
--- /dev/null
+<?php
+/**
+ * This test class pretends to be an RSS aggregator. It logs notifications
+ * from the cloud.
+ *
+ * PHP version 5
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Dummy aggregator that acts as a proper notification handler. It
+ * doesn't do anything but respond correctly when notified via
+ * REST. Mostly, this is just and action I used to develop the plugin
+ * and easily test things end-to-end. I'm leaving it in here as it
+ * may be useful for developing the plugin further.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ */
+class LoggingAggregatorAction extends Action
+{
+ var $challenge = null;
+ var $url = null;
+
+ /**
+ * Initialization.
+ *
+ * @param array $args Web and URL arguments
+ *
+ * @return boolean false if user doesn't exist
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->url = $this->arg('url');
+ $this->challenge = $this->arg('challenge');
+
+ common_debug("args = " . var_export($this->args, true));
+ common_debug('url = ' . $this->url . ' challenge = ' . $this->challenge);
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (empty($this->url)) {
+ // TRANS: Form validation error displayed when a URL parameter is missing.
+ $this->showError(_m('A URL parameter is required.'));
+ return;
+ }
+
+ if (!empty($this->challenge)) {
+ // must be a GET
+ if ($_SERVER['REQUEST_METHOD'] != 'GET') {
+ // TRANS: Form validation error displayed when HTTP GET is not used.
+ $this->showError(_m('This resource requires an HTTP GET.'));
+ return;
+ }
+
+ header('Content-Type: text/xml');
+ echo $this->challenge;
+ } else {
+ // must be a POST
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ // TRANS: Form validation error displayed when HTTP POST is not used.
+ $this->showError(_m('This resource requires an HTTP POST.'));
+ return;
+ }
+
+ header('Content-Type: text/xml');
+ Echo "<notifyResult success='true' msg='Thanks for the update.' />\n";
+ }
+
+ $this->ip = $_SERVER['REMOTE_ADDR'];
+
+ common_log(LOG_INFO, 'RSSCloud Logging Aggregator - ' .
+ $this->ip . ' claims the feed at ' .
+ $this->url . ' has been updated.');
+ }
+
+ /**
+ * Show an XML error when things go badly
+ *
+ * @param string $msg the error message
+ *
+ * @return void
+ */
+ function showError($msg)
+ {
+ header('HTTP/1.1 400 Bad Request');
+ header('Content-Type: text/xml');
+ echo "<?xml version='1.0'?>\n";
+ echo "<notifyResult success='false' msg='$msg' />\n";
+ }
+}
--- /dev/null
+<?php
+/**
+ * Action to let RSSCloud aggregators request update notification when
+ * user profile feeds change.
+ *
+ * PHP version 5
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Action class to handle RSSCloud notification (subscription) requests
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ */
+class RSSCloudRequestNotifyAction extends Action
+{
+ /**
+ * Initialization.
+ *
+ * @param array $args Web and URL arguments
+ *
+ * @return boolean false if user doesn't exist
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->ip = $_SERVER['REMOTE_ADDR'];
+ $this->port = $this->arg('port');
+ $this->path = $this->arg('path');
+
+ if ($this->path[0] != '/') {
+ $this->path = '/' . $this->path;
+ }
+
+ $this->protocol = $this->arg('protocol');
+ $this->procedure = $this->arg('notifyProcedure');
+ $this->domain = $this->arg('domain');
+
+ $this->feeds = $this->getFeeds();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Checks for all the required parameters for a subscription,
+ * validates that the feed being subscribed to is real, and then
+ * saves the subsctiption.
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ // TRANS: Form validation error displayed when POST is not used.
+ $this->showResult(false, _m('Request must be POST.'));
+ return;
+ }
+
+ $missing = array();
+
+ if (empty($this->port)) {
+ $missing[] = 'port';
+ }
+
+ if (empty($this->path)) {
+ $missing[] = 'path';
+ }
+
+ if (empty($this->protocol)) {
+ $missing[] = 'protocol';
+ } else if (strtolower($this->protocol) != 'http-post') {
+ // TRANS: Form validation error displayed when HTTP POST is not used.
+ $msg = _m('Only HTTP POST notifications are supported at this time.');
+ $this->showResult(false, $msg);
+ return;
+ }
+
+ if (!isset($this->procedure)) {
+ $missing[] = 'notifyProcedure';
+ }
+
+ if (!empty($missing)) {
+ // TRANS: List separator.
+ $separator = _m('SEPARATOR',', ');
+ // TRANS: Form validation error displayed when a request body is missing expected parameters.
+ // TRANS: %s is a list of parameters separated by a list separator (default: ", ").
+ $msg = sprintf(_m('The following parameters were missing from the request body: %s.'),implode($separator, $missing));
+ $this->showResult(false, $msg);
+ return;
+ }
+
+ if (empty($this->feeds)) {
+ // TRANS: Form validation error displayed when not providing any valid profile feed URLs.
+ $msg = _m('You must provide at least one valid profile feed URL ' .
+ '(url1, url2, url3 ... urlN).');
+ $this->showResult(false, $msg);
+ return;
+ }
+
+ // We have to validate everything before saving anything.
+ // We only return one success or failure no matter how
+ // many feeds the subscriber is trying to subscribe to
+ foreach ($this->feeds as $feed) {
+ if (!$this->validateFeed($feed)) {
+ $nh = $this->getNotifyUrl();
+ common_log(LOG_WARNING,
+ "RSSCloud plugin - $nh tried to subscribe to invalid feed: $feed");
+
+ // TRANS: Form validation error displayed when not providing a valid feed URL.
+ $msg = _m('Feed subscription failed: Not a valid feed.');
+ $this->showResult(false, $msg);
+ return;
+ }
+
+ if (!$this->testNotificationHandler($feed)) {
+ // TRANS: Form validation error displayed when feed subscription failed.
+ $msg = _m('Feed subscription failed: ' .
+ 'Notification handler does not respond correctly.');
+ $this->showResult(false, $msg);
+ return;
+ }
+ }
+
+ foreach ($this->feeds as $feed) {
+ $this->saveSubscription($feed);
+ }
+
+ // XXX: What to do about deleting stale subscriptions?
+ // 25 hours seems harsh. WordPress doesn't ever remove
+ // subscriptions.
+ // TRANS: Success message after subscribing to one or more feeds.
+ $msg = _m('Thanks for the subscription. ' .
+ 'When the feed(s) update(s), you will be notified.');
+
+ $this->showResult(true, $msg);
+ }
+
+ /**
+ * Validate that the requested feed is one we serve
+ * up via RSSCloud.
+ *
+ * @param string $feed the feed in question
+ *
+ * @return void
+ */
+ function validateFeed($feed)
+ {
+ $user = $this->userFromFeed($feed);
+
+ if (empty($user)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Pull all of the urls (url1, url2, url3...urlN) that
+ * the subscriber wants to subscribe to.
+ *
+ * @return array $feeds the list of feeds
+ */
+ function getFeeds()
+ {
+ $feeds = array();
+
+ while (list($key, $feed) = each($this->args)) {
+ if (preg_match('/^url\d*$/', $key)) {
+ $feeds[] = $feed;
+ }
+ }
+
+ return $feeds;
+ }
+
+ /**
+ * Test that a notification handler is there and is reponding
+ * correctly. This is called before adding a subscription.
+ *
+ * @param string $feed the feed to verify
+ *
+ * @return boolean success result
+ */
+ function testNotificationHandler($feed)
+ {
+ $notifyUrl = $this->getNotifyUrl();
+
+ $notifier = new RSSCloudNotifier();
+
+ if (isset($this->domain)) {
+ // 'domain' param set, so we have to use GET and send a challenge
+ common_log(LOG_INFO,
+ 'RSSCloud plugin - Testing notification handler with challenge: ' .
+ $notifyUrl);
+ return $notifier->challenge($notifyUrl, $feed);
+ } else {
+ common_log(LOG_INFO, 'RSSCloud plugin - Testing notification handler: ' .
+ $notifyUrl);
+
+ return $notifier->postUpdate($notifyUrl, $feed);
+ }
+ }
+
+ /**
+ * Build the URL for the notification handler based on the
+ * parameters passed in with the subscription request.
+ *
+ * @return string notification handler url
+ */
+ function getNotifyUrl()
+ {
+ if (isset($this->domain)) {
+ return 'http://' . $this->domain . ':' . $this->port . $this->path;
+ } else {
+ return 'http://' . $this->ip . ':' . $this->port . $this->path;
+ }
+ }
+
+ /**
+ * Uses the nickname part of the subscribed feed URL to figure out
+ * whethere there's really a user with such a feed. Used to
+ * validate feeds before adding a subscription.
+ *
+ * @param string $feed the feed in question
+ *
+ * @return boolean success
+ */
+ function userFromFeed($feed)
+ {
+ // We only do canonical RSS2 profile feeds (specified by ID), e.g.:
+ // http://www.example.com/api/statuses/user_timeline/2.rss
+ $path = common_path('api/statuses/user_timeline/');
+ $valid = '%^' . $path . '(?<id>.*)\.rss$%';
+
+ if (preg_match($valid, $feed, $matches)) {
+ $user = User::getKV('id', $matches['id']);
+ if (!empty($user)) {
+ return $user;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Save an RSSCloud subscription
+ *
+ * @param string $feed a valid profile feed
+ *
+ * @return boolean success result
+ */
+ function saveSubscription($feed)
+ {
+ $user = $this->userFromFeed($feed);
+
+ $notifyUrl = $this->getNotifyUrl();
+
+ $sub = RSSCloudSubscription::getSubscription($user->id, $notifyUrl);
+
+ if ($sub) {
+ common_log(LOG_INFO, "RSSCloud plugin - $notifyUrl refreshed subscription" .
+ " to user $user->nickname (id: $user->id).");
+ } else {
+ $sub = new RSSCloudSubscription();
+
+ $sub->subscribed = $user->id;
+ $sub->url = $notifyUrl;
+ $sub->created = common_sql_now();
+
+ if (!$sub->insert()) {
+ common_log_db_error($sub, 'INSERT', __FILE__);
+ return false;
+ }
+
+ common_log(LOG_INFO, "RSSCloud plugin - $notifyUrl subscribed" .
+ " to user $user->nickname (id: $user->id)");
+ }
+
+ return true;
+ }
+
+ /**
+ * Show an XML message indicating the subscription
+ * was successful or failed.
+ *
+ * @param boolean $success whether it was good or bad
+ * @param string $msg the message to output
+ *
+ * @return boolean success result
+ */
+ function showResult($success, $msg)
+ {
+ $this->startXML();
+ $this->elementStart('notifyResult',
+ array('success' => ($success) ? 'true' : 'false',
+ 'msg' => $msg));
+ $this->endXML();
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Table Definition for rsscloud_subscription
+ */
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+class RSSCloudSubscription extends Memcached_DataObject {
+
+ var $__table='rsscloud_subscription'; // table name
+ 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()
+ {
+
+ $db = $this->getDatabaseConnection();
+ $dbtype = $db->phptype;
+
+ $cols = array('subscribed' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'url' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'failures' => DB_DATAOBJECT_INT,
+ 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL,
+ 'modified' => ($dbtype == 'mysql' || $dbtype == 'mysqli') ?
+ DB_DATAOBJECT_MYSQLTIMESTAMP + DB_DATAOBJECT_NOTNULL :
+ DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME
+ );
+
+ return $cols;
+ }
+
+ function keys()
+ {
+ return array('subscribed' => 'N', 'url' => 'N');
+ }
+
+ static function getSubscription($subscribed, $url)
+ {
+ $sub = new RSSCloudSubscription();
+ $sub->whereAdd("subscribed = $subscribed");
+ $sub->whereAdd("url = '$url'");
+ $sub->limit(1);
+
+ if ($sub->find()) {
+ $sub->fetch();
+ return $sub;
+ }
+
+ return false;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Class to ping an rssCloud endpoint when a feed has been updated
+ *
+ * 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
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Class for notifying cloud-enabled RSS aggregators that StatusNet
+ * feeds have been updated.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ */
+class RSSCloudNotifier
+{
+ const MAX_FAILURES = 3;
+
+ /**
+ * Send an HTTP GET to the notification handler with a
+ * challenge string to see if it repsonds correctly.
+ *
+ * @param string $endpoint URL of the notification handler
+ * @param string $feed the feed being subscribed to
+ *
+ * @return boolean success
+ */
+ function challenge($endpoint, $feed)
+ {
+ $code = common_confirmation_code(128);
+ $params = array('url' => $feed, 'challenge' => $code);
+ $url = $endpoint . '?' . http_build_query($params);
+
+ try {
+ $client = new HTTPClient();
+ $response = $client->get($url);
+ } catch (HTTP_Request2_Exception $e) {
+ common_log(LOG_INFO,
+ 'RSSCloud plugin - failure testing notify handler ' .
+ $endpoint . ' - ' . $e->getMessage());
+ return false;
+ }
+
+ // Check response is betweet 200 and 299 and body contains challenge data
+
+ $status = $response->getStatus();
+ $body = $response->getBody();
+
+ if ($status >= 200 && $status < 300) {
+ // NOTE: the spec says that the body must contain the string
+ // challenge. It doesn't say that the body must contain the
+ // challenge string ONLY, although that seems to be the way
+ // the other implementors have interpreted it.
+
+ if (strpos($body, $code) !== false) {
+ common_log(LOG_INFO, 'RSSCloud plugin - ' .
+ "success testing notify handler: $endpoint");
+ return true;
+ } else {
+ common_log(LOG_INFO, 'RSSCloud plugin - ' .
+ 'challenge/repsonse failed for notify handler ' .
+ $endpoint);
+ common_debug('body = ' . var_export($body, true));
+ return false;
+ }
+ } else {
+ common_log(LOG_INFO, 'RSSCloud plugin - ' .
+ "failure testing notify handler: $endpoint " .
+ ' - got HTTP ' . $status);
+ common_debug('body = ' . var_export($body, true));
+ return false;
+ }
+ }
+
+ /**
+ * HTTP POST a notification that a feed has been updated
+ * ('ping the cloud').
+ *
+ * @param String $endpoint URL of the notification handler
+ * @param String $feed the feed being subscribed to
+ *
+ * @return boolean success
+ */
+ function postUpdate($endpoint, $feed)
+ {
+ $headers = array();
+ $postdata = array('url' => $feed);
+
+ try {
+ $client = new HTTPClient();
+ $response = $client->post($endpoint, $headers, $postdata);
+ } catch (HTTP_Request2_Exception $e) {
+ common_log(LOG_INFO, 'RSSCloud plugin - failure notifying ' .
+ $endpoint . ' that feed ' . $feed .
+ ' has changed: ' . $e->getMessage());
+ return false;
+ }
+
+ $status = $response->getStatus();
+
+ if ($status >= 200 && $status < 300) {
+ common_log(LOG_INFO, 'RSSCloud plugin - success notifying ' .
+ $endpoint . ' that feed ' . $feed . ' has changed.');
+ return true;
+ } else {
+ common_log(LOG_INFO, 'RSSCloud plugin - failure notifying ' .
+ $endpoint . ' that feed ' . $feed .
+ ' has changed: got HTTP ' . $status);
+ return false;
+ }
+ }
+
+ /**
+ * Notify all subscribers to a profile feed that it has changed.
+ *
+ * @param Profile $profile the profile whose feed has been
+ * updated
+ *
+ * @return boolean success
+ */
+ function notify($profile)
+ {
+ $feed = common_path('api/statuses/user_timeline/') .
+ $profile->id . '.rss';
+
+ $cloudSub = new RSSCloudSubscription();
+
+ $cloudSub->subscribed = $profile->id;
+
+ if ($cloudSub->find()) {
+ while ($cloudSub->fetch()) {
+ $result = $this->postUpdate($cloudSub->url, $feed);
+ if ($result == false) {
+ $this->handleFailure($cloudSub);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle problems posting cloud notifications. Increment the failure
+ * count, or delete the subscription if the maximum number of failures
+ * is exceeded.
+ *
+ * XXX: Redo with proper DB_DataObject methods once I figure out what
+ * what the problem is with pluginized DB_DataObjects. -Z
+ *
+ * @param RSSCloudSubscription $cloudSub the subscription in question
+ *
+ * @return boolean success
+ */
+ function handleFailure($cloudSub)
+ {
+ $failCnt = $cloudSub->failures + 1;
+
+ if ($failCnt == self::MAX_FAILURES) {
+
+ common_log(LOG_INFO,
+ 'Deleting RSSCloud subcription ' .
+ '(max failure count reached), profile: ' .
+ $cloudSub->subscribed .
+ ' handler: ' .
+ $cloudSub->url);
+
+ // XXX: WTF! ->delete() doesn't work. Clearly, there are some issues with
+ // the DB_DataObject, or my understanding of it. Have to drop into SQL.
+
+ // $result = $cloudSub->delete();
+
+ $qry = 'DELETE from rsscloud_subscription' .
+ ' WHERE subscribed = ' . $cloudSub->subscribed .
+ ' AND url = \'' . $cloudSub->url . '\'';
+
+ $result = $cloudSub->query($qry);
+
+ if (!$result) {
+ common_log_db_error($cloudSub, 'DELETE', __FILE__);
+ common_log(LOG_ERR, 'Could not delete RSSCloud subscription.');
+ }
+ } else {
+ common_debug('Updating failure count on RSSCloud subscription. ' .
+ $failCnt);
+
+ $failCnt = $cloudSub->failures + 1;
+
+ // XXX: ->update() not working either, gar!
+
+ $qry = 'UPDATE rsscloud_subscription' .
+ ' SET failures = ' . $failCnt .
+ ' WHERE subscribed = ' . $cloudSub->subscribed .
+ ' AND url = \'' . $cloudSub->url . '\'';
+
+ $result = $cloudSub->query($qry);
+
+ if (!$result) {
+ common_log_db_error($cloudsub, 'UPDATE', __FILE__);
+ common_log(LOG_ERR,
+ 'Could not update failure ' .
+ 'count on RSSCloud subscription');
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+class RSSCloudQueueHandler extends QueueHandler
+{
+ function transport()
+ {
+ return 'rsscloud';
+ }
+
+ function handle($notice)
+ {
+ try {
+ $profile = $notice->getProfile();
+ } catch (Exception $e) {
+ common_log(LOG_ERR, "Dropping RSSCloud item for notice with bogus profile: " . $e->getMessage());
+ return true;
+ }
+ $notifier = new RSSCloudNotifier();
+ return $notifier->notify($profile);
+ }
+}
return true;
}
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'KeepalivechannelAction':
- case 'ClosechannelAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'Realtime_channel':
- include_once $dir.'/'.$cls.'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Hook for RouterInitialized event.
*
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * A channel for real-time browser data
- *
- * PHP version 5
- *
- * 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 Realtime
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * A channel for real-time browser data
- *
- * For each user currently browsing the site, we want to know which page they're on
- * so we can send real-time updates to their browser.
- *
- * @category Realtime
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Realtime_channel extends Managed_DataObject
-{
- const TIMEOUT = 1800; // 30 minutes
-
- public $__table = 'realtime_channel'; // table name
-
- public $user_id; // int -> user.id, can be null
- public $action; // string
- public $arg1; // argument
- public $arg2; // argument, usually null
- public $channel_key; // 128-bit shared secret key
- public $audience; // listener count
- public $created; // created date
- public $modified; // modified date
-
- /**
- * The One True Thingy that must be defined and declared.
- */
- public static function schemaDef()
- {
- return array(
- 'description' => 'A channel of realtime notice data',
- 'fields' => array(
- 'user_id' => array('type' => 'int',
- 'not null' => false,
- 'description' => 'user viewing page; can be null'),
- 'action' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => true,
- 'description' => 'page being viewed'),
- 'arg1' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => false,
- 'description' => 'page argument, like username or tag'),
- 'arg2' => array('type' => 'varchar',
- 'length' => 255,
- 'not null' => false,
- 'description' => 'second page argument, like tag for showstream'),
- 'channel_key' => array('type' => 'varchar',
- 'length' => 32,
- 'not null' => true,
- 'description' => 'shared secret key for this channel'),
- 'audience' => array('type' => 'integer',
- 'not null' => true,
- 'default' => 0,
- 'description' => 'reference count'),
- 'created' => array('type' => 'datetime',
- 'not null' => true,
- 'description' => 'date this record was created'),
- 'modified' => array('type' => 'datetime',
- 'not null' => true,
- 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('channel_key'),
- 'unique keys' => array('realtime_channel_user_page_idx' => array('user_id', 'action', 'arg1', 'arg2')),
- 'foreign keys' => array(
- 'realtime_channel_user_id_fkey' => array('user', array('user_id' => 'id')),
- ),
- 'indexes' => array(
- 'realtime_channel_modified_idx' => array('modified'),
- 'realtime_channel_page_idx' => array('action', 'arg1', 'arg2')
- ),
- );
- }
-
- static function saveNew($user_id, $action, $arg1, $arg2)
- {
- $channel = new Realtime_channel();
-
- $channel->user_id = $user_id;
- $channel->action = $action;
- $channel->arg1 = $arg1;
- $channel->arg2 = $arg2;
- $channel->audience = 1;
-
- $channel->channel_key = common_good_rand(16); // 128-bit key, 32 hex chars
-
- $channel->created = common_sql_now();
- $channel->modified = $channel->created;
-
- $channel->insert();
-
- return $channel;
- }
-
- static function getChannel($user_id, $action, $arg1, $arg2)
- {
- $channel = self::fetchChannel($user_id, $action, $arg1, $arg2);
-
- // Ignore (and delete!) old channels
-
- if (!empty($channel)) {
- $modTime = strtotime($channel->modified);
- if ((time() - $modTime) > self::TIMEOUT) {
- $channel->delete();
- $channel = null;
- }
- }
-
- if (empty($channel)) {
- $channel = self::saveNew($user_id, $action, $arg1, $arg2);
- }
-
- return $channel;
- }
-
- static function getAllChannels($action, $arg1, $arg2)
- {
- $channel = new Realtime_channel();
-
- $channel->action = $action;
-
- if (is_null($arg1)) {
- $channel->whereAdd('arg1 is null');
- } else {
- $channel->arg1 = $arg1;
- }
-
- if (is_null($arg2)) {
- $channel->whereAdd('arg2 is null');
- } else {
- $channel->arg2 = $arg2;
- }
-
- $channel->whereAdd('modified > "' . common_sql_date(time() - self::TIMEOUT) . '"');
-
- $channels = array();
-
- if ($channel->find()) {
- $channels = $channel->fetchAll();
- }
-
- return $channels;
- }
-
- static function fetchChannel($user_id, $action, $arg1, $arg2)
- {
- $channel = new Realtime_channel();
-
- if (is_null($user_id)) {
- $channel->whereAdd('user_id is null');
- } else {
- $channel->user_id = $user_id;
- }
-
- $channel->action = $action;
-
- if (is_null($arg1)) {
- $channel->whereAdd('arg1 is null');
- } else {
- $channel->arg1 = $arg1;
- }
-
- if (is_null($arg2)) {
- $channel->whereAdd('arg2 is null');
- } else {
- $channel->arg2 = $arg2;
- }
-
- if ($channel->find(true)) {
- $channel->increment();
- return $channel;
- } else {
- return null;
- }
- }
-
- function increment()
- {
- // XXX: race
- $orig = clone($this);
- $this->audience++;
- $this->modified = common_sql_now();
- $this->update($orig);
- }
-
- function touch()
- {
- // XXX: race
- $orig = clone($this);
- $this->modified = common_sql_now();
- $this->update($orig);
- }
-
- function decrement()
- {
- // XXX: race
- if ($this->audience == 1) {
- $this->delete();
- } else {
- $orig = clone($this);
- $this->audience--;
- $this->modified = common_sql_now();
- $this->update($orig);
- }
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * action to close a channel
+ *
+ * PHP version 5
+ *
+ * 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 Realtime
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Action to close a channel
+ *
+ * @category Realtime
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ClosechannelAction extends Action
+{
+ protected $channelKey = null;
+ protected $channel = null;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ if (!$this->isPost()) {
+ // TRANS: Client exception. Do not translate POST.
+ throw new ClientException(_m('You have to POST it.'));
+ }
+
+ $this->channelKey = $this->trimmed('channelkey');
+
+ if (empty($this->channelKey)) {
+ // TRANS: Client exception thrown when the channel key argument is missing.
+ throw new ClientException(_m('No channel key argument.'));
+ }
+
+ $this->channel = Realtime_channel::getKV('channel_key', $this->channelKey);
+
+ if (empty($this->channel)) {
+ // TRANS: Client exception thrown when referring to a non-existing channel.
+ throw new ClientException(_m('No such channel.'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ $this->channel->decrement();
+
+ header('HTTP/1.1 204 No Content');
+
+ return;
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return false;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * action periodically pinged by a page to keep a channel alive
+ *
+ * PHP version 5
+ *
+ * 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 Realtime
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Action periodically pinged by a page to keep a channel alive
+ *
+ * @category Realtime
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class KeepalivechannelAction extends Action
+{
+ protected $channelKey = null;
+ protected $channel = null;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ if (!$this->isPost()) {
+ // TRANS: Client exception. Do not translate POST.
+ throw new ClientException(_m('You have to POST it.'));
+ }
+
+ $this->channelKey = $this->trimmed('channelkey');
+
+ if (empty($this->channelKey)) {
+ // TRANS: Client exception thrown when the channel key argument is missing.
+ throw new ClientException(_m('No channel key argument.'));
+ }
+
+ $this->channel = Realtime_channel::getKV('channel_key', $this->channelKey);
+
+ if (empty($this->channel)) {
+ // TRANS: Client exception thrown when referring to a non-existing channel.
+ throw new ClientException(_m('No such channel.'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ $this->channel->touch();
+
+ header('HTTP/1.1 204 No Content');
+
+ return;
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * MAY override
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return false;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * A channel for real-time browser data
+ *
+ * PHP version 5
+ *
+ * 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 Realtime
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * A channel for real-time browser data
+ *
+ * For each user currently browsing the site, we want to know which page they're on
+ * so we can send real-time updates to their browser.
+ *
+ * @category Realtime
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Realtime_channel extends Managed_DataObject
+{
+ const TIMEOUT = 1800; // 30 minutes
+
+ public $__table = 'realtime_channel'; // table name
+
+ public $user_id; // int -> user.id, can be null
+ public $action; // string
+ public $arg1; // argument
+ public $arg2; // argument, usually null
+ public $channel_key; // 128-bit shared secret key
+ public $audience; // listener count
+ public $created; // created date
+ public $modified; // modified date
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'A channel of realtime notice data',
+ 'fields' => array(
+ 'user_id' => array('type' => 'int',
+ 'not null' => false,
+ 'description' => 'user viewing page; can be null'),
+ 'action' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true,
+ 'description' => 'page being viewed'),
+ 'arg1' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => false,
+ 'description' => 'page argument, like username or tag'),
+ 'arg2' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => false,
+ 'description' => 'second page argument, like tag for showstream'),
+ 'channel_key' => array('type' => 'varchar',
+ 'length' => 32,
+ 'not null' => true,
+ 'description' => 'shared secret key for this channel'),
+ 'audience' => array('type' => 'integer',
+ 'not null' => true,
+ 'default' => 0,
+ 'description' => 'reference count'),
+ 'created' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('channel_key'),
+ 'unique keys' => array('realtime_channel_user_page_idx' => array('user_id', 'action', 'arg1', 'arg2')),
+ 'foreign keys' => array(
+ 'realtime_channel_user_id_fkey' => array('user', array('user_id' => 'id')),
+ ),
+ 'indexes' => array(
+ 'realtime_channel_modified_idx' => array('modified'),
+ 'realtime_channel_page_idx' => array('action', 'arg1', 'arg2')
+ ),
+ );
+ }
+
+ static function saveNew($user_id, $action, $arg1, $arg2)
+ {
+ $channel = new Realtime_channel();
+
+ $channel->user_id = $user_id;
+ $channel->action = $action;
+ $channel->arg1 = $arg1;
+ $channel->arg2 = $arg2;
+ $channel->audience = 1;
+
+ $channel->channel_key = common_good_rand(16); // 128-bit key, 32 hex chars
+
+ $channel->created = common_sql_now();
+ $channel->modified = $channel->created;
+
+ $channel->insert();
+
+ return $channel;
+ }
+
+ static function getChannel($user_id, $action, $arg1, $arg2)
+ {
+ $channel = self::fetchChannel($user_id, $action, $arg1, $arg2);
+
+ // Ignore (and delete!) old channels
+
+ if (!empty($channel)) {
+ $modTime = strtotime($channel->modified);
+ if ((time() - $modTime) > self::TIMEOUT) {
+ $channel->delete();
+ $channel = null;
+ }
+ }
+
+ if (empty($channel)) {
+ $channel = self::saveNew($user_id, $action, $arg1, $arg2);
+ }
+
+ return $channel;
+ }
+
+ static function getAllChannels($action, $arg1, $arg2)
+ {
+ $channel = new Realtime_channel();
+
+ $channel->action = $action;
+
+ if (is_null($arg1)) {
+ $channel->whereAdd('arg1 is null');
+ } else {
+ $channel->arg1 = $arg1;
+ }
+
+ if (is_null($arg2)) {
+ $channel->whereAdd('arg2 is null');
+ } else {
+ $channel->arg2 = $arg2;
+ }
+
+ $channel->whereAdd('modified > "' . common_sql_date(time() - self::TIMEOUT) . '"');
+
+ $channels = array();
+
+ if ($channel->find()) {
+ $channels = $channel->fetchAll();
+ }
+
+ return $channels;
+ }
+
+ static function fetchChannel($user_id, $action, $arg1, $arg2)
+ {
+ $channel = new Realtime_channel();
+
+ if (is_null($user_id)) {
+ $channel->whereAdd('user_id is null');
+ } else {
+ $channel->user_id = $user_id;
+ }
+
+ $channel->action = $action;
+
+ if (is_null($arg1)) {
+ $channel->whereAdd('arg1 is null');
+ } else {
+ $channel->arg1 = $arg1;
+ }
+
+ if (is_null($arg2)) {
+ $channel->whereAdd('arg2 is null');
+ } else {
+ $channel->arg2 = $arg2;
+ }
+
+ if ($channel->find(true)) {
+ $channel->increment();
+ return $channel;
+ } else {
+ return null;
+ }
+ }
+
+ function increment()
+ {
+ // XXX: race
+ $orig = clone($this);
+ $this->audience++;
+ $this->modified = common_sql_now();
+ $this->update($orig);
+ }
+
+ function touch()
+ {
+ // XXX: race
+ $orig = clone($this);
+ $this->modified = common_sql_now();
+ $this->update($orig);
+ }
+
+ function decrement()
+ {
+ // XXX: race
+ if ($this->audience == 1) {
+ $this->delete();
+ } else {
+ $orig = clone($this);
+ $this->audience--;
+ $this->modified = common_sql_now();
+ $this->update($orig);
+ }
+ }
+}
+++ /dev/null
-#!/usr/bin/env php
-<?php
-/*
- * StatusNet - a distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Script to print out current version of the software
- *
- * 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/>.
- */
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
-
-$shortoptions = 'u';
-$longoptions = array('universe');
-
-$helptext = <<<END_OF_CLEANUPCHANNELS_HELP
-cleanupchannels.php [options]
-Garbage-collects old realtime channels
-
--u --universe Do all sites
-
-END_OF_CLEANUPCHANNELS_HELP;
-
-require_once INSTALLDIR.'/scripts/commandline.inc';
-
-function cleanupChannels()
-{
- $rc = new Realtime_channel();
-
- $rc->selectAdd();
- $rc->selectAdd('channel_key');
-
- $rc->whereAdd('modified < "' . common_sql_date(time() - Realtime_channel::TIMEOUT) . '"');
-
- if ($rc->find()) {
- $keys = $rc->fetchAll();
-
- foreach ($keys as $key) {
- $rc = Realtime_channel::getKV('channel_key', $key);
- if (!empty($rc)) {
- printfv("Deleting realtime channel '$key'\n");
- $rc->delete();
- }
- }
- }
-}
-
-if (have_option('u', 'universe')) {
- $sn = new Status_network();
- if ($sn->find()) {
- while ($sn->fetch()) {
- $server = $sn->getServerName();
- StatusNet::init($server);
- cleanupChannels();
- }
- }
-} else {
- cleanupChannels();
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * action to close a channel
- *
- * PHP version 5
- *
- * 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 Realtime
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Action to close a channel
- *
- * @category Realtime
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ClosechannelAction extends Action
-{
- protected $channelKey = null;
- protected $channel = null;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- if (!$this->isPost()) {
- // TRANS: Client exception. Do not translate POST.
- throw new ClientException(_m('You have to POST it.'));
- }
-
- $this->channelKey = $this->trimmed('channelkey');
-
- if (empty($this->channelKey)) {
- // TRANS: Client exception thrown when the channel key argument is missing.
- throw new ClientException(_m('No channel key argument.'));
- }
-
- $this->channel = Realtime_channel::getKV('channel_key', $this->channelKey);
-
- if (empty($this->channel)) {
- // TRANS: Client exception thrown when referring to a non-existing channel.
- throw new ClientException(_m('No such channel.'));
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- $this->channel->decrement();
-
- header('HTTP/1.1 204 No Content');
-
- return;
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return false;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * action periodically pinged by a page to keep a channel alive
- *
- * PHP version 5
- *
- * 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 Realtime
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Action periodically pinged by a page to keep a channel alive
- *
- * @category Realtime
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class KeepalivechannelAction extends Action
-{
- protected $channelKey = null;
- protected $channel = null;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
-
- if (!$this->isPost()) {
- // TRANS: Client exception. Do not translate POST.
- throw new ClientException(_m('You have to POST it.'));
- }
-
- $this->channelKey = $this->trimmed('channelkey');
-
- if (empty($this->channelKey)) {
- // TRANS: Client exception thrown when the channel key argument is missing.
- throw new ClientException(_m('No channel key argument.'));
- }
-
- $this->channel = Realtime_channel::getKV('channel_key', $this->channelKey);
-
- if (empty($this->channel)) {
- // TRANS: Client exception thrown when referring to a non-existing channel.
- throw new ClientException(_m('No such channel.'));
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- $this->channel->touch();
-
- header('HTTP/1.1 204 No Content');
-
- return;
- }
-
- /**
- * Return true if read only.
- *
- * MAY override
- *
- * @param array $args other arguments
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return false;
- }
-}
--- /dev/null
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Script to print out current version of the software
+ *
+ * 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/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
+
+$shortoptions = 'u';
+$longoptions = array('universe');
+
+$helptext = <<<END_OF_CLEANUPCHANNELS_HELP
+cleanupchannels.php [options]
+Garbage-collects old realtime channels
+
+-u --universe Do all sites
+
+END_OF_CLEANUPCHANNELS_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+function cleanupChannels()
+{
+ $rc = new Realtime_channel();
+
+ $rc->selectAdd();
+ $rc->selectAdd('channel_key');
+
+ $rc->whereAdd('modified < "' . common_sql_date(time() - Realtime_channel::TIMEOUT) . '"');
+
+ if ($rc->find()) {
+ $keys = $rc->fetchAll();
+
+ foreach ($keys as $key) {
+ $rc = Realtime_channel::getKV('channel_key', $key);
+ if (!empty($rc)) {
+ printfv("Deleting realtime channel '$key'\n");
+ $rc->delete();
+ }
+ }
+ }
+}
+
+if (have_option('u', 'universe')) {
+ $sn = new Status_network();
+ if ($sn->find()) {
+ while ($sn->fetch()) {
+ $server = $sn->getServerName();
+ StatusNet::init($server);
+ cleanupChannels();
+ }
+ }
+} else {
+ cleanupChannels();
+}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'Registration_ip':
- include_once $dir . '/'.$cls.'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Called when someone tries to register.
*
+++ /dev/null
-<?php
-/**
- * Data class for storing IP addresses of new registrants.
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for storing IP addresses of new registrants.
- *
- * @category Spam
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class Registration_ip extends Managed_DataObject
-{
- public $__table = 'registration_ip'; // table name
- public $user_id; // int(4) primary_key not_null
- public $ipaddress; // varchar(15)
- public $created; // datetime() not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id this registration relates to'),
- 'ipaddress' => array('type' => 'varchar', 'length' => 45, 'description' => 'IP address, max 45+null in IPv6'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('user_id'),
- 'foreign keys' => array(
- 'registration_ip_user_id_fkey' => array('user', array('user_id' => 'id')),
- ),
- 'indexes' => array(
- 'registration_ip_ipaddress_idx' => array('ipaddress'),
- 'registration_ip_created_idx' => array('created'),
- ),
- );
- }
-
- /**
- * Get the users who've registered with this ip address.
- *
- * @param Array $ipaddress IP address to check for
- *
- * @return Array IDs of users who registered with this address.
- */
- static function usersByIP($ipaddress)
- {
- $ids = array();
-
- $ri = new Registration_ip();
- $ri->ipaddress = $ipaddress;
-
- if ($ri->find()) {
- while ($ri->fetch()) {
- $ids[] = $ri->user_id;
- }
- }
-
- return $ids;
- }
-}
--- /dev/null
+<?php
+/**
+ * Data class for storing IP addresses of new registrants.
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for storing IP addresses of new registrants.
+ *
+ * @category Spam
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class Registration_ip extends Managed_DataObject
+{
+ public $__table = 'registration_ip'; // table name
+ public $user_id; // int(4) primary_key not_null
+ public $ipaddress; // varchar(15)
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id this registration relates to'),
+ 'ipaddress' => array('type' => 'varchar', 'length' => 45, 'description' => 'IP address, max 45+null in IPv6'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('user_id'),
+ 'foreign keys' => array(
+ 'registration_ip_user_id_fkey' => array('user', array('user_id' => 'id')),
+ ),
+ 'indexes' => array(
+ 'registration_ip_ipaddress_idx' => array('ipaddress'),
+ 'registration_ip_created_idx' => array('created'),
+ ),
+ );
+ }
+
+ /**
+ * Get the users who've registered with this ip address.
+ *
+ * @param Array $ipaddress IP address to check for
+ *
+ * @return Array IDs of users who registered with this address.
+ */
+ static function usersByIP($ipaddress)
+ {
+ $ids = array();
+
+ $ri = new Registration_ip();
+ $ri->ipaddress = $ipaddress;
+
+ if ($ri->find()) {
+ while ($ri->fetch()) {
+ $ids[] = $ri->user_id;
+ }
+ }
+
+ return $ids;
+ }
+}
*/
public $disallowLogin = false;
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'ConfirmfirstemailAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- default:
- return true;
- }
- }
-
function onRouterInitialized($m)
{
$m->connect('main/confirmfirst/:code',
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Action for confirming first email registration
+ *
+ * PHP version 5
+ *
+ * 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 Confirmation
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Class comment
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class ConfirmfirstemailAction extends Action
+{
+ public $confirm;
+ public $code;
+ public $password;
+ public $user;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+ $user = common_current_user();
+
+ if (!empty($user)) {
+ // TRANS: Client exception thrown when trying to register while already logged in.
+ throw new ClientException(_m('You are already logged in.'));
+ }
+
+ $this->code = $this->trimmed('code');
+
+ $this->confirm = Confirm_address::getKV('code', $this->code);
+
+ if (empty($this->confirm)) {
+ // TRANS: Client exception thrown when trying to register with a non-existing confirmation code.
+ throw new ClientException(_m('Confirmation code not found.'));
+ return;
+ }
+
+ $this->user = User::getKV('id', $this->confirm->user_id);
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown when trying to register with a confirmation code that is not connected with a user.
+ throw new ServerException(_m('No user for that confirmation code.'));
+ }
+
+ $type = $this->confirm->address_type;
+
+ if ($type != 'email') {
+ // TRANS: Client exception thrown when trying to register with a invalid e-mail address.
+ // TRANS: %s is the invalid e-mail address.
+ throw new ServerException(sprintf(_m('Unrecognized address type %s.'), $type));
+ }
+
+ if (!empty($this->user->email) && $this->user->email == $confirm->address) {
+ // TRANS: Client error for an already confirmed email/jabber/sms address.
+ throw new ClientException(_m('That address has already been confirmed.'));
+ }
+
+ if ($this->isPost()) {
+
+ $this->checkSessionToken();
+
+ $password = $this->trimmed('password');
+ $confirm = $this->trimmed('confirm');
+
+ if (strlen($password) < 6) {
+ // TRANS: Client exception thrown when trying to register with too short a password.
+ throw new ClientException(_m('Password too short.'));
+ return;
+ } else if (0 != strcmp($password, $confirm)) {
+ // TRANS: Client exception thrown when trying to register without providing the same password twice.
+ throw new ClientException(_m('Passwords do not match.'));
+ return;
+ }
+
+ $this->password = $password;
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+ function handle($argarray=null)
+ {
+ $homepage = common_local_url('all',
+ array('nickname' => $this->user->nickname));
+
+ if ($this->isPost()) {
+ $this->confirmUser();
+ common_set_user($this->user);
+ common_real_login(true);
+ common_redirect($homepage, 303);
+ } else {
+ $this->showPage();
+ }
+ return;
+ }
+
+ function confirmUser()
+ {
+ $orig = clone($this->user);
+
+ $this->user->email = $this->confirm->address;
+
+ $this->user->updateKeys($orig);
+
+ $this->user->emailChanged();
+
+ $orig = clone($this->user);
+
+ $this->user->password = common_munge_password($this->password, $this->user->id);
+
+ $this->user->update($orig);
+
+ $this->confirm->delete();
+ }
+
+ function showContent()
+ {
+ $this->element('p', 'instructions',
+ // TRANS: Form instructions. %s is the nickname of the to be registered user.
+ sprintf(_m('You have confirmed the email address for your new user account %s. '.
+ 'Use the form below to set your new password.'),
+ $this->user->nickname));
+
+ $form = new ConfirmFirstEmailForm($this, $this->code);
+ $form->show();
+ }
+
+ function title()
+ {
+ // TRANS: Page title.
+ return _m('Set a password');
+ }
+}
+
+class ConfirmFirstEmailForm extends Form
+{
+ public $code;
+
+ function __construct($out, $code)
+ {
+ parent::__construct($out);
+ $this->code = $code;
+ }
+
+ function formLegend()
+ {
+ // TRANS: Form legend.
+ return _m('Confirm email address');
+ }
+
+ function action()
+ {
+ return common_local_url('confirmfirstemail',
+ array('code' => $this->code));
+ }
+
+ function formClass()
+ {
+ return 'form_settings';
+ }
+
+ function formData()
+ {
+ $this->out->elementStart('ul', 'form_data');
+ $this->out->elementStart('li');
+ // TRANS: Field label.
+ $this->out->password('password', _m('New password'),
+ // TRANS: Field title for password field.
+ _m('6 or more characters.'));
+ $this->out->elementEnd('li');
+ $this->out->elementStart('li');
+ // TRANS: Field label for repeat password field.
+ $this->out->password('confirm', _m('LABEL','Confirm'),
+ // TRANS: Field title for repeat password field.
+ _m('Same as password above.'));
+ $this->out->elementEnd('li');
+ $this->out->elementEnd('ul');
+ }
+
+ function formActions()
+ {
+ // TRANS: Button text for completing registration by e-mail.
+ $this->out->submit('save', _m('BUTTON','Save'));
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Action for confirming first email registration
- *
- * PHP version 5
- *
- * 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 Confirmation
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Class comment
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class ConfirmfirstemailAction extends Action
-{
- public $confirm;
- public $code;
- public $password;
- public $user;
-
- /**
- * For initializing members of the class.
- *
- * @param array $argarray misc. arguments
- *
- * @return boolean true
- */
- function prepare($argarray)
- {
- parent::prepare($argarray);
- $user = common_current_user();
-
- if (!empty($user)) {
- // TRANS: Client exception thrown when trying to register while already logged in.
- throw new ClientException(_m('You are already logged in.'));
- }
-
- $this->code = $this->trimmed('code');
-
- $this->confirm = Confirm_address::getKV('code', $this->code);
-
- if (empty($this->confirm)) {
- // TRANS: Client exception thrown when trying to register with a non-existing confirmation code.
- throw new ClientException(_m('Confirmation code not found.'));
- return;
- }
-
- $this->user = User::getKV('id', $this->confirm->user_id);
-
- if (empty($this->user)) {
- // TRANS: Client exception thrown when trying to register with a confirmation code that is not connected with a user.
- throw new ServerException(_m('No user for that confirmation code.'));
- }
-
- $type = $this->confirm->address_type;
-
- if ($type != 'email') {
- // TRANS: Client exception thrown when trying to register with a invalid e-mail address.
- // TRANS: %s is the invalid e-mail address.
- throw new ServerException(sprintf(_m('Unrecognized address type %s.'), $type));
- }
-
- if (!empty($this->user->email) && $this->user->email == $confirm->address) {
- // TRANS: Client error for an already confirmed email/jabber/sms address.
- throw new ClientException(_m('That address has already been confirmed.'));
- }
-
- if ($this->isPost()) {
-
- $this->checkSessionToken();
-
- $password = $this->trimmed('password');
- $confirm = $this->trimmed('confirm');
-
- if (strlen($password) < 6) {
- // TRANS: Client exception thrown when trying to register with too short a password.
- throw new ClientException(_m('Password too short.'));
- return;
- } else if (0 != strcmp($password, $confirm)) {
- // TRANS: Client exception thrown when trying to register without providing the same password twice.
- throw new ClientException(_m('Passwords do not match.'));
- return;
- }
-
- $this->password = $password;
- }
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $argarray is ignored since it's now passed in in prepare()
- *
- * @return void
- */
- function handle($argarray=null)
- {
- $homepage = common_local_url('all',
- array('nickname' => $this->user->nickname));
-
- if ($this->isPost()) {
- $this->confirmUser();
- common_set_user($this->user);
- common_real_login(true);
- common_redirect($homepage, 303);
- } else {
- $this->showPage();
- }
- return;
- }
-
- function confirmUser()
- {
- $orig = clone($this->user);
-
- $this->user->email = $this->confirm->address;
-
- $this->user->updateKeys($orig);
-
- $this->user->emailChanged();
-
- $orig = clone($this->user);
-
- $this->user->password = common_munge_password($this->password, $this->user->id);
-
- $this->user->update($orig);
-
- $this->confirm->delete();
- }
-
- function showContent()
- {
- $this->element('p', 'instructions',
- // TRANS: Form instructions. %s is the nickname of the to be registered user.
- sprintf(_m('You have confirmed the email address for your new user account %s. '.
- 'Use the form below to set your new password.'),
- $this->user->nickname));
-
- $form = new ConfirmFirstEmailForm($this, $this->code);
- $form->show();
- }
-
- function title()
- {
- // TRANS: Page title.
- return _m('Set a password');
- }
-}
-
-class ConfirmFirstEmailForm extends Form
-{
- public $code;
-
- function __construct($out, $code)
- {
- parent::__construct($out);
- $this->code = $code;
- }
-
- function formLegend()
- {
- // TRANS: Form legend.
- return _m('Confirm email address');
- }
-
- function action()
- {
- return common_local_url('confirmfirstemail',
- array('code' => $this->code));
- }
-
- function formClass()
- {
- return 'form_settings';
- }
-
- function formData()
- {
- $this->out->elementStart('ul', 'form_data');
- $this->out->elementStart('li');
- // TRANS: Field label.
- $this->out->password('password', _m('New password'),
- // TRANS: Field title for password field.
- _m('6 or more characters.'));
- $this->out->elementEnd('li');
- $this->out->elementStart('li');
- // TRANS: Field label for repeat password field.
- $this->out->password('confirm', _m('LABEL','Confirm'),
- // TRANS: Field title for repeat password field.
- _m('Same as password above.'));
- $this->out->elementEnd('li');
- $this->out->elementEnd('ul');
- }
-
- function formActions()
- {
- // TRANS: Button text for completing registration by e-mail.
- $this->out->submit('save', _m('BUTTON','Save'));
- }
-}
+++ /dev/null
-#!/usr/bin/env php
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
-
-$shortoptions = "e:";
-
-$helptext = <<<END_OF_REGISTERBYEMAIL_HELP
-USAGE: registerbyemail.php
-Registers a new user by email address and sends a confirmation email
-
- -e email Email to register
-
-END_OF_REGISTERBYEMAIL_HELP;
-
-require_once INSTALLDIR.'/scripts/commandline.inc';
-
-$email = get_option_value('e', 'email');
-
-$parts = explode('@', $email);
-$nickname = common_nicknamize($parts[0]);
-
-$user = User::getKV('nickname', $nickname);
-
-if (!empty($user)) {
- $confirm = new Confirm_address();
-
- $confirm->user_id = $user->id;
- $confirm->address_type = 'email';
-
- if ($confirm->find(true)) {
- $url = common_local_url('confirmfirstemail',
- array('code' => $confirm->code));
-
- print "$url\n";
- } else {
- print "User not waiting for confirmation.\n";
- }
-
- exit;
-}
-
-$user = User::register(array('nickname' => $nickname,
- 'password' => null));
-
-$confirm = new Confirm_address();
-$confirm->code = common_confirmation_code(128);
-$confirm->user_id = $user->id;
-$confirm->address = $email;
-$confirm->address_type = 'email';
-
-$confirm->insert();
-
-$url = common_local_url('confirmfirstemail',
- array('code' => $confirm->code));
-
-print "$url\n";
-
-mail_confirm_address($user,
- $confirm->code,
- $user->nickname,
- $email,
- $url);
--- /dev/null
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..'));
+
+$shortoptions = "e:";
+
+$helptext = <<<END_OF_REGISTERBYEMAIL_HELP
+USAGE: registerbyemail.php
+Registers a new user by email address and sends a confirmation email
+
+ -e email Email to register
+
+END_OF_REGISTERBYEMAIL_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+$email = get_option_value('e', 'email');
+
+$parts = explode('@', $email);
+$nickname = common_nicknamize($parts[0]);
+
+$user = User::getKV('nickname', $nickname);
+
+if (!empty($user)) {
+ $confirm = new Confirm_address();
+
+ $confirm->user_id = $user->id;
+ $confirm->address_type = 'email';
+
+ if ($confirm->find(true)) {
+ $url = common_local_url('confirmfirstemail',
+ array('code' => $confirm->code));
+
+ print "$url\n";
+ } else {
+ print "User not waiting for confirmation.\n";
+ }
+
+ exit;
+}
+
+$user = User::register(array('nickname' => $nickname,
+ 'password' => null));
+
+$confirm = new Confirm_address();
+$confirm->code = common_confirmation_code(128);
+$confirm->user_id = $user->id;
+$confirm->address = $email;
+$confirm->address_type = 'email';
+
+$confirm->insert();
+
+$url = common_local_url('confirmfirstemail',
+ array('code' => $confirm->code));
+
+print "$url\n";
+
+mail_confirm_address($user,
+ $confirm->code,
+ $user->nickname,
+ $email,
+ $url);
return true;
}
- /**
- * Load related modules when needed
- *
- * Most non-trivial plugins will require extra modules to do their work. Typically
- * these include data classes, action classes, widget classes, or external libraries.
- *
- * This method receives a class name and loads the PHP file related to that class. By
- * tradition, action classes typically have files named for the action, all lower-case.
- * Data classes are in files with the data class name, initial letter capitalized.
- *
- * Note that this method will be called for *all* overloaded classes, not just ones
- * in this plugin! So, make sure to return true by default to let other plugins, and
- * the core code, get a chance.
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'HelloAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'User_greeting_count':
- include_once $dir . '/'.$cls.'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Map URLs to actions
*
+++ /dev/null
-<?php
-/**
- * Data class for counting greetings
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for counting greetings
- *
- * We use the DB_DataObject framework for data classes in StatusNet. Each
- * table maps to a particular data class, making it easier to manipulate
- * data.
- *
- * Data classes should extend Memcached_DataObject, the (slightly misnamed)
- * extension of DB_DataObject that provides caching, internationalization,
- * and other bits of good functionality to StatusNet-specific data classes.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class User_greeting_count extends Managed_DataObject
-{
- public $__table = 'user_greeting_count'; // table name
- public $user_id; // int(4) primary_key not_null
- public $greeting_count; // int(4)
- public $created; // datetime() not_null
- public $modified; // datetime not_null default_0000-00-00%2000%3A00%3A00
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
- 'greeting_count' => array('type' => 'int', 'not null' => true, 'description' => 'the greeting count'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('user_id'),
- 'foreign keys' => array(
- 'user_greeting_count_user_id_fkey' => array('user', array('user_id' => 'id')),
- ),
- );
- }
-
- /**
- * Increment a user's greeting count and return instance
- *
- * This method handles the ins and outs of creating a new greeting_count for a
- * user or fetching the existing greeting count and incrementing its value.
- *
- * @param integer $user_id ID of the user to get a count for
- *
- * @return User_greeting_count instance for this user, with count already incremented.
- */
- static function inc($user_id)
- {
- $gc = User_greeting_count::getKV('user_id', $user_id);
-
- if (empty($gc)) {
- $gc = new User_greeting_count();
-
- $gc->user_id = $user_id;
- $gc->greeting_count = 1;
-
- $result = $gc->insert();
-
- if (!$result) {
- // TRANS: Exception thrown when the user greeting count could not be saved in the database.
- // TRANS: %d is a user ID (number).
- throw Exception(sprintf(_m('Could not save new greeting count for %d.'),
- $user_id));
- }
- } else {
- $orig = clone($gc);
-
- $gc->greeting_count++;
-
- $result = $gc->update($orig);
-
- if (!$result) {
- // TRANS: Exception thrown when the user greeting count could not be saved in the database.
- // TRANS: %d is a user ID (number).
- throw Exception(sprintf(_m('Could not increment greeting count for %d.'),
- $user_id));
- }
- }
-
- return $gc;
- }
-}
--- /dev/null
+<?php
+/**
+ * Give a warm greeting to our friendly user
+ *
+ * PHP version 5
+ *
+ * @category Sample
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Give a warm greeting to our friendly user
+ *
+ * This sample action shows some basic ways of doing output in an action
+ * class.
+ *
+ * Action classes have several output methods that they override from
+ * the parent class.
+ *
+ * @category Sample
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class HelloAction extends Action
+{
+ var $user = null;
+ var $gc = null;
+
+ /**
+ * Take arguments for running
+ *
+ * This method is called first, and it lets the action class get
+ * all its arguments and validate them. It's also the time
+ * to fetch any relevant data from the database.
+ *
+ * Action classes should run parent::prepare($args) as the first
+ * line of this method to make sure the default argument-processing
+ * happens.
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = common_current_user();
+
+ if (!empty($this->user)) {
+ $this->gc = User_greeting_count::inc($this->user->id);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle request
+ *
+ * This is the main method for handling a request. Note that
+ * most preparation should be done in the prepare() method;
+ * by the time handle() is called the action should be
+ * more or less ready to go.
+ *
+ * @param array $args $_REQUEST args; handled in prepare()
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ $this->showPage();
+ }
+
+ /**
+ * Title of this page
+ *
+ * Override this method to show a custom title.
+ *
+ * @return string Title of the page
+ */
+ function title()
+ {
+ if (empty($this->user)) {
+ // TRANS: Page title for sample plugin.
+ return _m('Hello');
+ } else {
+ // TRANS: Page title for sample plugin. %s is a user nickname.
+ return sprintf(_m('Hello, %s!'), $this->user->nickname);
+ }
+ }
+
+ /**
+ * Show content in the content area
+ *
+ * The default StatusNet page has a lot of decorations: menus,
+ * logos, tabs, all that jazz. This method is used to show
+ * content in the content area of the page; it's the main
+ * thing you want to overload.
+ *
+ * This method also demonstrates use of a plural localized string.
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ if (empty($this->user)) {
+ $this->element('p', array('class' => 'greeting'),
+ // TRANS: Message in sample plugin.
+ _m('Hello, stranger!'));
+ } else {
+ $this->element('p', array('class' => 'greeting'),
+ // TRANS: Message in sample plugin. %s is a user nickname.
+ sprintf(_m('Hello, %s'), $this->user->nickname));
+ $this->element('p', array('class' => 'greeting_count'),
+ // TRANS: Message in sample plugin.
+ // TRANS: %d is the number of times a user is greeted.
+ sprintf(_m('I have greeted you %d time.',
+ 'I have greeted you %d times.',
+ $this->gc->greeting_count),
+ $this->gc->greeting_count));
+ }
+ }
+
+ /**
+ * Return true if read only.
+ *
+ * Some actions only read from the database; others read and write.
+ * The simple database load-balancer built into StatusNet will
+ * direct read-only actions to database mirrors (if they are configured),
+ * and read-write actions to the master database.
+ *
+ * This defaults to false to avoid data integrity issues, but you
+ * should make sure to overload it for performance gains.
+ *
+ * @param array $args other arguments, if RO/RW status depends on them.
+ *
+ * @return boolean is read only action?
+ */
+ function isReadOnly($args)
+ {
+ return false;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class for counting greetings
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for counting greetings
+ *
+ * We use the DB_DataObject framework for data classes in StatusNet. Each
+ * table maps to a particular data class, making it easier to manipulate
+ * data.
+ *
+ * Data classes should extend Memcached_DataObject, the (slightly misnamed)
+ * extension of DB_DataObject that provides caching, internationalization,
+ * and other bits of good functionality to StatusNet-specific data classes.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class User_greeting_count extends Managed_DataObject
+{
+ public $__table = 'user_greeting_count'; // table name
+ public $user_id; // int(4) primary_key not_null
+ public $greeting_count; // int(4)
+ public $created; // datetime() not_null
+ public $modified; // datetime not_null default_0000-00-00%2000%3A00%3A00
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id'),
+ 'greeting_count' => array('type' => 'int', 'not null' => true, 'description' => 'the greeting count'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('user_id'),
+ 'foreign keys' => array(
+ 'user_greeting_count_user_id_fkey' => array('user', array('user_id' => 'id')),
+ ),
+ );
+ }
+
+ /**
+ * Increment a user's greeting count and return instance
+ *
+ * This method handles the ins and outs of creating a new greeting_count for a
+ * user or fetching the existing greeting count and incrementing its value.
+ *
+ * @param integer $user_id ID of the user to get a count for
+ *
+ * @return User_greeting_count instance for this user, with count already incremented.
+ */
+ static function inc($user_id)
+ {
+ $gc = User_greeting_count::getKV('user_id', $user_id);
+
+ if (empty($gc)) {
+ $gc = new User_greeting_count();
+
+ $gc->user_id = $user_id;
+ $gc->greeting_count = 1;
+
+ $result = $gc->insert();
+
+ if (!$result) {
+ // TRANS: Exception thrown when the user greeting count could not be saved in the database.
+ // TRANS: %d is a user ID (number).
+ throw Exception(sprintf(_m('Could not save new greeting count for %d.'),
+ $user_id));
+ }
+ } else {
+ $orig = clone($gc);
+
+ $gc->greeting_count++;
+
+ $result = $gc->update($orig);
+
+ if (!$result) {
+ // TRANS: Exception thrown when the user greeting count could not be saved in the database.
+ // TRANS: %d is a user ID (number).
+ throw Exception(sprintf(_m('Could not increment greeting count for %d.'),
+ $user_id));
+ }
+ }
+
+ return $gc;
+ }
+}
+++ /dev/null
-<?php
-/**
- * Give a warm greeting to our friendly user
- *
- * PHP version 5
- *
- * @category Sample
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Give a warm greeting to our friendly user
- *
- * This sample action shows some basic ways of doing output in an action
- * class.
- *
- * Action classes have several output methods that they override from
- * the parent class.
- *
- * @category Sample
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class HelloAction extends Action
-{
- var $user = null;
- var $gc = null;
-
- /**
- * Take arguments for running
- *
- * This method is called first, and it lets the action class get
- * all its arguments and validate them. It's also the time
- * to fetch any relevant data from the database.
- *
- * Action classes should run parent::prepare($args) as the first
- * line of this method to make sure the default argument-processing
- * happens.
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $this->user = common_current_user();
-
- if (!empty($this->user)) {
- $this->gc = User_greeting_count::inc($this->user->id);
- }
-
- return true;
- }
-
- /**
- * Handle request
- *
- * This is the main method for handling a request. Note that
- * most preparation should be done in the prepare() method;
- * by the time handle() is called the action should be
- * more or less ready to go.
- *
- * @param array $args $_REQUEST args; handled in prepare()
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- $this->showPage();
- }
-
- /**
- * Title of this page
- *
- * Override this method to show a custom title.
- *
- * @return string Title of the page
- */
- function title()
- {
- if (empty($this->user)) {
- // TRANS: Page title for sample plugin.
- return _m('Hello');
- } else {
- // TRANS: Page title for sample plugin. %s is a user nickname.
- return sprintf(_m('Hello, %s!'), $this->user->nickname);
- }
- }
-
- /**
- * Show content in the content area
- *
- * The default StatusNet page has a lot of decorations: menus,
- * logos, tabs, all that jazz. This method is used to show
- * content in the content area of the page; it's the main
- * thing you want to overload.
- *
- * This method also demonstrates use of a plural localized string.
- *
- * @return void
- */
- function showContent()
- {
- if (empty($this->user)) {
- $this->element('p', array('class' => 'greeting'),
- // TRANS: Message in sample plugin.
- _m('Hello, stranger!'));
- } else {
- $this->element('p', array('class' => 'greeting'),
- // TRANS: Message in sample plugin. %s is a user nickname.
- sprintf(_m('Hello, %s'), $this->user->nickname));
- $this->element('p', array('class' => 'greeting_count'),
- // TRANS: Message in sample plugin.
- // TRANS: %d is the number of times a user is greeted.
- sprintf(_m('I have greeted you %d time.',
- 'I have greeted you %d times.',
- $this->gc->greeting_count),
- $this->gc->greeting_count));
- }
- }
-
- /**
- * Return true if read only.
- *
- * Some actions only read from the database; others read and write.
- * The simple database load-balancer built into StatusNet will
- * direct read-only actions to database mirrors (if they are configured),
- * and read-write actions to the master database.
- *
- * This defaults to false to avoid data integrity issues, but you
- * should make sure to overload it for performance gains.
- *
- * @param array $args other arguments, if RO/RW status depends on them.
- *
- * @return boolean is read only action?
- */
- function isReadOnly($args)
- {
- return false;
- }
-}
+++ /dev/null
-<?php
-/**
- * Data class to store local search subscriptions
- *
- * PHP version 5
- *
- * @category SearchSubPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * For storing the search subscriptions
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-
-class SearchSub extends Managed_DataObject
-{
- public $__table = 'searchsub'; // table name
- public $search; // text
- public $profile_id; // int -> profile.id
- public $created; // datetime
-
- /**
- * The One True Thingy that must be defined and declared.
- */
- public static function schemaDef()
- {
- return array(
- 'description' => 'SearchSubPlugin search subscription records',
- 'fields' => array(
- 'search' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'hash search associated with this subscription'),
- 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile ID of subscribing user'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- ),
- 'primary key' => array('search', 'profile_id'),
- 'foreign keys' => array(
- 'searchsub_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
- ),
- 'indexes' => array(
- 'searchsub_created_idx' => array('created'),
- 'searchsub_profile_id_tag_idx' => array('profile_id', 'search'),
- ),
- );
- }
-
- /**
- * Start a search subscription!
- *
- * @param profile $profile subscriber
- * @param string $search subscribee
- * @return SearchSub
- */
- static function start(Profile $profile, $search)
- {
- $ts = new SearchSub();
- $ts->search = $search;
- $ts->profile_id = $profile->id;
- $ts->created = common_sql_now();
- $ts->insert();
- self::blow('searchsub:by_profile:%d', $profile->id);
- return $ts;
- }
-
- /**
- * End a search subscription!
- *
- * @param profile $profile subscriber
- * @param string $search subscribee
- */
- static function cancel(Profile $profile, $search)
- {
- $ts = SearchSub::pkeyGet(array('search' => $search,
- 'profile_id' => $profile->id));
- if ($ts) {
- $ts->delete();
- self::blow('searchsub:by_profile:%d', $profile->id);
- }
- }
-
- static function forProfile(Profile $profile)
- {
- $searches = array();
-
- $keypart = sprintf('searchsub:by_profile:%d', $profile->id);
- $searchstring = self::cacheGet($keypart);
-
- if ($searchstring !== false) {
- if (!empty($searchstring)) {
- $searches = explode(',', $searchstring);
- }
- } else {
- $searchsub = new SearchSub();
- $searchsub->profile_id = $profile->id;
- $searchsub->selectAdd();
- $searchsub->selectAdd('search');
-
- if ($searchsub->find()) {
- $searches = $searchsub->fetchAll('search');
- }
-
- self::cacheSet($keypart, implode(',', $searches));
- }
-
- return $searches;
- }
-}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'SearchSub':
- include_once $dir.'/'.$cls.'.php';
- return false;
- case 'SearchsubAction':
- case 'SearchunsubAction':
- case 'SearchsubsAction':
- case 'SearchSubForm':
- case 'SearchSubMenu':
- case 'SearchUnsubForm':
- case 'SearchSubTrackCommand':
- case 'SearchSubTrackOffCommand':
- case 'SearchSubTrackingCommand':
- case 'SearchSubUntrackCommand':
- include_once $dir.'/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Map URLs to actions
*
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008-2011, StatusNet, Inc.
+ *
+ * Search subscription action.
+ *
+ * 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/>.
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Search subscription action
+ *
+ * Takes parameters:
+ *
+ * - token: session token to prevent CSRF attacks
+ * - ajax: boolean; whether to return Ajax or full-browser results
+ *
+ * Only works if the current user is logged in.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2008-2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+class SearchsubAction extends Action
+{
+ var $user;
+ var $search;
+
+ /**
+ * Check pre-requisites and instantiate attributes
+ *
+ * @param Array $args array of arguments (URL, GET, POST)
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+ if ($this->boolean('ajax')) {
+ StatusNet::setApi(true);
+ }
+
+ // Only allow POST requests
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ // TRANS: Client error displayed trying to perform any request method other than POST.
+ // TRANS: Do not translate POST.
+ $this->clientError(_m('This action only accepts POST requests.'));
+ return false;
+ }
+
+ // CSRF protection
+
+ $token = $this->trimmed('token');
+
+ if (!$token || $token != common_session_token()) {
+ // TRANS: Client error displayed when the session token is not okay.
+ $this->clientError(_m('There was a problem with your session token.'.
+ ' Try again, please.'));
+ return false;
+ }
+
+ // Only for logged-in users
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
+ $this->clientError(_m('Not logged in.'));
+ return false;
+ }
+
+ // Profile to subscribe to
+
+ $this->search = $this->arg('search');
+
+ if (empty($this->search)) {
+ // TRANS: Client error displayed trying to subscribe to a non-existing profile.
+ $this->clientError(_m('No such profile.'));
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle request
+ *
+ * Does the subscription and returns results.
+ *
+ * @param Array $args unused.
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ // Throws exception on error
+
+ SearchSub::start($this->user->getProfile(),
+ $this->search);
+
+ if ($this->boolean('ajax')) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Page title when search subscription succeeded.
+ $this->element('title', null, _m('Subscribed'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $unsubscribe = new SearchUnsubForm($this, $this->search);
+ $unsubscribe->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ $url = common_local_url('search',
+ array('search' => $this->search));
+ common_redirect($url, 303);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List of a user's subscriptions
+ *
+ * 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 Social
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * A list of the user's subscriptions
+ *
+ * @category Social
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class SearchSubsAction extends GalleryAction
+{
+ function title()
+ {
+ if ($this->page == 1) {
+ // TRANS: Header for subscriptions overview for a user (first page).
+ // TRANS: %s is a user nickname.
+ return sprintf(_m('%s\'s search subscriptions'), $this->user->nickname);
+ } else {
+ // TRANS: Header for subscriptions overview for a user (not first page).
+ // TRANS: %1$s is a user nickname, %2$d is the page number.
+ return sprintf(_m('%1$s\'s search subscriptions, page %2$d'),
+ $this->user->nickname,
+ $this->page);
+ }
+ }
+
+ function showPageNotice()
+ {
+ $user = common_current_user();
+ if ($user && ($user->id == $this->profile->id)) {
+ $this->element('p', null,
+ // TRANS: Page notice for page with an overview of all search subscriptions
+ // TRANS: of the logged in user's own profile.
+ _m('You have subscribed to receive all notices on this site matching the following searches:'));
+ } else {
+ $this->element('p', null,
+ // TRANS: Page notice for page with an overview of all subscriptions of a user other
+ // TRANS: than the logged in user. %s is the user nickname.
+ sprintf(_m('%s has subscribed to receive all notices on this site matching the following searches:'),
+ $this->profile->nickname));
+ }
+ }
+
+ function showContent()
+ {
+ if (Event::handle('StartShowTagSubscriptionsContent', array($this))) {
+ parent::showContent();
+
+ $offset = ($this->page-1) * PROFILES_PER_PAGE;
+ $limit = PROFILES_PER_PAGE + 1;
+
+ $cnt = 0;
+
+ $searchsub = new SearchSub();
+ $searchsub->profile_id = $this->user->id;
+ $searchsub->limit($limit, $offset);
+ $searchsub->find();
+
+ if ($searchsub->N) {
+ $list = new SearchSubscriptionsList($searchsub, $this->user, $this);
+ $cnt = $list->show();
+ if (0 == $cnt) {
+ $this->showEmptyListMessage();
+ }
+ } else {
+ $this->showEmptyListMessage();
+ }
+
+ $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
+ $this->page, 'searchsubs',
+ array('nickname' => $this->user->nickname));
+
+
+ Event::handle('EndShowTagSubscriptionsContent', array($this));
+ }
+ }
+
+ function showEmptyListMessage()
+ {
+ if (common_logged_in()) {
+ $current_user = common_current_user();
+ if ($this->user->id === $current_user->id) {
+ // TRANS: Search subscription list text when the logged in user has no search subscriptions.
+ $message = _m('You are not subscribed to any text searches right now. You can push the "Subscribe" button ' .
+ 'on any notice text search to automatically receive any public messages on this site that match that ' .
+ 'search, even if you are not subscribed to the poster.');
+ } else {
+ // TRANS: Search subscription list text when looking at the subscriptions for a of a user other
+ // TRANS: than the logged in user that has no search subscriptions. %s is the user nickname.
+ $message = sprintf(_m('%s is not subscribed to any searches.'), $this->user->nickname);
+ }
+ }
+ else {
+ // TRANS: Subscription list text when looking at the subscriptions for a of a user that has none
+ // TRANS: as an anonymous user. %s is the user nickname.
+ $message = sprintf(_m('%s is not subscribed to any searches.'), $this->user->nickname);
+ }
+
+ $this->elementStart('div', 'guide');
+ $this->raw(common_markup_to_html($message));
+ $this->elementEnd('div');
+ }
+}
+
+// XXX SubscriptionsList and SubscriptionList are dangerously close
+
+class SearchSubscriptionsList extends SubscriptionList
+{
+ function newListItem($searchsub)
+ {
+ return new SearchSubscriptionsListItem($searchsub, $this->owner, $this->action);
+ }
+}
+
+class SearchSubscriptionsListItem extends SubscriptionListItem
+{
+ function startItem()
+ {
+ $this->out->elementStart('li', array('class' => 'searchsub'));
+ }
+
+ function showProfile()
+ {
+ $searchsub = $this->profile;
+ $search = $searchsub->search;
+
+ // Relevant portion!
+ $cur = common_current_user();
+ if (!empty($cur) && $cur->id == $this->owner->id) {
+ $this->showOwnerControls();
+ }
+
+ $url = common_local_url('noticesearch', array('q' => $search));
+ // TRANS: Search subscription list item. %1$s is a URL to a notice search,
+ // TRANS: %2$s are the search criteria, %3$s is a datestring.
+ $linkline = sprintf(_m('"<a href="%1$s">%2$s</a>" since %3$s'),
+ htmlspecialchars($url),
+ htmlspecialchars($search),
+ common_date_string($searchsub->created));
+
+ $this->out->elementStart('div', 'searchsub-item');
+ $this->out->raw($linkline);
+ $this->out->element('div', array('style' => 'clear: both'));
+ $this->out->elementEnd('div');
+ }
+
+ function showActions()
+ {
+ }
+
+ function showOwnerControls()
+ {
+ $this->out->elementStart('div', 'entity_actions');
+
+ $searchsub = $this->profile; // ?
+ $form = new SearchUnsubForm($this->out, $searchsub->search);
+ $form->show();
+
+ $this->out->elementEnd('div');
+ return;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008-2011, StatusNet, Inc.
+ *
+ * Search subscription action.
+ *
+ * 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/>.
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Search unsubscription action
+ *
+ * Takes parameters:
+ *
+ * - token: session token to prevent CSRF attacks
+ * - ajax: boolean; whether to return Ajax or full-browser results
+ *
+ * Only works if the current user is logged in.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2008-2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+class SearchunsubAction extends SearchsubAction
+{
+ /**
+ * Handle request
+ *
+ * Does the subscription and returns results.
+ *
+ * @param Array $args unused.
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ // Throws exception on error
+
+ SearchSub::cancel($this->user->getProfile(),
+ $this->search);
+
+ if ($this->boolean('ajax')) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Page title when search unsubscription succeeded.
+ $this->element('title', null, _m('Unsubscribed'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $subscribe = new SearchSubForm($this, $this->search);
+ $subscribe->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ $url = common_local_url('search',
+ array('search' => $this->search));
+ common_redirect($url, 303);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class to store local search subscriptions
+ *
+ * PHP version 5
+ *
+ * @category SearchSubPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * For storing the search subscriptions
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+
+class SearchSub extends Managed_DataObject
+{
+ public $__table = 'searchsub'; // table name
+ public $search; // text
+ public $profile_id; // int -> profile.id
+ public $created; // datetime
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'SearchSubPlugin search subscription records',
+ 'fields' => array(
+ 'search' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'hash search associated with this subscription'),
+ 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile ID of subscribing user'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ ),
+ 'primary key' => array('search', 'profile_id'),
+ 'foreign keys' => array(
+ 'searchsub_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
+ ),
+ 'indexes' => array(
+ 'searchsub_created_idx' => array('created'),
+ 'searchsub_profile_id_tag_idx' => array('profile_id', 'search'),
+ ),
+ );
+ }
+
+ /**
+ * Start a search subscription!
+ *
+ * @param profile $profile subscriber
+ * @param string $search subscribee
+ * @return SearchSub
+ */
+ static function start(Profile $profile, $search)
+ {
+ $ts = new SearchSub();
+ $ts->search = $search;
+ $ts->profile_id = $profile->id;
+ $ts->created = common_sql_now();
+ $ts->insert();
+ self::blow('searchsub:by_profile:%d', $profile->id);
+ return $ts;
+ }
+
+ /**
+ * End a search subscription!
+ *
+ * @param profile $profile subscriber
+ * @param string $search subscribee
+ */
+ static function cancel(Profile $profile, $search)
+ {
+ $ts = SearchSub::pkeyGet(array('search' => $search,
+ 'profile_id' => $profile->id));
+ if ($ts) {
+ $ts->delete();
+ self::blow('searchsub:by_profile:%d', $profile->id);
+ }
+ }
+
+ static function forProfile(Profile $profile)
+ {
+ $searches = array();
+
+ $keypart = sprintf('searchsub:by_profile:%d', $profile->id);
+ $searchstring = self::cacheGet($keypart);
+
+ if ($searchstring !== false) {
+ if (!empty($searchstring)) {
+ $searches = explode(',', $searchstring);
+ }
+ } else {
+ $searchsub = new SearchSub();
+ $searchsub->profile_id = $profile->id;
+ $searchsub->selectAdd();
+ $searchsub->selectAdd('search');
+
+ if ($searchsub->find()) {
+ $searches = $searchsub->fetchAll('search');
+ }
+
+ self::cacheSet($keypart, implode(',', $searches));
+ }
+
+ return $searches;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for subscribing to a search
+ *
+ * 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 SearchSubPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009-2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Form for subscribing to a user
+ *
+ * @category SearchSubPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ * @see UnsubscribeForm
+ */
+class SearchSubForm extends Form
+{
+ /**
+ * Name of search to subscribe to
+ */
+ var $search = '';
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param string $search name of search to subscribe to
+ */
+ function __construct($out=null, $search=null)
+ {
+ parent::__construct($out);
+
+ $this->search = $search;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'search-subscribe-' . $this->search;
+ }
+
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+ function formClass()
+ {
+ // class to match existing styles...
+ return 'form_user_subscribe ajax';
+ }
+
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('searchsub', array('search' => $this->search));
+ }
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend.
+ $this->out->element('legend', null, _m('Subscribe to this search'));
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->hidden('subscribeto-' . $this->search,
+ $this->search,
+ 'subscribeto');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $this->out->submit('submit',
+ // TRANS: Button text for subscribing to a search.
+ _m('BUTTON','Subscribe'),
+ 'submit',
+ null,
+ // TRANS: Button title for subscribing to a search.
+ _m('Subscribe to this search.'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for subscribing to a search
+ *
+ * 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 SearchSubPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009-2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Form for subscribing to a user
+ *
+ * @category SearchSubPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ * @see UnsubscribeForm
+ */
+class SearchUnsubForm extends SearchSubForm
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'search-unsubscribe-' . $this->search;
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+ function formClass()
+ {
+ // class to match existing styles...
+ return 'form_user_unsubscribe ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('searchunsub', array('search' => $this->search));
+ }
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend.
+ $this->out->element('legend', null, _m('Unsubscribe from this search'));
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $this->out->submit('submit',
+ // TRANS: Button text for unsubscribing from a text search.
+ _m('BUTTON','Unsubscribe'),
+ 'submit',
+ null,
+ // TRANS: Button title for unsubscribing from a text search.
+ _m('Unsubscribe from this search.'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Menu to show searches you're subscribed to
+ *
+ * PHP version 5
+ *
+ * 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 Menu
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Class comment
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class SearchSubMenu extends MoreMenu
+{
+ protected $user;
+ protected $searches;
+
+ function __construct($out, $user, $searches)
+ {
+ parent::__construct($out);
+ $this->user = $user;
+ $this->searches = $searches;
+ }
+
+ function tag()
+ {
+ return 'searchsubs';
+ }
+
+ function seeAllItem()
+ {
+ return array('searchsubs',
+ array('nickname' => $this->user->nickname),
+ _('See all'),
+ _('See all searches you are following'));
+ }
+
+ function getItems()
+ {
+ $items = array();
+
+ foreach ($this->searches as $search) {
+ if (!empty($search)) {
+ $items[] = array('noticesearch',
+ array('q' => $search),
+ sprintf('"%s"', $search),
+ sprintf(_('Notices including %s'), $search));;
+ }
+ }
+
+ return $items;
+ }
+
+ function item($actionName, $args, $label, $description, $id=null, $cls=null)
+ {
+ if (empty($id)) {
+ $id = $this->menuItemID($actionName, $args);
+ }
+
+ if ($actionName == 'noticesearch') {
+ // Add 'q' as a search param, not part of the url path
+ $url = common_local_url($actionName, array(), $args);
+ } else {
+ $url = common_local_url($actionName, $args);
+ }
+
+ $this->out->menuItem($url,
+ $label,
+ $description,
+ $this->isCurrent($actionName, $args),
+ $id,
+ $cls);
+ }
+}
+
--- /dev/null
+<?php
+
+class SearchSubTrackCommand extends Command
+{
+ var $keyword = null;
+
+ function __construct($user, $keyword)
+ {
+ parent::__construct($user);
+ $this->keyword = $keyword;
+ }
+
+ function handle($channel)
+ {
+ $cur = $this->user;
+ $searchsub = SearchSub::pkeyGet(array('search' => $this->keyword,
+ 'profile_id' => $cur->id));
+
+ if ($searchsub) {
+ // TRANS: Error text shown a user tries to track a search query they're already subscribed to.
+ $channel->error($cur, sprintf(_m('You are already tracking the search "%s".'), $this->keyword));
+ return;
+ }
+
+ try {
+ SearchSub::start($cur->getProfile(), $this->keyword);
+ } catch (Exception $e) {
+ // TRANS: Message given having failed to set up a search subscription by track command.
+ $channel->error($cur, sprintf(_m('Could not start a search subscription for query "%s".'),
+ $this->keyword));
+ return;
+ }
+
+ // TRANS: Message given having added a search subscription by track command.
+ $channel->output($cur, sprintf(_m('You are subscribed to the search "%s".'),
+ $this->keyword));
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+
+class SearchSubTrackingCommand extends Command
+{
+ function handle($channel)
+ {
+ $cur = $this->user;
+ $all = new SearchSub();
+ $all->profile_id = $cur->id;
+ $all->find();
+
+ if ($all->N == 0) {
+ // TRANS: Error text shown a user tries to disable all a search subscriptions with track off command, but has none.
+ $channel->error($cur, _m('You are not tracking any searches.'));
+ return;
+ }
+
+ $list = array();
+ while ($all->fetch()) {
+ $list[] = $all->search;
+ }
+
+ // TRANS: Separator for list of tracked searches.
+ $separator = _m('SEPARATOR','", "');
+
+ // TRANS: Message given having disabled all search subscriptions with 'track off'.
+ // TRANS: %s is a list of searches. Separator default is '", "'.
+ $channel->output($cur, sprintf(_m('You are tracking searches for: "%s".'),
+ implode($separator, $list)));
+ }
+}
--- /dev/null
+<?php
+
+class SearchSubTrackoffCommand extends Command
+{
+ function handle($channel)
+ {
+ $cur = $this->user;
+ $all = new SearchSub();
+ $all->profile_id = $cur->id;
+ $all->find();
+
+ if ($all->N == 0) {
+ // TRANS: Error text shown a user tries to disable all a search subscriptions with track off command, but has none.
+ $channel->error($cur, _m('You are not tracking any searches.'));
+ return;
+ }
+
+ $profile = $cur->getProfile();
+ while ($all->fetch()) {
+ try {
+ SearchSub::cancel($profile, $all->search);
+ } catch (Exception $e) {
+ // TRANS: Message given having failed to cancel one of the search subs with 'track off' command.
+ // TRANS: %s is the search for which the subscription removal failed.
+ $channel->error($cur, sprintf(_m('Error disabling search subscription for query "%s".'),
+ $all->search));
+ return;
+ }
+ }
+
+ // TRANS: Message given having disabled all search subscriptions with 'track off'.
+ $channel->output($cur, _m('Disabled all your search subscriptions.'));
+ }
+}
--- /dev/null
+<?php
+
+class SearchSubUntrackCommand extends Command
+{
+ var $keyword = null;
+
+ function __construct($user, $keyword)
+ {
+ parent::__construct($user);
+ $this->keyword = $keyword;
+ }
+
+ function handle($channel)
+ {
+ $cur = $this->user;
+ $searchsub = SearchSub::pkeyGet(array('search' => $this->keyword,
+ 'profile_id' => $cur->id));
+
+ if (!$searchsub) {
+ // TRANS: Error text shown a user tries to untrack a search query they're not subscribed to.
+ // TRANS: %s is the keyword for the search.
+ $channel->error($cur, sprintf(_m('You are not tracking the search "%s".'), $this->keyword));
+ return;
+ }
+
+ try {
+ SearchSub::cancel($cur->getProfile(), $this->keyword);
+ } catch (Exception $e) {
+ // TRANS: Message given having failed to cancel a search subscription by untrack command.
+ // TRANS: %s is the keyword for the query.
+ $channel->error($cur, sprintf(_m('Could not end a search subscription for query "%s".'),
+ $this->keyword));
+ return;
+ }
+
+ // TRANS: Message given having removed a search subscription by untrack command.
+ // TRANS: %s is the keyword for the search.
+ $channel->output($cur, sprintf(_m('You are no longer subscribed to the search "%s".'),
+ $this->keyword));
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008-2011, StatusNet, Inc.
- *
- * Search subscription action.
- *
- * 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/>.
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Search subscription action
- *
- * Takes parameters:
- *
- * - token: session token to prevent CSRF attacks
- * - ajax: boolean; whether to return Ajax or full-browser results
- *
- * Only works if the current user is logged in.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Brion Vibber <brion@status.net>
- * @copyright 2008-2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-class SearchsubAction extends Action
-{
- var $user;
- var $search;
-
- /**
- * Check pre-requisites and instantiate attributes
- *
- * @param Array $args array of arguments (URL, GET, POST)
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- parent::prepare($args);
- if ($this->boolean('ajax')) {
- StatusNet::setApi(true);
- }
-
- // Only allow POST requests
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- // TRANS: Client error displayed trying to perform any request method other than POST.
- // TRANS: Do not translate POST.
- $this->clientError(_m('This action only accepts POST requests.'));
- return false;
- }
-
- // CSRF protection
-
- $token = $this->trimmed('token');
-
- if (!$token || $token != common_session_token()) {
- // TRANS: Client error displayed when the session token is not okay.
- $this->clientError(_m('There was a problem with your session token.'.
- ' Try again, please.'));
- return false;
- }
-
- // Only for logged-in users
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
- $this->clientError(_m('Not logged in.'));
- return false;
- }
-
- // Profile to subscribe to
-
- $this->search = $this->arg('search');
-
- if (empty($this->search)) {
- // TRANS: Client error displayed trying to subscribe to a non-existing profile.
- $this->clientError(_m('No such profile.'));
- return false;
- }
-
- return true;
- }
-
- /**
- * Handle request
- *
- * Does the subscription and returns results.
- *
- * @param Array $args unused.
- *
- * @return void
- */
- function handle($args)
- {
- // Throws exception on error
-
- SearchSub::start($this->user->getProfile(),
- $this->search);
-
- if ($this->boolean('ajax')) {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- // TRANS: Page title when search subscription succeeded.
- $this->element('title', null, _m('Subscribed'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $unsubscribe = new SearchUnsubForm($this, $this->search);
- $unsubscribe->show();
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- $url = common_local_url('search',
- array('search' => $this->search));
- common_redirect($url, 303);
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for subscribing to a search
- *
- * 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 SearchSubPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @copyright 2009-2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * Form for subscribing to a user
- *
- * @category SearchSubPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- *
- * @see UnsubscribeForm
- */
-class SearchSubForm extends Form
-{
- /**
- * Name of search to subscribe to
- */
- var $search = '';
-
- /**
- * Constructor
- *
- * @param HTMLOutputter $out output channel
- * @param string $search name of search to subscribe to
- */
- function __construct($out=null, $search=null)
- {
- parent::__construct($out);
-
- $this->search = $search;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'search-subscribe-' . $this->search;
- }
-
-
- /**
- * class of the form
- *
- * @return string of the form class
- */
- function formClass()
- {
- // class to match existing styles...
- return 'form_user_subscribe ajax';
- }
-
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('searchsub', array('search' => $this->search));
- }
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend.
- $this->out->element('legend', null, _m('Subscribe to this search'));
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->hidden('subscribeto-' . $this->search,
- $this->search,
- 'subscribeto');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $this->out->submit('submit',
- // TRANS: Button text for subscribing to a search.
- _m('BUTTON','Subscribe'),
- 'submit',
- null,
- // TRANS: Button title for subscribing to a search.
- _m('Subscribe to this search.'));
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Menu to show searches you're subscribed to
- *
- * PHP version 5
- *
- * 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 Menu
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Class comment
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class SearchSubMenu extends MoreMenu
-{
- protected $user;
- protected $searches;
-
- function __construct($out, $user, $searches)
- {
- parent::__construct($out);
- $this->user = $user;
- $this->searches = $searches;
- }
-
- function tag()
- {
- return 'searchsubs';
- }
-
- function seeAllItem()
- {
- return array('searchsubs',
- array('nickname' => $this->user->nickname),
- _('See all'),
- _('See all searches you are following'));
- }
-
- function getItems()
- {
- $items = array();
-
- foreach ($this->searches as $search) {
- if (!empty($search)) {
- $items[] = array('noticesearch',
- array('q' => $search),
- sprintf('"%s"', $search),
- sprintf(_('Notices including %s'), $search));;
- }
- }
-
- return $items;
- }
-
- function item($actionName, $args, $label, $description, $id=null, $cls=null)
- {
- if (empty($id)) {
- $id = $this->menuItemID($actionName, $args);
- }
-
- if ($actionName == 'noticesearch') {
- // Add 'q' as a search param, not part of the url path
- $url = common_local_url($actionName, array(), $args);
- } else {
- $url = common_local_url($actionName, $args);
- }
-
- $this->out->menuItem($url,
- $label,
- $description,
- $this->isCurrent($actionName, $args),
- $id,
- $cls);
- }
-}
-
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * List of a user's subscriptions
- *
- * 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 Social
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @copyright 2008-2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * A list of the user's subscriptions
- *
- * @category Social
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class SearchSubsAction extends GalleryAction
-{
- function title()
- {
- if ($this->page == 1) {
- // TRANS: Header for subscriptions overview for a user (first page).
- // TRANS: %s is a user nickname.
- return sprintf(_m('%s\'s search subscriptions'), $this->user->nickname);
- } else {
- // TRANS: Header for subscriptions overview for a user (not first page).
- // TRANS: %1$s is a user nickname, %2$d is the page number.
- return sprintf(_m('%1$s\'s search subscriptions, page %2$d'),
- $this->user->nickname,
- $this->page);
- }
- }
-
- function showPageNotice()
- {
- $user = common_current_user();
- if ($user && ($user->id == $this->profile->id)) {
- $this->element('p', null,
- // TRANS: Page notice for page with an overview of all search subscriptions
- // TRANS: of the logged in user's own profile.
- _m('You have subscribed to receive all notices on this site matching the following searches:'));
- } else {
- $this->element('p', null,
- // TRANS: Page notice for page with an overview of all subscriptions of a user other
- // TRANS: than the logged in user. %s is the user nickname.
- sprintf(_m('%s has subscribed to receive all notices on this site matching the following searches:'),
- $this->profile->nickname));
- }
- }
-
- function showContent()
- {
- if (Event::handle('StartShowTagSubscriptionsContent', array($this))) {
- parent::showContent();
-
- $offset = ($this->page-1) * PROFILES_PER_PAGE;
- $limit = PROFILES_PER_PAGE + 1;
-
- $cnt = 0;
-
- $searchsub = new SearchSub();
- $searchsub->profile_id = $this->user->id;
- $searchsub->limit($limit, $offset);
- $searchsub->find();
-
- if ($searchsub->N) {
- $list = new SearchSubscriptionsList($searchsub, $this->user, $this);
- $cnt = $list->show();
- if (0 == $cnt) {
- $this->showEmptyListMessage();
- }
- } else {
- $this->showEmptyListMessage();
- }
-
- $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
- $this->page, 'searchsubs',
- array('nickname' => $this->user->nickname));
-
-
- Event::handle('EndShowTagSubscriptionsContent', array($this));
- }
- }
-
- function showEmptyListMessage()
- {
- if (common_logged_in()) {
- $current_user = common_current_user();
- if ($this->user->id === $current_user->id) {
- // TRANS: Search subscription list text when the logged in user has no search subscriptions.
- $message = _m('You are not subscribed to any text searches right now. You can push the "Subscribe" button ' .
- 'on any notice text search to automatically receive any public messages on this site that match that ' .
- 'search, even if you are not subscribed to the poster.');
- } else {
- // TRANS: Search subscription list text when looking at the subscriptions for a of a user other
- // TRANS: than the logged in user that has no search subscriptions. %s is the user nickname.
- $message = sprintf(_m('%s is not subscribed to any searches.'), $this->user->nickname);
- }
- }
- else {
- // TRANS: Subscription list text when looking at the subscriptions for a of a user that has none
- // TRANS: as an anonymous user. %s is the user nickname.
- $message = sprintf(_m('%s is not subscribed to any searches.'), $this->user->nickname);
- }
-
- $this->elementStart('div', 'guide');
- $this->raw(common_markup_to_html($message));
- $this->elementEnd('div');
- }
-}
-
-// XXX SubscriptionsList and SubscriptionList are dangerously close
-
-class SearchSubscriptionsList extends SubscriptionList
-{
- function newListItem($searchsub)
- {
- return new SearchSubscriptionsListItem($searchsub, $this->owner, $this->action);
- }
-}
-
-class SearchSubscriptionsListItem extends SubscriptionListItem
-{
- function startItem()
- {
- $this->out->elementStart('li', array('class' => 'searchsub'));
- }
-
- function showProfile()
- {
- $searchsub = $this->profile;
- $search = $searchsub->search;
-
- // Relevant portion!
- $cur = common_current_user();
- if (!empty($cur) && $cur->id == $this->owner->id) {
- $this->showOwnerControls();
- }
-
- $url = common_local_url('noticesearch', array('q' => $search));
- // TRANS: Search subscription list item. %1$s is a URL to a notice search,
- // TRANS: %2$s are the search criteria, %3$s is a datestring.
- $linkline = sprintf(_m('"<a href="%1$s">%2$s</a>" since %3$s'),
- htmlspecialchars($url),
- htmlspecialchars($search),
- common_date_string($searchsub->created));
-
- $this->out->elementStart('div', 'searchsub-item');
- $this->out->raw($linkline);
- $this->out->element('div', array('style' => 'clear: both'));
- $this->out->elementEnd('div');
- }
-
- function showActions()
- {
- }
-
- function showOwnerControls()
- {
- $this->out->elementStart('div', 'entity_actions');
-
- $searchsub = $this->profile; // ?
- $form = new SearchUnsubForm($this->out, $searchsub->search);
- $form->show();
-
- $this->out->elementEnd('div');
- return;
- }
-}
+++ /dev/null
-<?php
-
-class SearchSubTrackCommand extends Command
-{
- var $keyword = null;
-
- function __construct($user, $keyword)
- {
- parent::__construct($user);
- $this->keyword = $keyword;
- }
-
- function handle($channel)
- {
- $cur = $this->user;
- $searchsub = SearchSub::pkeyGet(array('search' => $this->keyword,
- 'profile_id' => $cur->id));
-
- if ($searchsub) {
- // TRANS: Error text shown a user tries to track a search query they're already subscribed to.
- $channel->error($cur, sprintf(_m('You are already tracking the search "%s".'), $this->keyword));
- return;
- }
-
- try {
- SearchSub::start($cur->getProfile(), $this->keyword);
- } catch (Exception $e) {
- // TRANS: Message given having failed to set up a search subscription by track command.
- $channel->error($cur, sprintf(_m('Could not start a search subscription for query "%s".'),
- $this->keyword));
- return;
- }
-
- // TRANS: Message given having added a search subscription by track command.
- $channel->output($cur, sprintf(_m('You are subscribed to the search "%s".'),
- $this->keyword));
- }
-}
\ No newline at end of file
+++ /dev/null
-<?php
-
-class SearchSubTrackingCommand extends Command
-{
- function handle($channel)
- {
- $cur = $this->user;
- $all = new SearchSub();
- $all->profile_id = $cur->id;
- $all->find();
-
- if ($all->N == 0) {
- // TRANS: Error text shown a user tries to disable all a search subscriptions with track off command, but has none.
- $channel->error($cur, _m('You are not tracking any searches.'));
- return;
- }
-
- $list = array();
- while ($all->fetch()) {
- $list[] = $all->search;
- }
-
- // TRANS: Separator for list of tracked searches.
- $separator = _m('SEPARATOR','", "');
-
- // TRANS: Message given having disabled all search subscriptions with 'track off'.
- // TRANS: %s is a list of searches. Separator default is '", "'.
- $channel->output($cur, sprintf(_m('You are tracking searches for: "%s".'),
- implode($separator, $list)));
- }
-}
+++ /dev/null
-<?php
-
-class SearchSubTrackoffCommand extends Command
-{
- function handle($channel)
- {
- $cur = $this->user;
- $all = new SearchSub();
- $all->profile_id = $cur->id;
- $all->find();
-
- if ($all->N == 0) {
- // TRANS: Error text shown a user tries to disable all a search subscriptions with track off command, but has none.
- $channel->error($cur, _m('You are not tracking any searches.'));
- return;
- }
-
- $profile = $cur->getProfile();
- while ($all->fetch()) {
- try {
- SearchSub::cancel($profile, $all->search);
- } catch (Exception $e) {
- // TRANS: Message given having failed to cancel one of the search subs with 'track off' command.
- // TRANS: %s is the search for which the subscription removal failed.
- $channel->error($cur, sprintf(_m('Error disabling search subscription for query "%s".'),
- $all->search));
- return;
- }
- }
-
- // TRANS: Message given having disabled all search subscriptions with 'track off'.
- $channel->output($cur, _m('Disabled all your search subscriptions.'));
- }
-}
+++ /dev/null
-<?php
-
-class SearchSubUntrackCommand extends Command
-{
- var $keyword = null;
-
- function __construct($user, $keyword)
- {
- parent::__construct($user);
- $this->keyword = $keyword;
- }
-
- function handle($channel)
- {
- $cur = $this->user;
- $searchsub = SearchSub::pkeyGet(array('search' => $this->keyword,
- 'profile_id' => $cur->id));
-
- if (!$searchsub) {
- // TRANS: Error text shown a user tries to untrack a search query they're not subscribed to.
- // TRANS: %s is the keyword for the search.
- $channel->error($cur, sprintf(_m('You are not tracking the search "%s".'), $this->keyword));
- return;
- }
-
- try {
- SearchSub::cancel($cur->getProfile(), $this->keyword);
- } catch (Exception $e) {
- // TRANS: Message given having failed to cancel a search subscription by untrack command.
- // TRANS: %s is the keyword for the query.
- $channel->error($cur, sprintf(_m('Could not end a search subscription for query "%s".'),
- $this->keyword));
- return;
- }
-
- // TRANS: Message given having removed a search subscription by untrack command.
- // TRANS: %s is the keyword for the search.
- $channel->output($cur, sprintf(_m('You are no longer subscribed to the search "%s".'),
- $this->keyword));
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008-2011, StatusNet, Inc.
- *
- * Search subscription action.
- *
- * 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/>.
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Search unsubscription action
- *
- * Takes parameters:
- *
- * - token: session token to prevent CSRF attacks
- * - ajax: boolean; whether to return Ajax or full-browser results
- *
- * Only works if the current user is logged in.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Brion Vibber <brion@status.net>
- * @copyright 2008-2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-class SearchunsubAction extends SearchsubAction
-{
- /**
- * Handle request
- *
- * Does the subscription and returns results.
- *
- * @param Array $args unused.
- *
- * @return void
- */
- function handle($args)
- {
- // Throws exception on error
-
- SearchSub::cancel($this->user->getProfile(),
- $this->search);
-
- if ($this->boolean('ajax')) {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- // TRANS: Page title when search unsubscription succeeded.
- $this->element('title', null, _m('Unsubscribed'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $subscribe = new SearchSubForm($this, $this->search);
- $subscribe->show();
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- $url = common_local_url('search',
- array('search' => $this->search));
- common_redirect($url, 303);
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for subscribing to a search
- *
- * 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 SearchSubPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @copyright 2009-2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * Form for subscribing to a user
- *
- * @category SearchSubPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- *
- * @see UnsubscribeForm
- */
-class SearchUnsubForm extends SearchSubForm
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'search-unsubscribe-' . $this->search;
- }
-
- /**
- * class of the form
- *
- * @return string of the form class
- */
- function formClass()
- {
- // class to match existing styles...
- return 'form_user_unsubscribe ajax';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('searchunsub', array('search' => $this->search));
- }
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend.
- $this->out->element('legend', null, _m('Unsubscribe from this search'));
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $this->out->submit('submit',
- // TRANS: Button text for unsubscribing from a text search.
- _m('BUTTON','Unsubscribe'),
- 'submit',
- null,
- // TRANS: Button title for unsubscribing from a text search.
- _m('Unsubscribe from this search.'));
- }
-}
$action->element('style', null, '#site_notice { width: 100% }');
return true;
}
-
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'SiteNoticeSection':
- include_once $dir . '/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
- }
- }
}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Site notice section
+ *
+ * PHP version 5
+ *
+ * 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 Site
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Site notice section
+ *
+ * @category Site
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class SiteNoticeSection extends Section
+{
+ var $text;
+
+ function __construct($action, $text)
+ {
+ parent::__construct($action);
+ $this->text = $text;
+ }
+
+ function title()
+ {
+ return _('Site notice');
+ }
+
+ function showContent()
+ {
+ $this->out->raw($this->text);
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Site notice section
- *
- * PHP version 5
- *
- * 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 Site
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Site notice section
- *
- * @category Site
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-class SiteNoticeSection extends Section
-{
- var $text;
-
- function __construct($action, $text)
- {
- parent::__construct($action);
- $this->text = $text;
- }
-
- function title()
- {
- return _('Site notice');
- }
-
- function showContent()
- {
- $this->out->raw($this->text);
- }
-}
const USERS_PER_MAP = 50000;
const NOTICES_PER_MAP = 50000;
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'Sitemap_user_count':
- case 'Sitemap_notice_count':
- require_once $dir . '/' . $cls . '.php';
- return false;
- case 'SitemapindexAction':
- case 'NoticesitemapAction':
- case 'UsersitemapAction':
- case 'SitemapadminpanelAction':
- require_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'SitemapAction':
- require_once $dir . '/' . strtolower($cls) . '.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Add sitemap-related information at the end of robots.txt
*
+++ /dev/null
-<?php
-/**
- * Data class for counting notice postings by date
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for counting notices by date
- *
- * We make a separate sitemap for each notice posted by date.
- * To save ourselves some (not inconsiderable) processing effort,
- * we cache this data in the sitemap_notice_count table. Each
- * row represents a day since the site has been started, with a count
- * of notices posted on that day. Since, after the end of the day,
- * this number doesn't change, it's a good candidate for persistent caching.
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Sitemap_notice_count extends Managed_DataObject
-{
- public $__table = 'sitemap_notice_count'; // table name
-
- public $notice_date; // date primary_key not_null
- public $notice_count; // int(4)
- public $created; // datetime() not_null
- public $modified; // datetime not_null default_0000-00-00%2000%3A00%3A00
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'notice_date' => array('type' => 'date', 'not null' => true, 'description' => 'record date'),
- 'notice_count' => array('type' => 'int', 'not null' => true, 'description' => 'the notice count'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('notice_date'),
- );
- }
-
- static function getAll()
- {
- $noticeCounts = self::cacheGet('sitemap:notice:counts');
-
- if ($noticeCounts === false) {
- $snc = new Sitemap_notice_count();
- $snc->orderBy('notice_date DESC');
-
- // Fetch the first one to check up-to-date-itude
-
- $n = $snc->find(true);
-
- $today = self::today();
- $noticeCounts = array();
-
- if (!$n) { // No counts saved yet
- $noticeCounts = self::initializeCounts();
- } else if ($snc->notice_date < $today) { // There are counts but not up to today
- $noticeCounts = self::fillInCounts($snc->notice_date);
- } else if ($snc->notice_date == $today) { // Refresh today's
- $noticeCounts[$today] = self::updateToday();
- }
-
- // starts with second-to-last date
-
- while ($snc->fetch()) {
- $noticeCounts[$snc->notice_date] = $snc->notice_count;
- }
-
- // Cache notice counts for 4 hours.
-
- self::cacheSet('sitemap:notice:counts', $noticeCounts, null, time() + 4 * 60 * 60);
- }
-
- return $noticeCounts;
- }
-
- static function initializeCounts()
- {
- $firstDate = self::getFirstDate(); // awww
- $today = self::today();
-
- $counts = array();
-
- for ($d = $firstDate; $d <= $today; $d = self::incrementDay($d)) {
- $n = self::getCount($d);
- self::insertCount($d, $n);
- $counts[$d] = $n;
- }
-
- return $counts;
- }
-
- static function fillInCounts($lastDate)
- {
- $today = self::today();
-
- $counts = array();
-
- $n = self::getCount($lastDate);
- self::updateCount($lastDate, $n);
-
- $counts[$lastDate] = $n;
-
- for ($d = self::incrementDay($lastDate); $d <= $today; $d = self::incrementDay($d)) {
- $n = self::getCount($d);
- self::insertCount($d, $n);
- }
-
- return $counts;
- }
-
- static function updateToday()
- {
- $today = self::today();
-
- $n = self::getCount($today);
- self::updateCount($today, $n);
-
- return $n;
- }
-
- static function getCount($d)
- {
- $notice = new Notice();
- $notice->whereAdd('created BETWEEN "'.$d.' 00:00:00" AND "'.self::incrementDay($d).' 00:00:00"');
- $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
- $n = $notice->count();
-
- return $n;
- }
-
- static function insertCount($d, $n)
- {
- $snc = new Sitemap_notice_count();
-
- $snc->notice_date = DB_DataObject_Cast::date($d);
-
- $snc->notice_count = $n;
- $snc->created = common_sql_now();
- $snc->modified = $snc->created;
-
- if (!$snc->insert()) {
- common_log(LOG_WARNING, "Could not save user counts for '$d'");
- }
- }
-
- static function updateCount($d, $n)
- {
- $snc = Sitemap_notice_count::getKV('notice_date', DB_DataObject_Cast::date($d));
-
- if (empty($snc)) {
- // TRANS: Exception
- throw new Exception(_m("No such registration date: $d."));
- }
-
- $orig = clone($snc);
-
- $snc->notice_date = DB_DataObject_Cast::date($d);
-
- $snc->notice_count = $n;
- $snc->created = common_sql_now();
- $snc->modified = $snc->created;
-
- if (!$snc->update($orig)) {
- common_log(LOG_WARNING, "Could not save user counts for '$d'");
- }
- }
-
- static function incrementDay($d)
- {
- $dt = self::dateStrToInt($d);
- return self::dateIntToStr($dt + 24 * 60 * 60);
- }
-
- static function dateStrToInt($d)
- {
- return strtotime($d.' 00:00:00');
- }
-
- static function dateIntToStr($dt)
- {
- return date('Y-m-d', $dt);
- }
-
- static function getFirstDate()
- {
- $n = new Notice();
-
- $n->selectAdd();
- $n->selectAdd('date(min(created)) as first_date');
-
- if ($n->find(true)) {
- return $n->first_date;
- } else {
- // Is this right?
- return self::dateIntToStr(time());
- }
- }
-
- static function today()
- {
- return self::dateIntToStr(time());
- }
-}
+++ /dev/null
-<?php
-/**
- * Data class for counting user registrations by date
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for counting users by date
- *
- * We make a separate sitemap for each user registered by date.
- * To save ourselves some processing effort, we cache this data
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Sitemap_user_count extends Managed_DataObject
-{
- public $__table = 'sitemap_user_count'; // table name
-
- public $registration_date; // date primary_key not_null
- public $user_count; // int(4)
- public $created; // datetime() not_null
- public $modified; // datetime not_null default_0000-00-00%2000%3A00%3A00
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'registration_date' => array('type' => 'date', 'not null' => true, 'description' => 'record date'),
- 'user_count' => array('type' => 'int', 'not null' => true, 'description' => 'the user count of the recorded date'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('registration_date'),
- );
- }
-
- static function getAll()
- {
- $userCounts = self::cacheGet('sitemap:user:counts');
-
- if ($userCounts === false) {
-
- $suc = new Sitemap_user_count();
- $suc->orderBy('registration_date DESC');
-
- // Fetch the first one to check up-to-date-itude
-
- $n = $suc->find(true);
-
- $today = self::today();
- $userCounts = array();
-
- if (!$n) { // No counts saved yet
- $userCounts = self::initializeCounts();
- } else if ($suc->registration_date < $today) { // There are counts but not up to today
- $userCounts = self::fillInCounts($suc->registration_date);
- } else if ($suc->registration_date == $today) { // Refresh today's
- $userCounts[$today] = self::updateToday();
- }
-
- // starts with second-to-last date
-
- while ($suc->fetch()) {
- $userCounts[$suc->registration_date] = $suc->user_count;
- }
-
- // Cache user counts for 4 hours.
-
- self::cacheSet('sitemap:user:counts', $userCounts, null, time() + 4 * 60 * 60);
- }
-
- return $userCounts;
- }
-
- static function initializeCounts()
- {
- $firstDate = self::getFirstDate(); // awww
- $today = self::today();
-
- $counts = array();
-
- for ($d = $firstDate; $d <= $today; $d = self::incrementDay($d)) {
- $n = self::getCount($d);
- self::insertCount($d, $n);
- $counts[$d] = $n;
- }
-
- return $counts;
- }
-
- static function fillInCounts($lastDate)
- {
- $today = self::today();
-
- $counts = array();
-
- $n = self::getCount($lastDate);
- self::updateCount($lastDate, $n);
-
- $counts[$lastDate] = $n;
-
- for ($d = self::incrementDay($lastDate); $d <= $today; $d = self::incrementDay($d)) {
- $n = self::getCount($d);
- self::insertCount($d, $n);
- }
-
- return $counts;
- }
-
- static function updateToday()
- {
- $today = self::today();
-
- $n = self::getCount($today);
- self::updateCount($today, $n);
-
- return $n;
- }
-
- static function getCount($d)
- {
- $user = new User();
- $user->whereAdd('created BETWEEN "'.$d.' 00:00:00" AND "'.self::incrementDay($d).' 00:00:00"');
- $n = $user->count();
-
- return $n;
- }
-
- static function insertCount($d, $n)
- {
- $suc = new Sitemap_user_count();
-
- $suc->registration_date = DB_DataObject_Cast::date($d);
- $suc->user_count = $n;
- $suc->created = common_sql_now();
- $suc->modified = $suc->created;
-
- if (!$suc->insert()) {
- common_log(LOG_WARNING, "Could not save user counts for '$d'");
- }
- }
-
- static function updateCount($d, $n)
- {
- $suc = Sitemap_user_count::getKV('registration_date', DB_DataObject_Cast::date($d));
-
- if (empty($suc)) {
- // TRANS: Exception thrown when a registration date cannot be found.
- throw new Exception(_m("No such registration date: $d."));
- }
-
- $orig = clone($suc);
-
- $suc->registration_date = DB_DataObject_Cast::date($d);
- $suc->user_count = $n;
- $suc->created = common_sql_now();
- $suc->modified = $suc->created;
-
- if (!$suc->update($orig)) {
- common_log(LOG_WARNING, "Could not save user counts for '$d'");
- }
- }
-
- static function incrementDay($d)
- {
- $dt = self::dateStrToInt($d);
- return self::dateIntToStr($dt + 24 * 60 * 60);
- }
-
- static function dateStrToInt($d)
- {
- return strtotime($d.' 00:00:00');
- }
-
- static function dateIntToStr($dt)
- {
- return date('Y-m-d', $dt);
- }
-
- static function getFirstDate()
- {
- $u = new User();
- $u->selectAdd();
- $u->selectAdd('date(min(created)) as first_date');
- if ($u->find(true)) {
- return $u->first_date;
- } else {
- // Is this right?
- return self::dateIntToStr(time());
- }
- }
-
- static function today()
- {
- return self::dateIntToStr(time());
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show list of user pages
+ *
+ * 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 Sitemap
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * sitemap for users
+ *
+ * @category Sitemap
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class NoticesitemapAction extends SitemapAction
+{
+ var $notices = null;
+ var $j = 0;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $y = $this->trimmed('year');
+
+ $m = $this->trimmed('month');
+ $d = $this->trimmed('day');
+
+ $i = $this->trimmed('index');
+
+ $y += 0;
+ $m += 0;
+ $d += 0;
+ $i += 0;
+
+ $this->notices = $this->getNotices($y, $m, $d, $i);
+ $this->j = 0;
+
+ return true;
+ }
+
+ function nextUrl()
+ {
+ if ($this->j < count($this->notices)) {
+ $n = $this->notices[$this->j];
+ $this->j++;
+ return array(common_local_url('shownotice', array('notice' => $n[0])),
+ common_date_w3dtf($n[1]),
+ 'never',
+ null);
+ } else {
+ return null;
+ }
+ }
+
+ function getNotices($y, $m, $d, $i)
+ {
+ $n = Notice::cacheGet("sitemap:notice:$y:$m:$d:$i");
+
+ if ($n === false) {
+
+ $notice = new Notice();
+
+ $begindt = sprintf('%04d-%02d-%02d 00:00:00', $y, $m, $d);
+
+ // XXX: estimates 1d == 24h, which screws up days
+ // with leap seconds (1d == 24h + 1s). Thankfully they're
+ // few and far between.
+
+ $theend = strtotime($begindt) + (24 * 60 * 60);
+ $enddt = common_sql_date($theend);
+
+ $notice->selectAdd();
+ $notice->selectAdd('id, created');
+
+ $notice->whereAdd("created >= '$begindt'");
+ $notice->whereAdd("created < '$enddt'");
+
+ $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
+
+ $notice->orderBy('created');
+
+ $offset = ($i-1) * SitemapPlugin::NOTICES_PER_MAP;
+ $limit = SitemapPlugin::NOTICES_PER_MAP;
+
+ $notice->limit($offset, $limit);
+
+ $notice->find();
+
+ $n = array();
+
+ while ($notice->fetch()) {
+ $n[] = array($notice->id, $notice->created);
+ }
+
+ $c = Cache::instance();
+
+ if (!empty($c)) {
+ $c->set(Cache::key("sitemap:notice:$y:$m:$d:$i"),
+ $n,
+ Cache::COMPRESSED,
+ ((time() > $theend) ? (time() + 90 * 24 * 60 * 60) : (time() + 5 * 60)));
+ }
+ }
+
+ return $n;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Superclass for sitemap-generating actions
+ *
+ * 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 Sitemap
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * superclass for sitemap actions
+ *
+ * @category Sitemap
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class SitemapAction extends Action
+{
+ /**
+ * handle the action
+ *
+ * @param array $args unused.
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ header('Content-Type: text/xml; charset=UTF-8');
+ $this->startXML();
+
+ $this->elementStart('urlset', array('xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9'));
+
+ while (list($url, $lm, $cf, $p) = $this->nextUrl()) {
+ $this->showUrl($url, $lm, $cf, $p);
+ }
+
+ $this->elementEnd('urlset');
+
+ $this->endXML();
+ }
+
+ function lastModified()
+ {
+ $y = $this->trimmed('year');
+
+ $m = $this->trimmed('month');
+ $d = $this->trimmed('day');
+
+ $y += 0;
+ $m += 0;
+ $d += 0;
+
+ $begdate = strtotime("$y-$m-$d 00:00:00");
+ $enddate = $begdate + (24 * 60 * 60);
+
+ if ($enddate < time()) {
+ return $enddate;
+ } else {
+ return null;
+ }
+ }
+
+ function showUrl($url, $lastMod=null, $changeFreq=null, $priority=null)
+ {
+ $this->elementStart('url');
+ $this->element('loc', null, $url);
+ if (!is_null($lastMod)) {
+ $this->element('lastmod', null, $lastMod);
+ }
+ if (!is_null($changeFreq)) {
+ $this->element('changefreq', null, $changeFreq);
+ }
+ if (!is_null($priority)) {
+ $this->element('priority', null, $priority);
+ }
+ $this->elementEnd('url');
+ }
+
+ function nextUrl()
+ {
+ return null;
+ }
+
+ function isReadOnly()
+ {
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Sitemap administration panel
+ *
+ * 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 Sitemap
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Administer sitemap settings
+ *
+ * @category Sitemap
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class SitemapadminpanelAction extends AdminPanelAction
+{
+ /**
+ * Returns the page title
+ *
+ * @return string page title
+ */
+ function title()
+ {
+ // TRANS: Title for sitemap.
+ return _m('Sitemap');
+ }
+
+ /**
+ * Instructions for using this form.
+ *
+ * @return string instructions
+ */
+ function getInstructions()
+ {
+ // TRANS: Instructions for sitemap.
+ return _m('Sitemap settings for this StatusNet site');
+ }
+
+ /**
+ * Show the site admin panel form
+ *
+ * @return void
+ */
+ function showForm()
+ {
+ $form = new SitemapAdminPanelForm($this);
+ $form->show();
+ return;
+ }
+
+ /**
+ * Save settings from the form
+ *
+ * @return void
+ */
+ function saveSettings()
+ {
+ static $settings = array('sitemap' => array('googlekey', 'yahookey', 'bingkey'));
+
+ $values = array();
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ $values[$section][$setting] = $this->trimmed($setting);
+ }
+ }
+
+ // This throws an exception on validation errors
+ $this->validate($values);
+
+ // assert(all values are valid);
+
+ $config = new Config();
+
+ $config->query('BEGIN');
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ Config::save($section, $setting, $values[$section][$setting]);
+ }
+ }
+
+ $config->query('COMMIT');
+
+ return;
+ }
+
+ function validate(&$values)
+ {
+ }
+}
+
+/**
+ * Form for the sitemap admin panel
+ */
+class SitemapAdminPanelForm extends AdminForm
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'form_sitemap_admin_panel';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_sitemap';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('sitemapadminpanel');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('ul', 'form_data');
+ $this->li();
+ $this->input('googlekey',
+ // TRANS: Field label.
+ _m('Google key'),
+ // TRANS: Title for field label.
+ _m('Google Webmaster Tools verification key.'),
+ 'sitemap');
+ $this->unli();
+ $this->li();
+ $this->input('yahookey',
+ // TRANS: Field label.
+ _m('Yahoo key'),
+ // TRANS: Title for field label.
+ _m('Yahoo! Site Explorer verification key.'),
+ 'sitemap');
+ $this->unli();
+ $this->li();
+ $this->input('bingkey',
+ // TRANS: Field label.
+ _m('Bing key'),
+ // TRANS: Title for field label.
+ _m('Bing Webmaster Tools verification key.'),
+ 'sitemap');
+ $this->unli();
+ $this->out->elementEnd('ul');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ $this->out->submit('submit',
+ // TRANS: Submit button text to save sitemap settings.
+ _m('BUTTON','Save'),
+ 'submit',
+ null,
+ // TRANS: Submit button title to save sitemap settings.
+ _m('Save sitemap settings.'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Generate sitemap index
+ *
+ * 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 Sitemap
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Show the sitemap index
+ *
+ * @category Sitemap
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class SitemapindexAction extends Action
+{
+ /**
+ * handle the action
+ *
+ * @param array $args unused.
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ header('Content-Type: text/xml; charset=UTF-8');
+ $this->startXML();
+
+ $this->elementStart('sitemapindex', array('xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9'));
+
+ $this->showNoticeSitemaps();
+ $this->showUserSitemaps();
+
+ $this->elementEnd('sitemapindex');
+
+ $this->endXML();
+ }
+
+ function showUserSitemaps()
+ {
+ $userCounts = Sitemap_user_count::getAll();
+
+ foreach ($userCounts as $dt => $cnt) {
+ $cnt = $cnt+0;
+
+ if ($cnt == 0) {
+ continue;
+ }
+
+ $n = (int)$cnt / (int)SitemapPlugin::USERS_PER_MAP;
+ if (($cnt % SitemapPlugin::USERS_PER_MAP) != 0) {
+ $n++;
+ }
+ for ($i = 1; $i <= $n; $i++) {
+ $this->showSitemap('user', $dt, $i);
+ }
+ }
+ }
+
+ function showNoticeSitemaps()
+ {
+ $noticeCounts = Sitemap_notice_count::getAll();
+
+ foreach ($noticeCounts as $dt => $cnt) {
+ if ($cnt == 0) {
+ continue;
+ }
+ $n = $cnt / SitemapPlugin::NOTICES_PER_MAP;
+ if ($cnt % SitemapPlugin::NOTICES_PER_MAP) {
+ $n++;
+ }
+ for ($i = 1; $i <= $n; $i++) {
+ $this->showSitemap('notice', $dt, $i);
+ }
+ }
+ }
+
+ function showSitemap($prefix, $dt, $i)
+ {
+ list($y, $m, $d) = explode('-', $dt);
+
+ $this->elementStart('sitemap');
+ $this->element('loc', null, common_local_url($prefix.'sitemap',
+ array('year' => $y,
+ 'month' => $m,
+ 'day' => $d,
+ 'index' => $i)));
+
+ $begdate = strtotime("$y-$m-$d 00:00:00");
+ $enddate = $begdate + (24 * 60 * 60);
+
+ if ($enddate < time()) {
+ $this->element('lastmod', null, date(DATE_W3C, $enddate));
+ }
+
+ $this->elementEnd('sitemap');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show list of user pages
+ *
+ * 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 Sitemap
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * sitemap for users
+ *
+ * @category Sitemap
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class UsersitemapAction extends SitemapAction
+{
+ var $users = null;
+ var $j = 0;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $y = $this->trimmed('year');
+
+ $m = $this->trimmed('month');
+ $d = $this->trimmed('day');
+
+ $i = $this->trimmed('index');
+
+ $y += 0;
+ $m += 0;
+ $d += 0;
+ $i += 0;
+
+ $this->users = $this->getUsers($y, $m, $d, $i);
+ $this->j = 0;
+ return true;
+ }
+
+ function nextUrl()
+ {
+ if ($this->j < count($this->users)) {
+ $nickname = $this->users[$this->j];
+ $this->j++;
+ return array(common_profile_url($nickname), null, null, '1.0');
+ } else {
+ return null;
+ }
+ }
+
+ function getUsers($y, $m, $d, $i)
+ {
+ $u = User::cacheGet("sitemap:user:$y:$m:$d:$i");
+
+ if ($u === false) {
+
+ $user = new User();
+
+ $begindt = sprintf('%04d-%02d-%02d 00:00:00', $y, $m, $d);
+
+ // XXX: estimates 1d == 24h, which screws up days
+ // with leap seconds (1d == 24h + 1s). Thankfully they're
+ // few and far between.
+
+ $theend = strtotime($begindt) + (24 * 60 * 60);
+ $enddt = common_sql_date($theend);
+
+ $user->selectAdd();
+ $user->selectAdd('nickname');
+ $user->whereAdd("created >= '$begindt'");
+ $user->whereAdd("created < '$enddt'");
+
+ $user->orderBy('created');
+
+ $offset = ($i-1) * SitemapPlugin::USERS_PER_MAP;
+ $limit = SitemapPlugin::USERS_PER_MAP;
+
+ $user->limit($offset, $limit);
+
+ $user->find();
+
+ while ($user->fetch()) {
+ $u[] = $user->nickname;
+ }
+
+ $c = Cache::instance();
+
+ if (!empty($c)) {
+ $c->set(Cache::key("sitemap:user:$y:$m:$d:$i"),
+ $u,
+ Cache::COMPRESSED,
+ ((time() > $theend) ? (time() + 90 * 24 * 60 * 60) : (time() + 5 * 60)));
+ }
+ }
+
+ return $u;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class for counting notice postings by date
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for counting notices by date
+ *
+ * We make a separate sitemap for each notice posted by date.
+ * To save ourselves some (not inconsiderable) processing effort,
+ * we cache this data in the sitemap_notice_count table. Each
+ * row represents a day since the site has been started, with a count
+ * of notices posted on that day. Since, after the end of the day,
+ * this number doesn't change, it's a good candidate for persistent caching.
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Sitemap_notice_count extends Managed_DataObject
+{
+ public $__table = 'sitemap_notice_count'; // table name
+
+ public $notice_date; // date primary_key not_null
+ public $notice_count; // int(4)
+ public $created; // datetime() not_null
+ public $modified; // datetime not_null default_0000-00-00%2000%3A00%3A00
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'notice_date' => array('type' => 'date', 'not null' => true, 'description' => 'record date'),
+ 'notice_count' => array('type' => 'int', 'not null' => true, 'description' => 'the notice count'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('notice_date'),
+ );
+ }
+
+ static function getAll()
+ {
+ $noticeCounts = self::cacheGet('sitemap:notice:counts');
+
+ if ($noticeCounts === false) {
+ $snc = new Sitemap_notice_count();
+ $snc->orderBy('notice_date DESC');
+
+ // Fetch the first one to check up-to-date-itude
+
+ $n = $snc->find(true);
+
+ $today = self::today();
+ $noticeCounts = array();
+
+ if (!$n) { // No counts saved yet
+ $noticeCounts = self::initializeCounts();
+ } else if ($snc->notice_date < $today) { // There are counts but not up to today
+ $noticeCounts = self::fillInCounts($snc->notice_date);
+ } else if ($snc->notice_date == $today) { // Refresh today's
+ $noticeCounts[$today] = self::updateToday();
+ }
+
+ // starts with second-to-last date
+
+ while ($snc->fetch()) {
+ $noticeCounts[$snc->notice_date] = $snc->notice_count;
+ }
+
+ // Cache notice counts for 4 hours.
+
+ self::cacheSet('sitemap:notice:counts', $noticeCounts, null, time() + 4 * 60 * 60);
+ }
+
+ return $noticeCounts;
+ }
+
+ static function initializeCounts()
+ {
+ $firstDate = self::getFirstDate(); // awww
+ $today = self::today();
+
+ $counts = array();
+
+ for ($d = $firstDate; $d <= $today; $d = self::incrementDay($d)) {
+ $n = self::getCount($d);
+ self::insertCount($d, $n);
+ $counts[$d] = $n;
+ }
+
+ return $counts;
+ }
+
+ static function fillInCounts($lastDate)
+ {
+ $today = self::today();
+
+ $counts = array();
+
+ $n = self::getCount($lastDate);
+ self::updateCount($lastDate, $n);
+
+ $counts[$lastDate] = $n;
+
+ for ($d = self::incrementDay($lastDate); $d <= $today; $d = self::incrementDay($d)) {
+ $n = self::getCount($d);
+ self::insertCount($d, $n);
+ }
+
+ return $counts;
+ }
+
+ static function updateToday()
+ {
+ $today = self::today();
+
+ $n = self::getCount($today);
+ self::updateCount($today, $n);
+
+ return $n;
+ }
+
+ static function getCount($d)
+ {
+ $notice = new Notice();
+ $notice->whereAdd('created BETWEEN "'.$d.' 00:00:00" AND "'.self::incrementDay($d).' 00:00:00"');
+ $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
+ $n = $notice->count();
+
+ return $n;
+ }
+
+ static function insertCount($d, $n)
+ {
+ $snc = new Sitemap_notice_count();
+
+ $snc->notice_date = DB_DataObject_Cast::date($d);
+
+ $snc->notice_count = $n;
+ $snc->created = common_sql_now();
+ $snc->modified = $snc->created;
+
+ if (!$snc->insert()) {
+ common_log(LOG_WARNING, "Could not save user counts for '$d'");
+ }
+ }
+
+ static function updateCount($d, $n)
+ {
+ $snc = Sitemap_notice_count::getKV('notice_date', DB_DataObject_Cast::date($d));
+
+ if (empty($snc)) {
+ // TRANS: Exception
+ throw new Exception(_m("No such registration date: $d."));
+ }
+
+ $orig = clone($snc);
+
+ $snc->notice_date = DB_DataObject_Cast::date($d);
+
+ $snc->notice_count = $n;
+ $snc->created = common_sql_now();
+ $snc->modified = $snc->created;
+
+ if (!$snc->update($orig)) {
+ common_log(LOG_WARNING, "Could not save user counts for '$d'");
+ }
+ }
+
+ static function incrementDay($d)
+ {
+ $dt = self::dateStrToInt($d);
+ return self::dateIntToStr($dt + 24 * 60 * 60);
+ }
+
+ static function dateStrToInt($d)
+ {
+ return strtotime($d.' 00:00:00');
+ }
+
+ static function dateIntToStr($dt)
+ {
+ return date('Y-m-d', $dt);
+ }
+
+ static function getFirstDate()
+ {
+ $n = new Notice();
+
+ $n->selectAdd();
+ $n->selectAdd('date(min(created)) as first_date');
+
+ if ($n->find(true)) {
+ return $n->first_date;
+ } else {
+ // Is this right?
+ return self::dateIntToStr(time());
+ }
+ }
+
+ static function today()
+ {
+ return self::dateIntToStr(time());
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class for counting user registrations by date
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for counting users by date
+ *
+ * We make a separate sitemap for each user registered by date.
+ * To save ourselves some processing effort, we cache this data
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Sitemap_user_count extends Managed_DataObject
+{
+ public $__table = 'sitemap_user_count'; // table name
+
+ public $registration_date; // date primary_key not_null
+ public $user_count; // int(4)
+ public $created; // datetime() not_null
+ public $modified; // datetime not_null default_0000-00-00%2000%3A00%3A00
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'registration_date' => array('type' => 'date', 'not null' => true, 'description' => 'record date'),
+ 'user_count' => array('type' => 'int', 'not null' => true, 'description' => 'the user count of the recorded date'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('registration_date'),
+ );
+ }
+
+ static function getAll()
+ {
+ $userCounts = self::cacheGet('sitemap:user:counts');
+
+ if ($userCounts === false) {
+
+ $suc = new Sitemap_user_count();
+ $suc->orderBy('registration_date DESC');
+
+ // Fetch the first one to check up-to-date-itude
+
+ $n = $suc->find(true);
+
+ $today = self::today();
+ $userCounts = array();
+
+ if (!$n) { // No counts saved yet
+ $userCounts = self::initializeCounts();
+ } else if ($suc->registration_date < $today) { // There are counts but not up to today
+ $userCounts = self::fillInCounts($suc->registration_date);
+ } else if ($suc->registration_date == $today) { // Refresh today's
+ $userCounts[$today] = self::updateToday();
+ }
+
+ // starts with second-to-last date
+
+ while ($suc->fetch()) {
+ $userCounts[$suc->registration_date] = $suc->user_count;
+ }
+
+ // Cache user counts for 4 hours.
+
+ self::cacheSet('sitemap:user:counts', $userCounts, null, time() + 4 * 60 * 60);
+ }
+
+ return $userCounts;
+ }
+
+ static function initializeCounts()
+ {
+ $firstDate = self::getFirstDate(); // awww
+ $today = self::today();
+
+ $counts = array();
+
+ for ($d = $firstDate; $d <= $today; $d = self::incrementDay($d)) {
+ $n = self::getCount($d);
+ self::insertCount($d, $n);
+ $counts[$d] = $n;
+ }
+
+ return $counts;
+ }
+
+ static function fillInCounts($lastDate)
+ {
+ $today = self::today();
+
+ $counts = array();
+
+ $n = self::getCount($lastDate);
+ self::updateCount($lastDate, $n);
+
+ $counts[$lastDate] = $n;
+
+ for ($d = self::incrementDay($lastDate); $d <= $today; $d = self::incrementDay($d)) {
+ $n = self::getCount($d);
+ self::insertCount($d, $n);
+ }
+
+ return $counts;
+ }
+
+ static function updateToday()
+ {
+ $today = self::today();
+
+ $n = self::getCount($today);
+ self::updateCount($today, $n);
+
+ return $n;
+ }
+
+ static function getCount($d)
+ {
+ $user = new User();
+ $user->whereAdd('created BETWEEN "'.$d.' 00:00:00" AND "'.self::incrementDay($d).' 00:00:00"');
+ $n = $user->count();
+
+ return $n;
+ }
+
+ static function insertCount($d, $n)
+ {
+ $suc = new Sitemap_user_count();
+
+ $suc->registration_date = DB_DataObject_Cast::date($d);
+ $suc->user_count = $n;
+ $suc->created = common_sql_now();
+ $suc->modified = $suc->created;
+
+ if (!$suc->insert()) {
+ common_log(LOG_WARNING, "Could not save user counts for '$d'");
+ }
+ }
+
+ static function updateCount($d, $n)
+ {
+ $suc = Sitemap_user_count::getKV('registration_date', DB_DataObject_Cast::date($d));
+
+ if (empty($suc)) {
+ // TRANS: Exception thrown when a registration date cannot be found.
+ throw new Exception(_m("No such registration date: $d."));
+ }
+
+ $orig = clone($suc);
+
+ $suc->registration_date = DB_DataObject_Cast::date($d);
+ $suc->user_count = $n;
+ $suc->created = common_sql_now();
+ $suc->modified = $suc->created;
+
+ if (!$suc->update($orig)) {
+ common_log(LOG_WARNING, "Could not save user counts for '$d'");
+ }
+ }
+
+ static function incrementDay($d)
+ {
+ $dt = self::dateStrToInt($d);
+ return self::dateIntToStr($dt + 24 * 60 * 60);
+ }
+
+ static function dateStrToInt($d)
+ {
+ return strtotime($d.' 00:00:00');
+ }
+
+ static function dateIntToStr($dt)
+ {
+ return date('Y-m-d', $dt);
+ }
+
+ static function getFirstDate()
+ {
+ $u = new User();
+ $u->selectAdd();
+ $u->selectAdd('date(min(created)) as first_date');
+ if ($u->find(true)) {
+ return $u->first_date;
+ } else {
+ // Is this right?
+ return self::dateIntToStr(time());
+ }
+ }
+
+ static function today()
+ {
+ return self::dateIntToStr(time());
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Show list of user pages
- *
- * 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 Sitemap
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * sitemap for users
- *
- * @category Sitemap
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class NoticesitemapAction extends SitemapAction
-{
- var $notices = null;
- var $j = 0;
-
- function prepare($args)
- {
- parent::prepare($args);
-
- $y = $this->trimmed('year');
-
- $m = $this->trimmed('month');
- $d = $this->trimmed('day');
-
- $i = $this->trimmed('index');
-
- $y += 0;
- $m += 0;
- $d += 0;
- $i += 0;
-
- $this->notices = $this->getNotices($y, $m, $d, $i);
- $this->j = 0;
-
- return true;
- }
-
- function nextUrl()
- {
- if ($this->j < count($this->notices)) {
- $n = $this->notices[$this->j];
- $this->j++;
- return array(common_local_url('shownotice', array('notice' => $n[0])),
- common_date_w3dtf($n[1]),
- 'never',
- null);
- } else {
- return null;
- }
- }
-
- function getNotices($y, $m, $d, $i)
- {
- $n = Notice::cacheGet("sitemap:notice:$y:$m:$d:$i");
-
- if ($n === false) {
-
- $notice = new Notice();
-
- $begindt = sprintf('%04d-%02d-%02d 00:00:00', $y, $m, $d);
-
- // XXX: estimates 1d == 24h, which screws up days
- // with leap seconds (1d == 24h + 1s). Thankfully they're
- // few and far between.
-
- $theend = strtotime($begindt) + (24 * 60 * 60);
- $enddt = common_sql_date($theend);
-
- $notice->selectAdd();
- $notice->selectAdd('id, created');
-
- $notice->whereAdd("created >= '$begindt'");
- $notice->whereAdd("created < '$enddt'");
-
- $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
-
- $notice->orderBy('created');
-
- $offset = ($i-1) * SitemapPlugin::NOTICES_PER_MAP;
- $limit = SitemapPlugin::NOTICES_PER_MAP;
-
- $notice->limit($offset, $limit);
-
- $notice->find();
-
- $n = array();
-
- while ($notice->fetch()) {
- $n[] = array($notice->id, $notice->created);
- }
-
- $c = Cache::instance();
-
- if (!empty($c)) {
- $c->set(Cache::key("sitemap:notice:$y:$m:$d:$i"),
- $n,
- Cache::COMPRESSED,
- ((time() > $theend) ? (time() + 90 * 24 * 60 * 60) : (time() + 5 * 60)));
- }
- }
-
- return $n;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Superclass for sitemap-generating actions
- *
- * 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 Sitemap
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * superclass for sitemap actions
- *
- * @category Sitemap
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class SitemapAction extends Action
-{
- /**
- * handle the action
- *
- * @param array $args unused.
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- header('Content-Type: text/xml; charset=UTF-8');
- $this->startXML();
-
- $this->elementStart('urlset', array('xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9'));
-
- while (list($url, $lm, $cf, $p) = $this->nextUrl()) {
- $this->showUrl($url, $lm, $cf, $p);
- }
-
- $this->elementEnd('urlset');
-
- $this->endXML();
- }
-
- function lastModified()
- {
- $y = $this->trimmed('year');
-
- $m = $this->trimmed('month');
- $d = $this->trimmed('day');
-
- $y += 0;
- $m += 0;
- $d += 0;
-
- $begdate = strtotime("$y-$m-$d 00:00:00");
- $enddate = $begdate + (24 * 60 * 60);
-
- if ($enddate < time()) {
- return $enddate;
- } else {
- return null;
- }
- }
-
- function showUrl($url, $lastMod=null, $changeFreq=null, $priority=null)
- {
- $this->elementStart('url');
- $this->element('loc', null, $url);
- if (!is_null($lastMod)) {
- $this->element('lastmod', null, $lastMod);
- }
- if (!is_null($changeFreq)) {
- $this->element('changefreq', null, $changeFreq);
- }
- if (!is_null($priority)) {
- $this->element('priority', null, $priority);
- }
- $this->elementEnd('url');
- }
-
- function nextUrl()
- {
- return null;
- }
-
- function isReadOnly()
- {
- return true;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Sitemap administration panel
- *
- * 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 Sitemap
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Administer sitemap settings
- *
- * @category Sitemap
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class SitemapadminpanelAction extends AdminPanelAction
-{
- /**
- * Returns the page title
- *
- * @return string page title
- */
- function title()
- {
- // TRANS: Title for sitemap.
- return _m('Sitemap');
- }
-
- /**
- * Instructions for using this form.
- *
- * @return string instructions
- */
- function getInstructions()
- {
- // TRANS: Instructions for sitemap.
- return _m('Sitemap settings for this StatusNet site');
- }
-
- /**
- * Show the site admin panel form
- *
- * @return void
- */
- function showForm()
- {
- $form = new SitemapAdminPanelForm($this);
- $form->show();
- return;
- }
-
- /**
- * Save settings from the form
- *
- * @return void
- */
- function saveSettings()
- {
- static $settings = array('sitemap' => array('googlekey', 'yahookey', 'bingkey'));
-
- $values = array();
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- $values[$section][$setting] = $this->trimmed($setting);
- }
- }
-
- // This throws an exception on validation errors
- $this->validate($values);
-
- // assert(all values are valid);
-
- $config = new Config();
-
- $config->query('BEGIN');
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- Config::save($section, $setting, $values[$section][$setting]);
- }
- }
-
- $config->query('COMMIT');
-
- return;
- }
-
- function validate(&$values)
- {
- }
-}
-
-/**
- * Form for the sitemap admin panel
- */
-class SitemapAdminPanelForm extends AdminForm
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'form_sitemap_admin_panel';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_sitemap';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('sitemapadminpanel');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('ul', 'form_data');
- $this->li();
- $this->input('googlekey',
- // TRANS: Field label.
- _m('Google key'),
- // TRANS: Title for field label.
- _m('Google Webmaster Tools verification key.'),
- 'sitemap');
- $this->unli();
- $this->li();
- $this->input('yahookey',
- // TRANS: Field label.
- _m('Yahoo key'),
- // TRANS: Title for field label.
- _m('Yahoo! Site Explorer verification key.'),
- 'sitemap');
- $this->unli();
- $this->li();
- $this->input('bingkey',
- // TRANS: Field label.
- _m('Bing key'),
- // TRANS: Title for field label.
- _m('Bing Webmaster Tools verification key.'),
- 'sitemap');
- $this->unli();
- $this->out->elementEnd('ul');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- $this->out->submit('submit',
- // TRANS: Submit button text to save sitemap settings.
- _m('BUTTON','Save'),
- 'submit',
- null,
- // TRANS: Submit button title to save sitemap settings.
- _m('Save sitemap settings.'));
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Generate sitemap index
- *
- * 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 Sitemap
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Show the sitemap index
- *
- * @category Sitemap
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class SitemapindexAction extends Action
-{
- /**
- * handle the action
- *
- * @param array $args unused.
- *
- * @return void
- */
- function handle($args)
- {
- header('Content-Type: text/xml; charset=UTF-8');
- $this->startXML();
-
- $this->elementStart('sitemapindex', array('xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9'));
-
- $this->showNoticeSitemaps();
- $this->showUserSitemaps();
-
- $this->elementEnd('sitemapindex');
-
- $this->endXML();
- }
-
- function showUserSitemaps()
- {
- $userCounts = Sitemap_user_count::getAll();
-
- foreach ($userCounts as $dt => $cnt) {
- $cnt = $cnt+0;
-
- if ($cnt == 0) {
- continue;
- }
-
- $n = (int)$cnt / (int)SitemapPlugin::USERS_PER_MAP;
- if (($cnt % SitemapPlugin::USERS_PER_MAP) != 0) {
- $n++;
- }
- for ($i = 1; $i <= $n; $i++) {
- $this->showSitemap('user', $dt, $i);
- }
- }
- }
-
- function showNoticeSitemaps()
- {
- $noticeCounts = Sitemap_notice_count::getAll();
-
- foreach ($noticeCounts as $dt => $cnt) {
- if ($cnt == 0) {
- continue;
- }
- $n = $cnt / SitemapPlugin::NOTICES_PER_MAP;
- if ($cnt % SitemapPlugin::NOTICES_PER_MAP) {
- $n++;
- }
- for ($i = 1; $i <= $n; $i++) {
- $this->showSitemap('notice', $dt, $i);
- }
- }
- }
-
- function showSitemap($prefix, $dt, $i)
- {
- list($y, $m, $d) = explode('-', $dt);
-
- $this->elementStart('sitemap');
- $this->element('loc', null, common_local_url($prefix.'sitemap',
- array('year' => $y,
- 'month' => $m,
- 'day' => $d,
- 'index' => $i)));
-
- $begdate = strtotime("$y-$m-$d 00:00:00");
- $enddate = $begdate + (24 * 60 * 60);
-
- if ($enddate < time()) {
- $this->element('lastmod', null, date(DATE_W3C, $enddate));
- }
-
- $this->elementEnd('sitemap');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Show list of user pages
- *
- * 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 Sitemap
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * sitemap for users
- *
- * @category Sitemap
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class UsersitemapAction extends SitemapAction
-{
- var $users = null;
- var $j = 0;
-
- function prepare($args)
- {
- parent::prepare($args);
-
- $y = $this->trimmed('year');
-
- $m = $this->trimmed('month');
- $d = $this->trimmed('day');
-
- $i = $this->trimmed('index');
-
- $y += 0;
- $m += 0;
- $d += 0;
- $i += 0;
-
- $this->users = $this->getUsers($y, $m, $d, $i);
- $this->j = 0;
- return true;
- }
-
- function nextUrl()
- {
- if ($this->j < count($this->users)) {
- $nickname = $this->users[$this->j];
- $this->j++;
- return array(common_profile_url($nickname), null, null, '1.0');
- } else {
- return null;
- }
- }
-
- function getUsers($y, $m, $d, $i)
- {
- $u = User::cacheGet("sitemap:user:$y:$m:$d:$i");
-
- if ($u === false) {
-
- $user = new User();
-
- $begindt = sprintf('%04d-%02d-%02d 00:00:00', $y, $m, $d);
-
- // XXX: estimates 1d == 24h, which screws up days
- // with leap seconds (1d == 24h + 1s). Thankfully they're
- // few and far between.
-
- $theend = strtotime($begindt) + (24 * 60 * 60);
- $enddt = common_sql_date($theend);
-
- $user->selectAdd();
- $user->selectAdd('nickname');
- $user->whereAdd("created >= '$begindt'");
- $user->whereAdd("created < '$enddt'");
-
- $user->orderBy('created');
-
- $offset = ($i-1) * SitemapPlugin::USERS_PER_MAP;
- $limit = SitemapPlugin::USERS_PER_MAP;
-
- $user->limit($offset, $limit);
-
- $user->find();
-
- while ($user->fetch()) {
- $u[] = $user->nickname;
- }
-
- $c = Cache::instance();
-
- if (!empty($c)) {
- $c->set(Cache::key("sitemap:user:$y:$m:$d:$i"),
- $u,
- Cache::COMPRESSED,
- ((time() > $theend) ? (time() + 90 * 24 * 60 * 60) : (time() + 5 * 60)));
- }
- }
-
- return $u;
- }
-}
return true;
}
- /**
- * Automatically load the actions and libraries used by the plugin
- *
- * @param Class $cls the class
- *
- * @return boolean hook return
- *
- */
- function onAutoload($cls)
- {
- $base = dirname(__FILE__);
- $lower = strtolower($cls);
- switch ($lower) {
- case 'favoritedsliceaction':
- require_once "$base/$lower.php";
- return false;
- default:
- return true;
- }
- }
-
function onSlicedFavoritesGetSettings($slice, &$data)
{
if (isset($this->slices[$slice])) {
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List of popular notices
+ *
+ * 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 Public
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class FavoritedSliceAction extends FavoritedAction
+{
+ private $includeUsers = array(), $excludeUsers = array();
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ * @todo move queries from showContent() to here
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->slice = $this->arg('slice', 'default');
+ $data = array();
+ if (Event::handle('SlicedFavoritesGetSettings', array($this->slice, &$data))) {
+ // TRANS: Client exception.
+ throw new ClientException(_m('Unknown favorites slice.'));
+ }
+ if (isset($data['include'])) {
+ $this->includeUsers = $data['include'];
+ }
+ if (isset($data['exclude'])) {
+ $this->excludeUsers = $data['exclude'];
+ }
+
+ return true;
+ }
+
+ /**
+ * Content area
+ *
+ * Shows the list of popular notices
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $slice = $this->sliceWhereClause();
+ if (!$slice) {
+ return parent::showContent();
+ }
+
+ $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
+ $cutoff = sprintf("fave.modified > '%s'",
+ common_sql_date(time() - common_config('popular', 'cutoff')));
+
+ $qry = 'SELECT notice.*, '.
+ $weightexpr . ' as weight ' .
+ 'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
+ "WHERE $cutoff AND $slice " .
+ 'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' .
+ 'ORDER BY weight DESC';
+
+ $offset = ($this->page - 1) * NOTICES_PER_PAGE;
+ $limit = NOTICES_PER_PAGE + 1;
+
+ if (common_config('db', 'type') == 'pgsql') {
+ $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
+ } else {
+ $qry .= ' LIMIT ' . $offset . ', ' . $limit;
+ }
+
+ $notice = Memcached_DataObject::cachedQuery('Notice',
+ $qry,
+ 600);
+
+ $nl = new NoticeList($notice, $this);
+
+ $cnt = $nl->show();
+
+ if ($cnt == 0) {
+ $this->showEmptyList();
+ }
+
+ $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
+ $this->page, 'favorited');
+ }
+
+ private function sliceWhereClause()
+ {
+ $include = $this->nicknamesToIds($this->includeUsers);
+ $exclude = $this->nicknamesToIds($this->excludeUsers);
+
+ if (count($include) == 1) {
+ return "profile_id = " . intval($include[0]);
+ } else if (count($include) > 1) {
+ return "profile_id IN (" . implode(',', $include) . ")";
+ } else if (count($exclude) == 1) {
+ return "profile_id != " . intval($exclude[0]);
+ } else if (count($exclude) > 1) {
+ return "profile_id NOT IN (" . implode(',', $exclude) . ")";
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ *
+ * @param array $nicks array of user nicknames
+ * @return array of profile/user IDs
+ */
+ private function nicknamesToIds($nicks)
+ {
+ $ids = array();
+ foreach ($nicks as $nick) {
+ // not the most efficient way for a big list!
+ $user = User::getKV('nickname', $nick);
+ if ($user) {
+ $ids[] = intval($user->id);
+ }
+ }
+ return $ids;
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * List of popular notices
- *
- * 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 Public
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-class FavoritedSliceAction extends FavoritedAction
-{
- private $includeUsers = array(), $excludeUsers = array();
-
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- *
- * @todo move queries from showContent() to here
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $this->slice = $this->arg('slice', 'default');
- $data = array();
- if (Event::handle('SlicedFavoritesGetSettings', array($this->slice, &$data))) {
- // TRANS: Client exception.
- throw new ClientException(_m('Unknown favorites slice.'));
- }
- if (isset($data['include'])) {
- $this->includeUsers = $data['include'];
- }
- if (isset($data['exclude'])) {
- $this->excludeUsers = $data['exclude'];
- }
-
- return true;
- }
-
- /**
- * Content area
- *
- * Shows the list of popular notices
- *
- * @return void
- */
- function showContent()
- {
- $slice = $this->sliceWhereClause();
- if (!$slice) {
- return parent::showContent();
- }
-
- $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
- $cutoff = sprintf("fave.modified > '%s'",
- common_sql_date(time() - common_config('popular', 'cutoff')));
-
- $qry = 'SELECT notice.*, '.
- $weightexpr . ' as weight ' .
- 'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
- "WHERE $cutoff AND $slice " .
- 'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' .
- 'ORDER BY weight DESC';
-
- $offset = ($this->page - 1) * NOTICES_PER_PAGE;
- $limit = NOTICES_PER_PAGE + 1;
-
- if (common_config('db', 'type') == 'pgsql') {
- $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
- } else {
- $qry .= ' LIMIT ' . $offset . ', ' . $limit;
- }
-
- $notice = Memcached_DataObject::cachedQuery('Notice',
- $qry,
- 600);
-
- $nl = new NoticeList($notice, $this);
-
- $cnt = $nl->show();
-
- if ($cnt == 0) {
- $this->showEmptyList();
- }
-
- $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
- $this->page, 'favorited');
- }
-
- private function sliceWhereClause()
- {
- $include = $this->nicknamesToIds($this->includeUsers);
- $exclude = $this->nicknamesToIds($this->excludeUsers);
-
- if (count($include) == 1) {
- return "profile_id = " . intval($include[0]);
- } else if (count($include) > 1) {
- return "profile_id IN (" . implode(',', $include) . ")";
- } else if (count($exclude) == 1) {
- return "profile_id != " . intval($exclude[0]);
- } else if (count($exclude) > 1) {
- return "profile_id NOT IN (" . implode(',', $exclude) . ")";
- } else {
- return false;
- }
- }
-
- /**
- *
- * @param array $nicks array of user nicknames
- * @return array of profile/user IDs
- */
- private function nicknamesToIds($nicks)
- {
- $ids = array();
- foreach ($nicks as $nick) {
- // not the most efficient way for a big list!
- $user = User::getKV('nickname', $nick);
- if ($user) {
- $ids[] = intval($user->id);
- }
- }
- return $ids;
- }
-}
include_once INSTALLDIR . '/plugins/SphinxSearch/' .
strtolower($cls) . '.php';
return false;
- default:
- return true;
}
+
+ return parent::onAutoload($cls);
}
/**
return true;
}
- /**
- * Automatically load the actions and libraries used by the plugin
- *
- * @param Class $cls the class
- *
- * @return boolean hook return
- *
- */
- function onAutoload($cls)
- {
- $base = dirname(__FILE__);
- $lower = strtolower($cls);
- $files = array("$base/lib/$lower.php",
- "$base/classes/$cls.php");
- if (substr($lower, -6) == 'action') {
- $files[] = "$base/actions/" . substr($lower, 0, -6) . ".php";
- }
- foreach ($files as $file) {
- if (file_exists($file)) {
- include_once $file;
- return false;
- }
- }
- return true;
- }
-
function handle($notice)
{
// Is anybody mirroring?
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ * 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/>.
+ *
+ * @package StatusNet
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class AddMirrorForm extends Form
+{
+ /**
+ * Name of the form
+ *
+ * Sub-classes should overload this with the name of their form.
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ }
+
+ /**
+ * Visible or invisible data elements
+ *
+ * Display the form fields that make up the data of the form.
+ * Sub-classes should overload this to show their data.
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->hidden('provider', 'feed');
+ $this->out->elementStart('fieldset');
+
+ $this->out->elementStart('ul');
+
+ $this->li();
+ $this->doInput('addmirror-feedurl',
+ 'feedurl',
+ // TRANS: Field label.
+ _m('Web page or feed URL:'),
+ $this->out->trimmed('feedurl'));
+ $this->unli();
+
+ $this->li();
+ // TRANS: Button text for adding a feed.
+ $this->out->submit('addmirror-save', _m('BUTTON','Add feed'));
+ $this->unli();
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('fieldset');
+ }
+
+ protected function doInput($id, $name, $label, $value=null, $instructions=null)
+ {
+ $this->out->element('label', array('for' => $id), $label);
+ $attrs = array('name' => $name,
+ 'type' => 'text',
+ 'id' => $id,
+ 'style' => 'width: 80%');
+ if ($value) {
+ $attrs['value'] = $value;
+ }
+ $this->out->element('input', $attrs);
+ if ($instructions) {
+ $this->out->element('p', 'form_guide', $instructions);
+ }
+ }
+
+ /**
+ * Buttons for form actions
+ *
+ * Submit and cancel buttons (or whatever)
+ * Sub-classes should overload this to show their own buttons.
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ }
+
+ /**
+ * ID of the form
+ *
+ * Should be unique on the page. Sub-classes should overload this
+ * to show their own IDs.
+ *
+ * @return string ID of the form
+ */
+ function id()
+ {
+ return 'add-mirror-form';
+ }
+
+ /**
+ * Action of the form.
+ *
+ * URL to post to. Should be overloaded by subclasses to give
+ * somewhere to post to.
+ *
+ * @return string URL to post to
+ */
+ function action()
+ {
+ return common_local_url('addmirror');
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+ function formClass()
+ {
+ return 'form_settings';
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ * 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/>.
+ *
+ * @package StatusNet
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class AddTwitterMirrorForm extends AddMirrorForm
+{
+
+ /**
+ * Visible or invisible data elements
+ *
+ * Display the form fields that make up the data of the form.
+ * Sub-classes should overload this to show their data.
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->hidden('provider', 'twitter');
+ $this->out->elementStart('fieldset');
+
+ $this->out->elementStart('ul');
+
+ $this->li();
+ $this->doInput('addmirror-feedurl',
+ 'screen_name',
+ // TRANS: Field label.
+ _m('Twitter username:'),
+ $this->out->trimmed('screen_name'));
+ $this->unli();
+
+ $this->li();
+ // TRANS: Button text for adding a Twitter feed mirror.
+ $this->out->submit('addmirror-save', _m('BUTTON','Add feed'));
+ $this->unli();
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('fieldset');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ * 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/>.
+ *
+ * @package StatusNet
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class EditMirrorForm extends Form
+{
+ function __construct($action, $profile)
+ {
+ parent::__construct($action);
+
+ $this->profile = clone($profile);
+ $this->user = common_current_user();
+ $this->mirror = SubMirror::pkeyGet(array('subscriber' => $this->user->id,
+ 'subscribed' => $this->profile->id));
+ }
+
+ /**
+ * Name of the form
+ *
+ * Sub-classes should overload this with the name of their form.
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ }
+
+ /**
+ * Visible or invisible data elements
+ *
+ * Display the form fields that make up the data of the form.
+ * Sub-classes should overload this to show their data.
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset');
+
+ $this->out->hidden('profile', $this->profile->id);
+
+ $this->out->elementStart('div', array('style' => 'float: left; width: 80px;'));
+ $img = $this->getAvatar($this->profile);
+ $feed = $this->getFeed($this->profile);
+ $this->out->elementStart('a', array('href' => $this->profile->profileurl));
+ $this->out->element('img', array('src' => $img, 'style' => 'float: left'));
+ $this->out->elementEnd('a');
+ $this->out->elementEnd('div');
+
+
+ $this->out->elementStart('div', array('style' => 'margin-left: 80px; margin-right: 20px'));
+ $this->out->elementStart('p');
+ $this->out->elementStart('div');
+ $this->out->element('a', array('href' => $this->profile->profileurl), $this->profile->getBestName());
+ $this->out->elementEnd('div');
+ $this->out->elementStart('div');
+ if ($feed) {
+ // XXX: Why the hard coded space?
+ // TRANS: Field label (URL expectected).
+ $this->out->text(_m('LABEL', 'Remote feed:') . ' ');
+ //$this->out->element('a', array('href' => $feed), $feed);
+ $this->out->element('input', array('value' => $feed, 'readonly' => 'readonly', 'style' => 'width: 100%'));
+ } else {
+ // TRANS: Field label.
+ $this->out->text(_m('LABEL', 'Local user'));
+ }
+ $this->out->elementEnd('div');
+ $this->out->elementEnd('p');
+
+ $this->out->elementStart('fieldset', array('style' => 'margin-top: 20px'));
+ // TRANS: Fieldset legend for feed mirror setting.
+ $this->out->element('legend', false, _m('Mirroring style'));
+
+ // TRANS: Feed mirror style (radio button option).
+ $styles = array('repeat' => _m('Repeat: reference the original user\'s post (sometimes shows as "RT @blah")'),
+ // TRANS: Feed mirror style (radio button option).
+ 'copy' => _m('Repost the content under my account'));
+ foreach ($styles as $key => $label) {
+ $this->out->elementStart('div');
+ $attribs = array('type' => 'radio',
+ 'value' => $key,
+ 'name' => 'style',
+ 'id' => $this->id() . '-style');
+ if ($key == $this->mirror->style || ($key == 'repeat' && empty($this->mirror->style))) {
+ $attribs['checked'] = 'checked';
+ }
+ $this->out->element('input', $attribs);
+ $this->out->element('span', false, $label); // @todo FIXME: should be label, but the styles muck it up for now
+ $this->out->elementEnd('div');
+
+ }
+ $this->out->elementEnd('fieldset');
+
+
+ $this->out->elementStart('div');
+ // TRANS: Button text to save feed mirror settings.
+ $this->out->submit($this->id() . '-save', _m('BUTTON','Save'));
+ $this->out->element('input', array('type' => 'submit',
+ // TRANS: Button text to stop mirroring a feed.
+ 'value' => _m('BUTTON','Stop mirroring'),
+ 'name' => 'delete',
+ 'class' => 'submit'));
+ $this->out->elementEnd('div');
+
+ $this->out->elementEnd('div');
+ $this->out->elementEnd('fieldset');
+ }
+
+ private function getAvatar($profile)
+ {
+ $avatar = $this->profile->getAvatar(48);
+ if ($avatar) {
+ return $avatar->displayUrl();
+ } else {
+ return Avatar::defaultImage(48);
+ }
+ }
+
+ private function getFeed($profile)
+ {
+ // Ok this is a bit of a hack. ;)
+ if (class_exists('Ostatus_profile')) {
+ $oprofile = Ostatus_profile::getKV('profile_id', $profile->id);
+ if ($oprofile) {
+ return $oprofile->feeduri;
+ }
+ }
+ var_dump('wtf');
+ return false;
+ }
+
+ /**
+ * ID of the form
+ *
+ * Should be unique on the page. Sub-classes should overload this
+ * to show their own IDs.
+ *
+ * @return string ID of the form
+ */
+ function id()
+ {
+ return 'edit-mirror-form-' . $this->profile->id;
+ }
+
+ /**
+ * Action of the form.
+ *
+ * URL to post to. Should be overloaded by subclasses to give
+ * somewhere to post to.
+ *
+ * @return string URL to post to
+ */
+ function action()
+ {
+ return common_local_url('editmirror');
+ }
+
+ /**
+ * Class of the form.
+ *
+ * @return string the form's class
+ */
+ function formClass()
+ {
+ return 'form_settings';
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- * 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/>.
- *
- * @package StatusNet
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-class AddMirrorForm extends Form
-{
- /**
- * Name of the form
- *
- * Sub-classes should overload this with the name of their form.
- *
- * @return void
- */
- function formLegend()
- {
- }
-
- /**
- * Visible or invisible data elements
- *
- * Display the form fields that make up the data of the form.
- * Sub-classes should overload this to show their data.
- *
- * @return void
- */
- function formData()
- {
- $this->out->hidden('provider', 'feed');
- $this->out->elementStart('fieldset');
-
- $this->out->elementStart('ul');
-
- $this->li();
- $this->doInput('addmirror-feedurl',
- 'feedurl',
- // TRANS: Field label.
- _m('Web page or feed URL:'),
- $this->out->trimmed('feedurl'));
- $this->unli();
-
- $this->li();
- // TRANS: Button text for adding a feed.
- $this->out->submit('addmirror-save', _m('BUTTON','Add feed'));
- $this->unli();
- $this->out->elementEnd('ul');
- $this->out->elementEnd('fieldset');
- }
-
- protected function doInput($id, $name, $label, $value=null, $instructions=null)
- {
- $this->out->element('label', array('for' => $id), $label);
- $attrs = array('name' => $name,
- 'type' => 'text',
- 'id' => $id,
- 'style' => 'width: 80%');
- if ($value) {
- $attrs['value'] = $value;
- }
- $this->out->element('input', $attrs);
- if ($instructions) {
- $this->out->element('p', 'form_guide', $instructions);
- }
- }
-
- /**
- * Buttons for form actions
- *
- * Submit and cancel buttons (or whatever)
- * Sub-classes should overload this to show their own buttons.
- *
- * @return void
- */
- function formActions()
- {
- }
-
- /**
- * ID of the form
- *
- * Should be unique on the page. Sub-classes should overload this
- * to show their own IDs.
- *
- * @return string ID of the form
- */
- function id()
- {
- return 'add-mirror-form';
- }
-
- /**
- * Action of the form.
- *
- * URL to post to. Should be overloaded by subclasses to give
- * somewhere to post to.
- *
- * @return string URL to post to
- */
- function action()
- {
- return common_local_url('addmirror');
- }
-
- /**
- * Class of the form.
- *
- * @return string the form's class
- */
- function formClass()
- {
- return 'form_settings';
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- * 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/>.
- *
- * @package StatusNet
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-class AddTwitterMirrorForm extends AddMirrorForm
-{
-
- /**
- * Visible or invisible data elements
- *
- * Display the form fields that make up the data of the form.
- * Sub-classes should overload this to show their data.
- *
- * @return void
- */
- function formData()
- {
- $this->out->hidden('provider', 'twitter');
- $this->out->elementStart('fieldset');
-
- $this->out->elementStart('ul');
-
- $this->li();
- $this->doInput('addmirror-feedurl',
- 'screen_name',
- // TRANS: Field label.
- _m('Twitter username:'),
- $this->out->trimmed('screen_name'));
- $this->unli();
-
- $this->li();
- // TRANS: Button text for adding a Twitter feed mirror.
- $this->out->submit('addmirror-save', _m('BUTTON','Add feed'));
- $this->unli();
- $this->out->elementEnd('ul');
- $this->out->elementEnd('fieldset');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- * 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/>.
- *
- * @package StatusNet
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-class EditMirrorForm extends Form
-{
- function __construct($action, $profile)
- {
- parent::__construct($action);
-
- $this->profile = clone($profile);
- $this->user = common_current_user();
- $this->mirror = SubMirror::pkeyGet(array('subscriber' => $this->user->id,
- 'subscribed' => $this->profile->id));
- }
-
- /**
- * Name of the form
- *
- * Sub-classes should overload this with the name of their form.
- *
- * @return void
- */
- function formLegend()
- {
- }
-
- /**
- * Visible or invisible data elements
- *
- * Display the form fields that make up the data of the form.
- * Sub-classes should overload this to show their data.
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart('fieldset');
-
- $this->out->hidden('profile', $this->profile->id);
-
- $this->out->elementStart('div', array('style' => 'float: left; width: 80px;'));
- $img = $this->getAvatar($this->profile);
- $feed = $this->getFeed($this->profile);
- $this->out->elementStart('a', array('href' => $this->profile->profileurl));
- $this->out->element('img', array('src' => $img, 'style' => 'float: left'));
- $this->out->elementEnd('a');
- $this->out->elementEnd('div');
-
-
- $this->out->elementStart('div', array('style' => 'margin-left: 80px; margin-right: 20px'));
- $this->out->elementStart('p');
- $this->out->elementStart('div');
- $this->out->element('a', array('href' => $this->profile->profileurl), $this->profile->getBestName());
- $this->out->elementEnd('div');
- $this->out->elementStart('div');
- if ($feed) {
- // XXX: Why the hard coded space?
- // TRANS: Field label (URL expectected).
- $this->out->text(_m('LABEL', 'Remote feed:') . ' ');
- //$this->out->element('a', array('href' => $feed), $feed);
- $this->out->element('input', array('value' => $feed, 'readonly' => 'readonly', 'style' => 'width: 100%'));
- } else {
- // TRANS: Field label.
- $this->out->text(_m('LABEL', 'Local user'));
- }
- $this->out->elementEnd('div');
- $this->out->elementEnd('p');
-
- $this->out->elementStart('fieldset', array('style' => 'margin-top: 20px'));
- // TRANS: Fieldset legend for feed mirror setting.
- $this->out->element('legend', false, _m('Mirroring style'));
-
- // TRANS: Feed mirror style (radio button option).
- $styles = array('repeat' => _m('Repeat: reference the original user\'s post (sometimes shows as "RT @blah")'),
- // TRANS: Feed mirror style (radio button option).
- 'copy' => _m('Repost the content under my account'));
- foreach ($styles as $key => $label) {
- $this->out->elementStart('div');
- $attribs = array('type' => 'radio',
- 'value' => $key,
- 'name' => 'style',
- 'id' => $this->id() . '-style');
- if ($key == $this->mirror->style || ($key == 'repeat' && empty($this->mirror->style))) {
- $attribs['checked'] = 'checked';
- }
- $this->out->element('input', $attribs);
- $this->out->element('span', false, $label); // @todo FIXME: should be label, but the styles muck it up for now
- $this->out->elementEnd('div');
-
- }
- $this->out->elementEnd('fieldset');
-
-
- $this->out->elementStart('div');
- // TRANS: Button text to save feed mirror settings.
- $this->out->submit($this->id() . '-save', _m('BUTTON','Save'));
- $this->out->element('input', array('type' => 'submit',
- // TRANS: Button text to stop mirroring a feed.
- 'value' => _m('BUTTON','Stop mirroring'),
- 'name' => 'delete',
- 'class' => 'submit'));
- $this->out->elementEnd('div');
-
- $this->out->elementEnd('div');
- $this->out->elementEnd('fieldset');
- }
-
- private function getAvatar($profile)
- {
- $avatar = $this->profile->getAvatar(48);
- if ($avatar) {
- return $avatar->displayUrl();
- } else {
- return Avatar::defaultImage(48);
- }
- }
-
- private function getFeed($profile)
- {
- // Ok this is a bit of a hack. ;)
- if (class_exists('Ostatus_profile')) {
- $oprofile = Ostatus_profile::getKV('profile_id', $profile->id);
- if ($oprofile) {
- return $oprofile->feeduri;
- }
- }
- var_dump('wtf');
- return false;
- }
-
- /**
- * ID of the form
- *
- * Should be unique on the page. Sub-classes should overload this
- * to show their own IDs.
- *
- * @return string ID of the form
- */
- function id()
- {
- return 'edit-mirror-form-' . $this->profile->id;
- }
-
- /**
- * Action of the form.
- *
- * URL to post to. Should be overloaded by subclasses to give
- * somewhere to post to.
- *
- * @return string URL to post to
- */
- function action()
- {
- return common_local_url('editmirror');
- }
-
- /**
- * Class of the form.
- *
- * @return string the form's class
- */
- function formClass()
- {
- return 'form_settings';
- }
-}
+++ /dev/null
-<?php
-/**
- * Data class to store local tag subscriptions
- *
- * PHP version 5
- *
- * @category TagSubPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * For storing the tag subscriptions
- *
- * @category PollPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class TagSub extends Managed_DataObject
-{
- public $__table = 'tagsub'; // table name
- public $tag; // text
- public $profile_id; // int -> profile.id
- public $created; // datetime
-
- /**
- * The One True Thingy that must be defined and declared.
- */
- public static function schemaDef()
- {
- return array(
- 'description' => 'TagSubPlugin tag subscription records',
- 'fields' => array(
- 'tag' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'hash tag associated with this subscription'),
- 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile ID of subscribing user'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- ),
- 'primary key' => array('tag', 'profile_id'),
- 'foreign keys' => array(
- 'tagsub_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
- ),
- 'indexes' => array(
- 'tagsub_created_idx' => array('created'),
- 'tagsub_profile_id_tag_idx' => array('profile_id', 'tag'),
- ),
- );
- }
-
- /**
- * Start a tag subscription!
- *
- * @param profile $profile subscriber
- * @param string $tag subscribee
- * @return TagSub
- */
- static function start(Profile $profile, $tag)
- {
- $ts = new TagSub();
- $ts->tag = $tag;
- $ts->profile_id = $profile->id;
- $ts->created = common_sql_now();
- $ts->insert();
- self::blow('tagsub:by_profile:%d', $profile->id);
- return $ts;
- }
-
- /**
- * End a tag subscription!
- *
- * @param profile $profile subscriber
- * @param string $tag subscribee
- */
- static function cancel(Profile $profile, $tag)
- {
- $ts = TagSub::pkeyGet(array('tag' => $tag,
- 'profile_id' => $profile->id));
- if ($ts) {
- $ts->delete();
- self::blow('tagsub:by_profile:%d', $profile->id);
- }
- }
-
- static function forProfile(Profile $profile)
- {
- $tags = array();
-
- $keypart = sprintf('tagsub:by_profile:%d', $profile->id);
- $tagstring = self::cacheGet($keypart);
-
- if ($tagstring !== false) { // cache hit
- if (!empty($tagstring)) {
- $tags = explode(',', $tagstring);
- }
- } else {
- $tagsub = new TagSub();
- $tagsub->profile_id = $profile->id;
- $tagsub->selectAdd();
- $tagsub->selectAdd('tag');
-
- if ($tagsub->find()) {
- $tags = $tagsub->fetchAll('tag');
- }
-
- self::cacheSet($keypart, implode(',', $tags));
- }
-
- return $tags;
- }
-}
return true;
}
- /**
- * Load related modules when needed
- *
- * @param string $cls Name of the class to be loaded
- *
- * @return boolean hook value; true means continue processing, false means stop.
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls)
- {
- case 'TagSub':
- include_once $dir.'/'.$cls.'.php';
- return false;
- case 'TagsubAction':
- case 'TagunsubAction':
- case 'TagsubsAction':
- case 'TagSubForm':
- case 'TagSubMenu':
- case 'TagUnsubForm':
- include_once $dir.'/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Map URLs to actions
*
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008-2011, StatusNet, Inc.
+ *
+ * Tag subscription action.
+ *
+ * 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/>.
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Tag subscription action
+ *
+ * Takes parameters:
+ *
+ * - token: session token to prevent CSRF attacks
+ * - ajax: boolean; whether to return Ajax or full-browser results
+ *
+ * Only works if the current user is logged in.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2008-2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+class TagsubAction extends Action
+{
+ var $user;
+ var $tag;
+
+ /**
+ * Check pre-requisites and instantiate attributes
+ *
+ * @param Array $args array of arguments (URL, GET, POST)
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+ if ($this->boolean('ajax')) {
+ StatusNet::setApi(true);
+ }
+
+ // Only allow POST requests
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ // TRANS: Client error displayed trying to perform any request method other than POST.
+ // TRANS: Do not translate POST.
+ $this->clientError(_m('This action only accepts POST requests.'));
+ return false;
+ }
+
+ // CSRF protection
+
+ $token = $this->trimmed('token');
+
+ if (!$token || $token != common_session_token()) {
+ // TRANS: Client error displayed when the session token is not okay.
+ $this->clientError(_m('There was a problem with your session token.'.
+ ' Try again, please.'));
+ return false;
+ }
+
+ // Only for logged-in users
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
+ $this->clientError(_m('Not logged in.'));
+ return false;
+ }
+
+ // Profile to subscribe to
+
+ $this->tag = $this->arg('tag');
+
+ if (empty($this->tag)) {
+ // TRANS: Client error displayed trying to subscribe to a non-existing profile.
+ $this->clientError(_m('No such profile.'));
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle request
+ *
+ * Does the subscription and returns results.
+ *
+ * @param Array $args unused.
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ // Throws exception on error
+
+ TagSub::start($this->user->getProfile(),
+ $this->tag);
+
+ if ($this->boolean('ajax')) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Page title when tag subscription succeeded.
+ $this->element('title', null, _m('Subscribed'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $unsubscribe = new TagUnsubForm($this, $this->tag);
+ $unsubscribe->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ $url = common_local_url('tag',
+ array('tag' => $this->tag));
+ common_redirect($url, 303);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List of a user's subscriptions
+ *
+ * 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 Social
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * A list of the user's subscriptions
+ *
+ * @category Social
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class TagSubsAction extends GalleryAction
+{
+ function title()
+ {
+ if ($this->page == 1) {
+ // TRANS: Header for subscriptions overview for a user (first page).
+ // TRANS: %s is a user nickname.
+ return sprintf(_m('%s\'s tag subscriptions'), $this->user->nickname);
+ } else {
+ // TRANS: Header for subscriptions overview for a user (not first page).
+ // TRANS: %1$s is a user nickname, %2$d is the page number.
+ return sprintf(_m('%1$s\'s tag subscriptions, page %2$d'),
+ $this->user->nickname,
+ $this->page);
+ }
+ }
+
+ function showPageNotice()
+ {
+ $user = common_current_user();
+ if ($user && ($user->id == $this->profile->id)) {
+ $this->element('p', null,
+ // TRANS: Page notice for page with an overview of all tag subscriptions
+ // TRANS: of the logged in user's own profile.
+ _m('You have subscribed to receive all notices on this site containing the following tags:'));
+ } else {
+ $this->element('p', null,
+ // TRANS: Page notice for page with an overview of all subscriptions of a user other
+ // TRANS: than the logged in user. %s is the user nickname.
+ sprintf(_m('%s has subscribed to receive all notices on this site containing the following tags:'),
+ $this->profile->nickname));
+ }
+ }
+
+ function showContent()
+ {
+ if (Event::handle('StartShowTagSubscriptionsContent', array($this))) {
+ parent::showContent();
+
+ $offset = ($this->page-1) * PROFILES_PER_PAGE;
+ $limit = PROFILES_PER_PAGE + 1;
+
+ $cnt = 0;
+
+ $tagsub = new TagSub();
+ $tagsub->profile_id = $this->user->id;
+ $tagsub->limit($limit, $offset);
+ $tagsub->find();
+
+ if ($tagsub->N) {
+ $list = new TagSubscriptionsList($tagsub, $this->user, $this);
+ $cnt = $list->show();
+ if (0 == $cnt) {
+ $this->showEmptyListMessage();
+ }
+ } else {
+ $this->showEmptyListMessage();
+ }
+
+ $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
+ $this->page, 'tagsubs',
+ array('nickname' => $this->user->nickname));
+
+
+ Event::handle('EndShowTagSubscriptionsContent', array($this));
+ }
+ }
+
+ function showEmptyListMessage()
+ {
+ if (common_logged_in()) {
+ $current_user = common_current_user();
+ if ($this->user->id === $current_user->id) {
+ // TRANS: Tag subscription list text when the logged in user has no tag subscriptions.
+ $message = _m('You are not listening to any hash tags right now. You can push the "Subscribe" button ' .
+ 'on any hashtag page to automatically receive any public messages on this site that use that ' .
+ 'tag, even if you are not subscribed to the poster.');
+ } else {
+ // TRANS: Tag subscription list text when looking at the subscriptions for a of a user other
+ // TRANS: than the logged in user that has no tag subscriptions. %s is the user nickname.
+ $message = sprintf(_m('%s is not following any tags.'), $this->user->nickname);
+ }
+ }
+ else {
+ // TRANS: Subscription list text when looking at the subscriptions for a of a user that has none
+ // TRANS: as an anonymous user. %s is the user nickname.
+ $message = sprintf(_m('%s is not following any tags.'), $this->user->nickname);
+ }
+
+ $this->elementStart('div', 'guide');
+ $this->raw(common_markup_to_html($message));
+ $this->elementEnd('div');
+ }
+}
+
+// XXX SubscriptionsList and SubscriptionList are dangerously close
+
+class TagSubscriptionsList extends SubscriptionList
+{
+ function newListItem($tagsub)
+ {
+ return new TagSubscriptionsListItem($tagsub, $this->owner, $this->action);
+ }
+}
+
+class TagSubscriptionsListItem extends SubscriptionListItem
+{
+ function startItem()
+ {
+ $this->out->elementStart('li', array('class' => 'tagsub'));
+ }
+
+ function showProfile()
+ {
+ $tagsub = $this->profile;
+ $tag = $tagsub->tag;
+
+ // Relevant portion!
+ $cur = common_current_user();
+ if (!empty($cur) && $cur->id == $this->owner->id) {
+ $this->showOwnerControls();
+ }
+
+ $url = common_local_url('tag', array('tag' => $tag));
+ // TRANS: %1$s is a URL to a tag, %2$s is a tag,
+ // TRANS: %3$s a date string.
+ $linkline = sprintf(_m('#<a href="%1$s">%2$s</a> since %3$s'),
+ htmlspecialchars($url),
+ htmlspecialchars($tag),
+ common_date_string($tagsub->created));
+
+ $this->out->elementStart('div', 'tagsub-item');
+ $this->out->raw($linkline);
+ $this->out->element('div', array('style' => 'clear: both'));
+ $this->out->elementEnd('div');
+ }
+
+ function showActions()
+ {
+ }
+
+ function showOwnerControls()
+ {
+ $this->out->elementStart('div', 'entity_actions');
+
+ $tagsub = $this->profile; // ?
+ $form = new TagUnsubForm($this->out, $tagsub->tag);
+ $form->show();
+
+ $this->out->elementEnd('div');
+ return;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008-2011, StatusNet, Inc.
+ *
+ * Tag subscription action.
+ *
+ * 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/>.
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Tag unsubscription action
+ *
+ * Takes parameters:
+ *
+ * - token: session token to prevent CSRF attacks
+ * - ajax: boolean; whether to return Ajax or full-browser results
+ *
+ * Only works if the current user is logged in.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2008-2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
+ * @link http://status.net/
+ */
+class TagunsubAction extends TagsubAction
+{
+ /**
+ * Handle request
+ *
+ * Does the subscription and returns results.
+ *
+ * @param Array $args unused.
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ // Throws exception on error
+
+ TagSub::cancel($this->user->getProfile(),
+ $this->tag);
+
+ if ($this->boolean('ajax')) {
+ $this->startHTML('text/xml;charset=utf-8');
+ $this->elementStart('head');
+ // TRANS: Page title when tag unsubscription succeeded.
+ $this->element('title', null, _m('Unsubscribed'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $subscribe = new TagSubForm($this, $this->tag);
+ $subscribe->show();
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ $url = common_local_url('tag',
+ array('tag' => $this->tag));
+ common_redirect($url, 303);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class to store local tag subscriptions
+ *
+ * PHP version 5
+ *
+ * @category TagSubPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * For storing the tag subscriptions
+ *
+ * @category PollPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class TagSub extends Managed_DataObject
+{
+ public $__table = 'tagsub'; // table name
+ public $tag; // text
+ public $profile_id; // int -> profile.id
+ public $created; // datetime
+
+ /**
+ * The One True Thingy that must be defined and declared.
+ */
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'TagSubPlugin tag subscription records',
+ 'fields' => array(
+ 'tag' => array('type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'hash tag associated with this subscription'),
+ 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile ID of subscribing user'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ ),
+ 'primary key' => array('tag', 'profile_id'),
+ 'foreign keys' => array(
+ 'tagsub_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
+ ),
+ 'indexes' => array(
+ 'tagsub_created_idx' => array('created'),
+ 'tagsub_profile_id_tag_idx' => array('profile_id', 'tag'),
+ ),
+ );
+ }
+
+ /**
+ * Start a tag subscription!
+ *
+ * @param profile $profile subscriber
+ * @param string $tag subscribee
+ * @return TagSub
+ */
+ static function start(Profile $profile, $tag)
+ {
+ $ts = new TagSub();
+ $ts->tag = $tag;
+ $ts->profile_id = $profile->id;
+ $ts->created = common_sql_now();
+ $ts->insert();
+ self::blow('tagsub:by_profile:%d', $profile->id);
+ return $ts;
+ }
+
+ /**
+ * End a tag subscription!
+ *
+ * @param profile $profile subscriber
+ * @param string $tag subscribee
+ */
+ static function cancel(Profile $profile, $tag)
+ {
+ $ts = TagSub::pkeyGet(array('tag' => $tag,
+ 'profile_id' => $profile->id));
+ if ($ts) {
+ $ts->delete();
+ self::blow('tagsub:by_profile:%d', $profile->id);
+ }
+ }
+
+ static function forProfile(Profile $profile)
+ {
+ $tags = array();
+
+ $keypart = sprintf('tagsub:by_profile:%d', $profile->id);
+ $tagstring = self::cacheGet($keypart);
+
+ if ($tagstring !== false) { // cache hit
+ if (!empty($tagstring)) {
+ $tags = explode(',', $tagstring);
+ }
+ } else {
+ $tagsub = new TagSub();
+ $tagsub->profile_id = $profile->id;
+ $tagsub->selectAdd();
+ $tagsub->selectAdd('tag');
+
+ if ($tagsub->find()) {
+ $tags = $tagsub->fetchAll('tag');
+ }
+
+ self::cacheSet($keypart, implode(',', $tags));
+ }
+
+ return $tags;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for subscribing to a tag
+ *
+ * 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 TagSubPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009-2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Form for subscribing to a user
+ *
+ * @category TagSubPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ * @see UnsubscribeForm
+ */
+class TagSubForm extends Form
+{
+ /**
+ * Name of tag to subscribe to
+ */
+ var $tag = '';
+
+ /**
+ * Constructor
+ *
+ * @param HTMLOutputter $out output channel
+ * @param string $tag name of tag to subscribe to
+ */
+ function __construct($out=null, $tag=null)
+ {
+ parent::__construct($out);
+
+ $this->tag = $tag;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'tag-subscribe-' . $this->tag;
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+ function formClass()
+ {
+ // class to match existing styles...
+ return 'form_user_subscribe ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('tagsub', array('tag' => $this->tag));
+ }
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend.
+ $this->out->element('legend', null, _m('Subscribe to this tag'));
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->hidden('subscribeto-' . $this->tag,
+ $this->tag,
+ 'subscribeto');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Submit button text to subscribe to a tag.
+ $this->out->submit('submit', _m('BUTTON','Subscribe'),
+ // TRANS: Submit button title to subscribe to a tag.
+ 'submit', null, _m('Subscribe to this tag.'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for subscribing to a tag
+ *
+ * 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 TagSubPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009-2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Form for subscribing to a user
+ *
+ * @category TagSubPlugin
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ * @see UnsubscribeForm
+ */
+class TagUnsubForm extends TagSubForm
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'tag-unsubscribe-' . $this->tag;
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+ function formClass()
+ {
+ // class to match existing styles...
+ return 'form_user_unsubscribe ajax';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('tagunsub', array('tag' => $this->tag));
+ }
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend.
+ $this->out->element('legend', null, _m('Unsubscribe from this tag'));
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Submit button text to unsubscribe from a tag.
+ $this->out->submit('submit', _m('BUTTON','Unsubscribe'),
+ // TRANS: Submit button title to unsubscribe from a tag.
+ 'submit', null, _m('Unsubscribe from this tag.'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Menu to show tags you're subscribed to
+ *
+ * PHP version 5
+ *
+ * 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 Menu
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Class comment
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+class TagSubMenu extends MoreMenu
+{
+ protected $user;
+ protected $tags;
+
+ function __construct($out, $user, $tags)
+ {
+ parent::__construct($out);
+ $this->user = $user;
+ $this->tags = $tags;
+ }
+
+ function getItems()
+ {
+ $items = array();
+
+ foreach ($this->tags as $tag) {
+ if (!empty($tag)) {
+ $items[] = array('tag',
+ array('tag' => $tag),
+ sprintf('#%s', $tag),
+ // TRANS: Menu item title. %s is a tag.
+ sprintf(_('Notices tagged with "%s".'), $tag));
+ }
+ }
+
+ return $items;
+ }
+
+ function tag()
+ {
+ return 'tagsubs';
+ }
+
+ function seeAllItem()
+ {
+ return array('tagsubs',
+ array('nickname' => $this->user->nickname),
+ _('See all'),
+ _('See all tags you are following'));
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008-2011, StatusNet, Inc.
- *
- * Tag subscription action.
- *
- * 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/>.
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Tag subscription action
- *
- * Takes parameters:
- *
- * - token: session token to prevent CSRF attacks
- * - ajax: boolean; whether to return Ajax or full-browser results
- *
- * Only works if the current user is logged in.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Brion Vibber <brion@status.net>
- * @copyright 2008-2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-class TagsubAction extends Action
-{
- var $user;
- var $tag;
-
- /**
- * Check pre-requisites and instantiate attributes
- *
- * @param Array $args array of arguments (URL, GET, POST)
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- parent::prepare($args);
- if ($this->boolean('ajax')) {
- StatusNet::setApi(true);
- }
-
- // Only allow POST requests
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- // TRANS: Client error displayed trying to perform any request method other than POST.
- // TRANS: Do not translate POST.
- $this->clientError(_m('This action only accepts POST requests.'));
- return false;
- }
-
- // CSRF protection
-
- $token = $this->trimmed('token');
-
- if (!$token || $token != common_session_token()) {
- // TRANS: Client error displayed when the session token is not okay.
- $this->clientError(_m('There was a problem with your session token.'.
- ' Try again, please.'));
- return false;
- }
-
- // Only for logged-in users
-
- $this->user = common_current_user();
-
- if (empty($this->user)) {
- // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
- $this->clientError(_m('Not logged in.'));
- return false;
- }
-
- // Profile to subscribe to
-
- $this->tag = $this->arg('tag');
-
- if (empty($this->tag)) {
- // TRANS: Client error displayed trying to subscribe to a non-existing profile.
- $this->clientError(_m('No such profile.'));
- return false;
- }
-
- return true;
- }
-
- /**
- * Handle request
- *
- * Does the subscription and returns results.
- *
- * @param Array $args unused.
- *
- * @return void
- */
- function handle($args)
- {
- // Throws exception on error
-
- TagSub::start($this->user->getProfile(),
- $this->tag);
-
- if ($this->boolean('ajax')) {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- // TRANS: Page title when tag subscription succeeded.
- $this->element('title', null, _m('Subscribed'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $unsubscribe = new TagUnsubForm($this, $this->tag);
- $unsubscribe->show();
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- $url = common_local_url('tag',
- array('tag' => $this->tag));
- common_redirect($url, 303);
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for subscribing to a tag
- *
- * 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 TagSubPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @copyright 2009-2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * Form for subscribing to a user
- *
- * @category TagSubPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- *
- * @see UnsubscribeForm
- */
-class TagSubForm extends Form
-{
- /**
- * Name of tag to subscribe to
- */
- var $tag = '';
-
- /**
- * Constructor
- *
- * @param HTMLOutputter $out output channel
- * @param string $tag name of tag to subscribe to
- */
- function __construct($out=null, $tag=null)
- {
- parent::__construct($out);
-
- $this->tag = $tag;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'tag-subscribe-' . $this->tag;
- }
-
- /**
- * class of the form
- *
- * @return string of the form class
- */
- function formClass()
- {
- // class to match existing styles...
- return 'form_user_subscribe ajax';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('tagsub', array('tag' => $this->tag));
- }
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend.
- $this->out->element('legend', null, _m('Subscribe to this tag'));
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->hidden('subscribeto-' . $this->tag,
- $this->tag,
- 'subscribeto');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Submit button text to subscribe to a tag.
- $this->out->submit('submit', _m('BUTTON','Subscribe'),
- // TRANS: Submit button title to subscribe to a tag.
- 'submit', null, _m('Subscribe to this tag.'));
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2011, StatusNet, Inc.
- *
- * Menu to show tags you're subscribed to
- *
- * PHP version 5
- *
- * 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 Menu
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-/**
- * Class comment
- *
- * @category General
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-class TagSubMenu extends MoreMenu
-{
- protected $user;
- protected $tags;
-
- function __construct($out, $user, $tags)
- {
- parent::__construct($out);
- $this->user = $user;
- $this->tags = $tags;
- }
-
- function getItems()
- {
- $items = array();
-
- foreach ($this->tags as $tag) {
- if (!empty($tag)) {
- $items[] = array('tag',
- array('tag' => $tag),
- sprintf('#%s', $tag),
- // TRANS: Menu item title. %s is a tag.
- sprintf(_('Notices tagged with "%s".'), $tag));
- }
- }
-
- return $items;
- }
-
- function tag()
- {
- return 'tagsubs';
- }
-
- function seeAllItem()
- {
- return array('tagsubs',
- array('nickname' => $this->user->nickname),
- _('See all'),
- _('See all tags you are following'));
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * List of a user's subscriptions
- *
- * 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 Social
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @copyright 2008-2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * A list of the user's subscriptions
- *
- * @category Social
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class TagSubsAction extends GalleryAction
-{
- function title()
- {
- if ($this->page == 1) {
- // TRANS: Header for subscriptions overview for a user (first page).
- // TRANS: %s is a user nickname.
- return sprintf(_m('%s\'s tag subscriptions'), $this->user->nickname);
- } else {
- // TRANS: Header for subscriptions overview for a user (not first page).
- // TRANS: %1$s is a user nickname, %2$d is the page number.
- return sprintf(_m('%1$s\'s tag subscriptions, page %2$d'),
- $this->user->nickname,
- $this->page);
- }
- }
-
- function showPageNotice()
- {
- $user = common_current_user();
- if ($user && ($user->id == $this->profile->id)) {
- $this->element('p', null,
- // TRANS: Page notice for page with an overview of all tag subscriptions
- // TRANS: of the logged in user's own profile.
- _m('You have subscribed to receive all notices on this site containing the following tags:'));
- } else {
- $this->element('p', null,
- // TRANS: Page notice for page with an overview of all subscriptions of a user other
- // TRANS: than the logged in user. %s is the user nickname.
- sprintf(_m('%s has subscribed to receive all notices on this site containing the following tags:'),
- $this->profile->nickname));
- }
- }
-
- function showContent()
- {
- if (Event::handle('StartShowTagSubscriptionsContent', array($this))) {
- parent::showContent();
-
- $offset = ($this->page-1) * PROFILES_PER_PAGE;
- $limit = PROFILES_PER_PAGE + 1;
-
- $cnt = 0;
-
- $tagsub = new TagSub();
- $tagsub->profile_id = $this->user->id;
- $tagsub->limit($limit, $offset);
- $tagsub->find();
-
- if ($tagsub->N) {
- $list = new TagSubscriptionsList($tagsub, $this->user, $this);
- $cnt = $list->show();
- if (0 == $cnt) {
- $this->showEmptyListMessage();
- }
- } else {
- $this->showEmptyListMessage();
- }
-
- $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
- $this->page, 'tagsubs',
- array('nickname' => $this->user->nickname));
-
-
- Event::handle('EndShowTagSubscriptionsContent', array($this));
- }
- }
-
- function showEmptyListMessage()
- {
- if (common_logged_in()) {
- $current_user = common_current_user();
- if ($this->user->id === $current_user->id) {
- // TRANS: Tag subscription list text when the logged in user has no tag subscriptions.
- $message = _m('You are not listening to any hash tags right now. You can push the "Subscribe" button ' .
- 'on any hashtag page to automatically receive any public messages on this site that use that ' .
- 'tag, even if you are not subscribed to the poster.');
- } else {
- // TRANS: Tag subscription list text when looking at the subscriptions for a of a user other
- // TRANS: than the logged in user that has no tag subscriptions. %s is the user nickname.
- $message = sprintf(_m('%s is not following any tags.'), $this->user->nickname);
- }
- }
- else {
- // TRANS: Subscription list text when looking at the subscriptions for a of a user that has none
- // TRANS: as an anonymous user. %s is the user nickname.
- $message = sprintf(_m('%s is not following any tags.'), $this->user->nickname);
- }
-
- $this->elementStart('div', 'guide');
- $this->raw(common_markup_to_html($message));
- $this->elementEnd('div');
- }
-}
-
-// XXX SubscriptionsList and SubscriptionList are dangerously close
-
-class TagSubscriptionsList extends SubscriptionList
-{
- function newListItem($tagsub)
- {
- return new TagSubscriptionsListItem($tagsub, $this->owner, $this->action);
- }
-}
-
-class TagSubscriptionsListItem extends SubscriptionListItem
-{
- function startItem()
- {
- $this->out->elementStart('li', array('class' => 'tagsub'));
- }
-
- function showProfile()
- {
- $tagsub = $this->profile;
- $tag = $tagsub->tag;
-
- // Relevant portion!
- $cur = common_current_user();
- if (!empty($cur) && $cur->id == $this->owner->id) {
- $this->showOwnerControls();
- }
-
- $url = common_local_url('tag', array('tag' => $tag));
- // TRANS: %1$s is a URL to a tag, %2$s is a tag,
- // TRANS: %3$s a date string.
- $linkline = sprintf(_m('#<a href="%1$s">%2$s</a> since %3$s'),
- htmlspecialchars($url),
- htmlspecialchars($tag),
- common_date_string($tagsub->created));
-
- $this->out->elementStart('div', 'tagsub-item');
- $this->out->raw($linkline);
- $this->out->element('div', array('style' => 'clear: both'));
- $this->out->elementEnd('div');
- }
-
- function showActions()
- {
- }
-
- function showOwnerControls()
- {
- $this->out->elementStart('div', 'entity_actions');
-
- $tagsub = $this->profile; // ?
- $form = new TagUnsubForm($this->out, $tagsub->tag);
- $form->show();
-
- $this->out->elementEnd('div');
- return;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008-2011, StatusNet, Inc.
- *
- * Tag subscription action.
- *
- * 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/>.
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Tag unsubscription action
- *
- * Takes parameters:
- *
- * - token: session token to prevent CSRF attacks
- * - ajax: boolean; whether to return Ajax or full-browser results
- *
- * Only works if the current user is logged in.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Brion Vibber <brion@status.net>
- * @copyright 2008-2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
- * @link http://status.net/
- */
-class TagunsubAction extends TagsubAction
-{
- /**
- * Handle request
- *
- * Does the subscription and returns results.
- *
- * @param Array $args unused.
- *
- * @return void
- */
- function handle($args)
- {
- // Throws exception on error
-
- TagSub::cancel($this->user->getProfile(),
- $this->tag);
-
- if ($this->boolean('ajax')) {
- $this->startHTML('text/xml;charset=utf-8');
- $this->elementStart('head');
- // TRANS: Page title when tag unsubscription succeeded.
- $this->element('title', null, _m('Unsubscribed'));
- $this->elementEnd('head');
- $this->elementStart('body');
- $subscribe = new TagSubForm($this, $this->tag);
- $subscribe->show();
- $this->elementEnd('body');
- $this->elementEnd('html');
- } else {
- $url = common_local_url('tag',
- array('tag' => $this->tag));
- common_redirect($url, 303);
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for subscribing to a tag
- *
- * 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 TagSubPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @copyright 2009-2011 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * Form for subscribing to a user
- *
- * @category TagSubPlugin
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @author Evan Prodromou <evan@status.net>
- * @author Sarven Capadisli <csarven@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- *
- * @see UnsubscribeForm
- */
-class TagUnsubForm extends TagSubForm
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'tag-unsubscribe-' . $this->tag;
- }
-
- /**
- * class of the form
- *
- * @return string of the form class
- */
- function formClass()
- {
- // class to match existing styles...
- return 'form_user_unsubscribe ajax';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('tagunsub', array('tag' => $this->tag));
- }
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend.
- $this->out->element('legend', null, _m('Unsubscribe from this tag'));
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Submit button text to unsubscribe from a tag.
- $this->out->submit('submit', _m('BUTTON','Unsubscribe'),
- // TRANS: Submit button title to unsubscribe from a tag.
- 'submit', null, _m('Unsubscribe from this tag.'));
- }
-}
+++ /dev/null
-<?php
-/**
- * Data class for remembering notice-to-status mappings
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for mapping notices to statuses
- *
- * Notices flow back and forth between Twitter and StatusNet. We use this
- * table to remember which StatusNet notice corresponds to which Twitter
- * status.
- *
- * Note that notice_id is unique only within a single database; if you
- * want to share this data for some reason, get the notice's URI and use
- * that instead, since it's universally unique.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-
-class Notice_to_status extends Managed_DataObject
-{
- public $__table = 'notice_to_status'; // table name
- public $notice_id; // int(4) primary_key not_null
- public $status_id; // bigint not_null
- public $created; // datetime() not_null
- public $modified; // datetime not_null default_0000-00-00%2000%3A00%3A00
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'local notice id'),
- 'status_id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'twitter status id'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('notice_id'),
- 'unique keys' => array(
- 'status_id_key' => array('status_id'),
- ),
- 'foreign keys' => array(
- 'notice_to_status_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
- ),
- );
- }
-
- /**
- * Save a mapping between a notice and a status
- * Warning: status_id values may not fit in 32-bit integers.
- *
- * @param integer $notice_id ID of the notice in StatusNet
- * @param integer $status_id ID of the status in Twitter
- *
- * @return Notice_to_status new object for this value
- */
- static function saveNew($notice_id, $status_id)
- {
- if (empty($notice_id)) {
- throw new Exception("Invalid notice_id $notice_id");
- }
- $n2s = Notice_to_status::getKV('notice_id', $notice_id);
-
- if (!empty($n2s)) {
- return $n2s;
- }
-
- if (empty($status_id)) {
- throw new Exception("Invalid status_id $status_id");
- }
- $n2s = Notice_to_status::getKV('status_id', $status_id);
-
- if (!empty($n2s)) {
- return $n2s;
- }
-
- common_debug("Mapping notice {$notice_id} to Twitter status {$status_id}");
-
- $n2s = new Notice_to_status();
-
- $n2s->notice_id = $notice_id;
- $n2s->status_id = $status_id;
- $n2s->created = common_sql_now();
-
- $n2s->insert();
-
- return $n2s;
- }
-}
return true;
}
- /**
- * Automatically load the actions and libraries used by the Twitter bridge
- *
- * @param Class $cls the class
- *
- * @return boolean hook return
- *
- */
- function onAutoload($cls)
- {
- $dir = dirname(__FILE__);
-
- switch ($cls) {
- case 'TwittersettingsAction':
- case 'TwitterauthorizationAction':
- case 'TwitterloginAction':
- case 'TwitteradminpanelAction':
- include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'TwitterOAuthClient':
- case 'TwitterQueueHandler':
- case 'TweetInQueueHandler':
- case 'TwitterImport':
- case 'JsonStreamReader':
- case 'TwitterStreamReader':
- include_once $dir . '/' . strtolower($cls) . '.php';
- return false;
- case 'TwitterSiteStream':
- case 'TwitterUserStream':
- include_once $dir . '/twitterstreamreader.php';
- return false;
- case 'Notice_to_status':
- case 'Twitter_synch_status':
- include_once $dir . '/' . $cls . '.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Add a Twitter queue item for each notice
*
+++ /dev/null
-<?php
-/**
- * Store last-touched ID for various timelines
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Store various timeline data
- *
- * We don't want to keep re-fetching the same statuses and direct messages from Twitter.
- * So, we store the last ID we see from a timeline, and store it. Next time
- * around, we use that ID in the since_id parameter.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @see DB_DataObject
- */
-class Twitter_synch_status extends Managed_DataObject
-{
- public $__table = 'twitter_synch_status'; // table name
- public $foreign_id; // bigint primary_key not_null
- public $timeline; // varchar(255) primary_key not_null
- public $last_id; // bigint not_null
- public $created; // datetime() not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'foreign_id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'Foreign message ID'),
- 'timeline' => array('type' => 'varchar', 'length' => 255, 'description' => 'timeline name'),
- 'last_id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'last id fetched'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('foreign_id', 'timeline'),
- );
- }
-
- static function getLastId($foreign_id, $timeline)
- {
- $tss = self::pkeyGet(array('foreign_id' => $foreign_id,
- 'timeline' => $timeline));
-
- if (empty($tss)) {
- return null;
- } else {
- return $tss->last_id;
- }
- }
-
- static function setLastId($foreign_id, $timeline, $last_id)
- {
- $tss = self::pkeyGet(array('foreign_id' => $foreign_id,
- 'timeline' => $timeline));
-
- if (empty($tss)) {
- $tss = new Twitter_synch_status();
-
- $tss->foreign_id = $foreign_id;
- $tss->timeline = $timeline;
- $tss->last_id = $last_id;
- $tss->created = common_sql_now();
- $tss->modified = $tss->created;
-
- $tss->insert();
-
- return true;
- } else {
- $orig = clone($tss);
-
- $tss->last_id = $last_id;
- $tss->modified = common_sql_now();
-
- $tss->update();
-
- return true;
- }
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Twitter bridge administration panel
+ *
+ * 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 Settings
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Administer global Twitter bridge settings
+ *
+ * @category Admin
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ */
+class TwitteradminpanelAction extends AdminPanelAction
+{
+ /**
+ * Returns the page title
+ *
+ * @return string page title
+ */
+ function title()
+ {
+ // TRANS: Page title for Twitter administration panel.
+ return _m('TITLE','Twitter');
+ }
+
+ /**
+ * Instructions for using this form.
+ *
+ * @return string instructions
+ */
+ function getInstructions()
+ {
+ // TRANS: Instructions for Twitter bridge administration page.
+ return _m('Twitter bridge settings');
+ }
+
+ /**
+ * Show the Twitter admin panel form
+ *
+ * @return void
+ */
+ function showForm()
+ {
+ $form = new TwitterAdminPanelForm($this);
+ $form->show();
+ return;
+ }
+
+ /**
+ * Save settings from the form
+ *
+ * @return void
+ */
+ function saveSettings()
+ {
+ static $settings = array(
+ 'twitter' => array('consumer_key', 'consumer_secret'),
+ 'integration' => array('source')
+ );
+
+ static $booleans = array(
+ 'twitter' => array('signin')
+ );
+ if (Event::handle('TwitterBridgeAdminImportControl')) {
+ $booleans['twitterimport'] = array('enabled');
+ }
+
+ $values = array();
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ $values[$section][$setting]
+ = $this->trimmed($setting);
+ }
+ }
+
+ foreach ($booleans as $section => $parts) {
+ foreach ($parts as $setting) {
+ $values[$section][$setting]
+ = ($this->boolean($setting)) ? 1 : 0;
+ }
+ }
+
+ // This throws an exception on validation errors
+
+ $this->validate($values);
+
+ // assert(all values are valid);
+
+ $config = new Config();
+
+ $config->query('BEGIN');
+
+ foreach ($settings as $section => $parts) {
+ foreach ($parts as $setting) {
+ Config::save($section, $setting, $values[$section][$setting]);
+ }
+ }
+
+ foreach ($booleans as $section => $parts) {
+ foreach ($parts as $setting) {
+ Config::save($section, $setting, $values[$section][$setting]);
+ }
+ }
+
+ $config->query('COMMIT');
+
+ // Flush the router cache: we may have enabled/disabled bridging,
+ // which will add or remove some actions.
+ $cache = Cache::instance();
+ $cache->delete(Router::cacheKey());
+
+ return;
+ }
+
+ function validate(&$values)
+ {
+ // Validate consumer key and secret (can't be too long)
+
+ if (mb_strlen($values['twitter']['consumer_key']) > 255) {
+ $this->clientError(
+ // TRANS: Client error displayed when a consumer key is invalid because it is too long.
+ _m('Invalid consumer key. Maximum length is 255 characters.')
+ );
+ }
+
+ if (mb_strlen($values['twitter']['consumer_secret']) > 255) {
+ $this->clientError(
+ // TRANS: Client error displayed when a consumer secret is invalid because it is too long.
+ _m('Invalid consumer secret. Maximum length is 255 characters.')
+ );
+ }
+ }
+
+ function isImportEnabled()
+ {
+ // Since daemon setup isn't automated yet...
+ // @todo: if merged into main queues, detect presence of daemon config
+ return true;
+ }
+}
+
+class TwitterAdminPanelForm extends AdminForm
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'twitteradminpanel';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('twitteradminpanel');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart(
+ 'fieldset',
+ array('id' => 'settings_twitter-application')
+ );
+ // TRANS: Fieldset legend for Twitter application settings.
+ $this->out->element('legend', null, _m('Twitter application settings'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->input(
+ 'consumer_key',
+ // TRANS: Field label for Twitter assigned consumer key.
+ _m('Consumer key'),
+ // TRANS: Field title for Twitter assigned consumer key.
+ _m('The consumer key assigned by Twitter.'),
+ 'twitter'
+ );
+ $this->unli();
+
+ $this->li();
+ $this->input(
+ 'consumer_secret',
+ // TRANS: Field label for Twitter assigned consumer secret.
+ _m('Consumer secret'),
+ // TRANS: Field title for Twitter assigned consumer secret.
+ _m('The consumer secret assigned by Twitter.'),
+ 'twitter'
+ );
+ $this->unli();
+
+ $globalConsumerKey = common_config('twitter', 'global_consumer_key');
+ $globalConsumerSec = common_config('twitter', 'global_consumer_secret');
+
+ if (!empty($globalConsumerKey) && !empty($globalConsumerSec)) {
+ $this->li();
+ // TRANS: Form guide displayed when two required fields have already been provided.
+ $this->out->element('p', 'form_guide', _m('Note: A global consumer key and secret are set.'));
+ $this->unli();
+ }
+
+ $this->li();
+ $this->input(
+ 'source',
+ // TRANS: Field label for Twitter application name.
+ _m('Integration source'),
+ // TRANS: Field title for Twitter application name.
+ _m('The name of your Twitter application.'),
+ 'integration'
+ );
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('fieldset');
+
+ $this->out->elementStart(
+ 'fieldset',
+ array('id' => 'settings_twitter-options')
+ );
+ // TRANS: Fieldset legend for Twitter integration options.
+ $this->out->element('legend', null, _m('Options'));
+
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+
+ $this->out->checkbox(
+ // TRANS: Checkbox label for global setting.
+ 'signin', _m('Enable "Sign-in with Twitter"'),
+ (bool) $this->value('signin', 'twitter'),
+ // TRANS: Checkbox title.
+ _m('This allow users to login with their Twitter credentials.')
+ );
+ $this->unli();
+
+ if (Event::handle('TwitterBridgeAdminImportControl')) {
+ $this->li();
+ $this->out->checkbox(
+ // TRANS: Checkbox label for global setting.
+ 'enabled', _m('Enable Twitter import'),
+ (bool) $this->value('enabled', 'twitterimport'),
+ // TRANS: Checkbox title for global setting.
+ _m('Allow users to import their Twitter friends\' timelines. Requires daemons to be manually configured.')
+ );
+ $this->unli();
+ }
+
+ $this->out->elementEnd('ul');
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text for saving the administrative Twitter bridge settings.
+ $this->out->submit('submit', _m('BUTTON','Save'), 'submit', null,
+ // TRANS: Button title for saving the administrative Twitter bridge settings.
+ _m('Save the Twitter bridge settings.'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Class for doing OAuth authentication against Twitter
+ *
+ * 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
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Julien C <chaumond@gmail.com>
+ * @copyright 2009-2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
+
+/**
+ * Class for doing OAuth authentication against Twitter
+ *
+ * Peforms the OAuth "dance" between StatusNet and Twitter -- requests a token,
+ * authorizes it, and exchanges it for an access token. It also creates a link
+ * (Foreign_link) between the StatusNet user and Twitter user and stores the
+ * access token and secret in the link.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Julien C <chaumond@gmail.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ */
+class TwitterauthorizationAction extends Action
+{
+ var $twuid = null;
+ var $tw_fields = null;
+ var $access_token = null;
+ var $signin = null;
+ var $verifier = null;
+
+ /**
+ * Initialize class members. Looks for 'oauth_token' parameter.
+ *
+ * @param array $args misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->signin = $this->boolean('signin');
+ $this->oauth_token = $this->arg('oauth_token');
+ $this->verifier = $this->arg('oauth_verifier');
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $args is ignored since it's now passed in in prepare()
+ *
+ * @return nothing
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (common_logged_in()) {
+ $user = common_current_user();
+ $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
+
+ // If there's already a foreign link record and a foreign user
+ // it means the accounts are already linked, and this is unecessary.
+ // So go back.
+
+ if (isset($flink)) {
+ $fuser = $flink->getForeignUser();
+ if (!empty($fuser)) {
+ common_redirect(common_local_url('twittersettings'));
+ }
+ }
+ }
+
+ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+
+ // User was not logged in to StatusNet before
+
+ $this->twuid = $this->trimmed('twuid');
+
+ $this->tw_fields = array('screen_name' => $this->trimmed('tw_fields_screen_name'),
+ 'fullname' => $this->trimmed('tw_fields_fullname'));
+
+ $this->access_token = new OAuthToken($this->trimmed('access_token_key'), $this->trimmed('access_token_secret'));
+
+ $token = $this->trimmed('token');
+
+ if (!$token || $token != common_session_token()) {
+ // TRANS: Client error displayed when the session token does not match or is not given.
+ $this->showForm(_m('There was a problem with your session token. Try again, please.'));
+ return;
+ }
+
+ if ($this->arg('create')) {
+ if (!$this->boolean('license')) {
+ // TRANS: Form validation error displayed when the checkbox to agree to the license has not been checked.
+ $this->showForm(_m('You cannot register if you do not agree to the license.'),
+ $this->trimmed('newname'));
+ return;
+ }
+ $this->createNewUser();
+ } else if ($this->arg('connect')) {
+ $this->connectNewUser();
+ } else {
+ common_debug('Twitter bridge - ' . print_r($this->args, true));
+ // TRANS: Form validation error displayed when an unhandled error occurs.
+ $this->showForm(_m('Something weird happened.'),
+ $this->trimmed('newname'));
+ }
+ } else {
+ // $this->oauth_token is only populated once Twitter authorizes our
+ // request token. If it's empty we're at the beginning of the auth
+ // process
+
+ if (empty($this->oauth_token)) {
+ $this->authorizeRequestToken();
+ } else {
+ $this->saveAccessToken();
+ }
+ }
+ }
+
+ /**
+ * Asks Twitter for a request token, and then redirects to Twitter
+ * to authorize it.
+ *
+ * @return nothing
+ */
+ function authorizeRequestToken()
+ {
+ try {
+ // Get a new request token and authorize it
+
+ $client = new TwitterOAuthClient();
+ $req_tok = $client->getRequestToken();
+
+ // Sock the request token away in the session temporarily
+
+ $_SESSION['twitter_request_token'] = $req_tok->key;
+ $_SESSION['twitter_request_token_secret'] = $req_tok->secret;
+
+ $auth_link = $client->getAuthorizeLink($req_tok, $this->signin);
+ } catch (OAuthClientException $e) {
+ $msg = sprintf(
+ 'OAuth client error - code: %1s, msg: %2s',
+ $e->getCode(),
+ $e->getMessage()
+ );
+ common_log(LOG_INFO, 'Twitter bridge - ' . $msg);
+ $this->serverError(
+ // TRANS: Server error displayed when linking to a Twitter account fails.
+ _m('Could not link your Twitter account.')
+ );
+ }
+
+ common_redirect($auth_link);
+ }
+
+ /**
+ * Called when Twitter returns an authorized request token. Exchanges
+ * it for an access token and stores it.
+ *
+ * @return nothing
+ */
+ function saveAccessToken()
+ {
+ // Check to make sure Twitter returned the same request
+ // token we sent them
+
+ if ($_SESSION['twitter_request_token'] != $this->oauth_token) {
+ $this->serverError(
+ // TRANS: Server error displayed when linking to a Twitter account fails because of an incorrect oauth_token.
+ _m('Could not link your Twitter account: oauth_token mismatch.')
+ );
+ }
+
+ $twitter_user = null;
+
+ try {
+
+ $client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
+ $_SESSION['twitter_request_token_secret']);
+
+ // Exchange the request token for an access token
+
+ $atok = $client->getAccessToken($this->verifier);
+
+ // Test the access token and get the user's Twitter info
+
+ $client = new TwitterOAuthClient($atok->key, $atok->secret);
+ $twitter_user = $client->verifyCredentials();
+
+ } catch (OAuthClientException $e) {
+ $msg = sprintf(
+ 'OAuth client error - code: %1$s, msg: %2$s',
+ $e->getCode(),
+ $e->getMessage()
+ );
+ common_log(LOG_INFO, 'Twitter bridge - ' . $msg);
+ $this->serverError(
+ // TRANS: Server error displayed when linking to a Twitter account fails.
+ _m('Could not link your Twitter account.')
+ );
+ }
+
+ if (common_logged_in()) {
+ // Save the access token and Twitter user info
+
+ $user = common_current_user();
+ $this->saveForeignLink($user->id, $twitter_user->id, $atok);
+ save_twitter_user($twitter_user->id, $twitter_user->screen_name);
+
+ } else {
+
+ $this->twuid = $twitter_user->id;
+ $this->tw_fields = array("screen_name" => $twitter_user->screen_name,
+ "fullname" => $twitter_user->name);
+ $this->access_token = $atok;
+ $this->tryLogin();
+ }
+
+ // Clean up the the mess we made in the session
+
+ unset($_SESSION['twitter_request_token']);
+ unset($_SESSION['twitter_request_token_secret']);
+
+ if (common_logged_in()) {
+ common_redirect(common_local_url('twittersettings'));
+ }
+ }
+
+ /**
+ * Saves a Foreign_link between Twitter user and local user,
+ * which includes the access token and secret.
+ *
+ * @param int $user_id StatusNet user ID
+ * @param int $twuid Twitter user ID
+ * @param OAuthToken $token the access token to save
+ *
+ * @return nothing
+ */
+ function saveForeignLink($user_id, $twuid, $access_token)
+ {
+ $flink = new Foreign_link();
+
+ $flink->user_id = $user_id;
+ $flink->service = TWITTER_SERVICE;
+
+ // delete stale flink, if any
+ $result = $flink->find(true);
+
+ if (!empty($result)) {
+ $flink->safeDelete();
+ }
+
+ $flink->user_id = $user_id;
+ $flink->foreign_id = $twuid;
+ $flink->service = TWITTER_SERVICE;
+
+ $creds = TwitterOAuthClient::packToken($access_token);
+
+ $flink->credentials = $creds;
+ $flink->created = common_sql_now();
+
+ // Defaults: noticesync on, everything else off
+
+ $flink->set_flags(true, false, false, false);
+
+ $flink_id = $flink->insert();
+
+ if (empty($flink_id)) {
+ common_log_db_error($flink, 'INSERT', __FILE__);
+ // TRANS: Server error displayed when linking to a Twitter account fails.
+ $this->serverError(_m('Could not link your Twitter account.'));
+ }
+
+ return $flink_id;
+ }
+
+ function showPageNotice()
+ {
+ if ($this->error) {
+ $this->element('div', array('class' => 'error'), $this->error);
+ } else {
+ $this->element('div', 'instructions',
+ // TRANS: Page instruction. %s is the StatusNet sitename.
+ sprintf(_m('This is the first time you have logged into %s so we must connect your Twitter account to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
+ }
+ }
+
+ function title()
+ {
+ // TRANS: Page title.
+ return _m('Twitter Account Setup');
+ }
+
+ function showForm($error=null, $username=null)
+ {
+ $this->error = $error;
+ $this->username = $username;
+
+ $this->showPage();
+ }
+
+ function showPage()
+ {
+ parent::showPage();
+ }
+
+ /**
+ * @fixme much of this duplicates core code, which is very fragile.
+ * Should probably be replaced with an extensible mini version of
+ * the core registration form.
+ */
+ function showContent()
+ {
+ if (!empty($this->message_text)) {
+ $this->element('p', null, $this->message);
+ return;
+ }
+
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'form_settings_twitter_connect',
+ 'class' => 'form_settings',
+ 'action' => common_local_url('twitterauthorization')));
+ $this->elementStart('fieldset', array('id' => 'settings_twitter_connect_options'));
+ // TRANS: Fieldset legend.
+ $this->element('legend', null, _m('Connection options'));
+
+ $this->hidden('access_token_key', $this->access_token->key);
+ $this->hidden('access_token_secret', $this->access_token->secret);
+ $this->hidden('twuid', $this->twuid);
+ $this->hidden('tw_fields_screen_name', $this->tw_fields['screen_name']);
+ $this->hidden('tw_fields_name', $this->tw_fields['fullname']);
+ $this->hidden('token', common_session_token());
+
+ // Don't allow new account creation if site is flagged as invite only
+ if (common_config('site', 'inviteonly') == false) {
+ $this->elementStart('fieldset');
+ $this->element('legend', null,
+ // TRANS: Fieldset legend.
+ _m('Create new account'));
+ $this->element('p', null,
+ // TRANS: Sub form introduction text.
+ _m('Create a new user with this nickname.'));
+ $this->elementStart('ul', 'form_data');
+
+ // Hook point for captcha etc
+ Event::handle('StartRegistrationFormData', array($this));
+
+ $this->elementStart('li');
+ // TRANS: Field label.
+ $this->input('newname', _m('New nickname'),
+ ($this->username) ? $this->username : '',
+ // TRANS: Field title for nickname field.
+ _m('1-64 lowercase letters or numbers, no punctuation or spaces.'));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ // TRANS: Field label.
+ $this->input('email', _m('LABEL','Email'), $this->getEmail(),
+ // TRANS: Field title for e-mail address field.
+ _m('Used only for updates, announcements, '.
+ 'and password recovery'));
+ $this->elementEnd('li');
+
+ // Hook point for captcha etc
+ Event::handle('EndRegistrationFormData', array($this));
+
+ $this->elementEnd('ul');
+ // TRANS: Button text for creating a new StatusNet account in the Twitter connect page.
+ $this->submit('create', _m('BUTTON','Create'));
+ $this->elementEnd('fieldset');
+ }
+
+ $this->elementStart('fieldset');
+ $this->element('legend', null,
+ // TRANS: Fieldset legend.
+ _m('Connect existing account'));
+ $this->element('p', null,
+ // TRANS: Sub form introduction text.
+ _m('If you already have an account, login with your username and password to connect it to your Twitter account.'));
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ // TRANS: Field label.
+ $this->input('nickname', _m('Existing nickname'));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ // TRANS: Field label.
+ $this->password('password', _m('Password'));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->elementEnd('fieldset');
+
+ $this->elementStart('fieldset');
+ $this->element('legend', null,
+ // TRANS: Fieldset legend.
+ _m('License'));
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->element('input', array('type' => 'checkbox',
+ 'id' => 'license',
+ 'class' => 'checkbox',
+ 'name' => 'license',
+ 'value' => 'true'));
+ $this->elementStart('label', array('class' => 'checkbox', 'for' => 'license'));
+ // TRANS: Text for license agreement checkbox.
+ // TRANS: %s is the license as configured for the StatusNet site.
+ $message = _m('My text and files are available under %s ' .
+ 'except this private data: password, ' .
+ 'email address, IM address, and phone number.');
+ $link = '<a href="' .
+ htmlspecialchars(common_config('license', 'url')) .
+ '">' .
+ htmlspecialchars(common_config('license', 'title')) .
+ '</a>';
+ $this->raw(sprintf(htmlspecialchars($message), $link));
+ $this->elementEnd('label');
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->elementEnd('fieldset');
+ // TRANS: Button text for connecting an existing StatusNet account in the Twitter connect page..
+ $this->submit('connect', _m('BUTTON','Connect'));
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+ }
+
+ /**
+ * Get specified e-mail from the form, or the invite code.
+ *
+ * @return string
+ */
+ function getEmail()
+ {
+ $email = $this->trimmed('email');
+ if (!empty($email)) {
+ return $email;
+ }
+
+ // Terrible hack for invites...
+ if (common_config('site', 'inviteonly')) {
+ $code = $_SESSION['invitecode'];
+ if ($code) {
+ $invite = Invitation::getKV($code);
+
+ if ($invite && $invite->address_type == 'email') {
+ return $invite->address;
+ }
+ }
+ }
+ return '';
+ }
+
+ function message($msg)
+ {
+ $this->message_text = $msg;
+ $this->showPage();
+ }
+
+ function createNewUser()
+ {
+ if (!Event::handle('StartRegistrationTry', array($this))) {
+ return;
+ }
+
+ if (common_config('site', 'closed')) {
+ // TRANS: Client error displayed when trying to create a new user while creating new users is not allowed.
+ $this->clientError(_m('Registration not allowed.'));
+ return;
+ }
+
+ $invite = null;
+
+ if (common_config('site', 'inviteonly')) {
+ $code = $_SESSION['invitecode'];
+ if (empty($code)) {
+ // TRANS: Client error displayed when trying to create a new user while creating new users is not allowed.
+ $this->clientError(_m('Registration not allowed.'));
+ return;
+ }
+
+ $invite = Invitation::getKV($code);
+
+ if (empty($invite)) {
+ // TRANS: Client error displayed when trying to create a new user with an invalid invitation code.
+ $this->clientError(_m('Not a valid invitation code.'));
+ return;
+ }
+ }
+
+ try {
+ $nickname = Nickname::normalize($this->trimmed('newname'));
+ } catch (NicknameException $e) {
+ $this->showForm($e->getMessage());
+ return;
+ }
+
+ if (!User::allowed_nickname($nickname)) {
+ // TRANS: Client error displayed when trying to create a new user with an invalid username.
+ $this->showForm(_m('Nickname not allowed.'));
+ return;
+ }
+
+ if (User::getKV('nickname', $nickname)) {
+ // TRANS: Client error displayed when trying to create a new user with a username that is already in use.
+ $this->showForm(_m('Nickname already in use. Try another one.'));
+ return;
+ }
+
+ $fullname = trim($this->tw_fields['fullname']);
+
+ $args = array('nickname' => $nickname, 'fullname' => $fullname);
+
+ if (!empty($invite)) {
+ $args['code'] = $invite->code;
+ }
+
+ $email = $this->getEmail();
+ if (!empty($email)) {
+ $args['email'] = $email;
+ }
+
+ $user = User::register($args);
+
+ if (empty($user)) {
+ // TRANS: Server error displayed when creating a new user has failed.
+ $this->serverError(_m('Error registering user.'));
+ return;
+ }
+
+ $result = $this->saveForeignLink($user->id,
+ $this->twuid,
+ $this->access_token);
+
+ save_twitter_user($this->twuid, $this->tw_fields['screen_name']);
+
+ if (!$result) {
+ // TRANS: Server error displayed when connecting a user to a Twitter user has failed.
+ $this->serverError(_m('Error connecting user to Twitter.'));
+ return;
+ }
+
+ common_set_user($user);
+ common_real_login(true);
+
+ common_debug('TwitterBridge Plugin - ' .
+ "Registered new user $user->id from Twitter user $this->twuid");
+
+ Event::handle('EndRegistrationTry', array($this));
+
+ common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
+ 303);
+ }
+
+ function connectNewUser()
+ {
+ $nickname = $this->trimmed('nickname');
+ $password = $this->trimmed('password');
+
+ if (!common_check_user($nickname, $password)) {
+ // TRANS: Form validation error displayed when connecting an existing user to a Twitter user fails because
+ // TRANS: the provided username and/or password are incorrect.
+ $this->showForm(_m('Invalid username or password.'));
+ return;
+ }
+
+ $user = User::getKV('nickname', $nickname);
+
+ if (!empty($user)) {
+ common_debug('TwitterBridge Plugin - ' .
+ "Legit user to connect to Twitter: $nickname");
+ }
+
+ $result = $this->saveForeignLink($user->id,
+ $this->twuid,
+ $this->access_token);
+
+ save_twitter_user($this->twuid, $this->tw_fields['screen_name']);
+
+ if (!$result) {
+ // TRANS: Server error displayed connecting a user to a Twitter user has failed.
+ $this->serverError(_m('Error connecting user to Twitter.'));
+ return;
+ }
+
+ common_debug('TwitterBridge Plugin - ' .
+ "Connected Twitter user $this->twuid to local user $user->id");
+
+ common_set_user($user);
+ common_real_login(true);
+
+ $this->goHome($user->nickname);
+ }
+
+ function connectUser()
+ {
+ $user = common_current_user();
+
+ $result = $this->flinkUser($user->id, $this->twuid);
+
+ if (empty($result)) {
+ // TRANS: Server error displayed connecting a user to a Twitter user has failed.
+ $this->serverError(_m('Error connecting user to Twitter.'));
+ return;
+ }
+
+ common_debug('TwitterBridge Plugin - ' .
+ "Connected Twitter user $this->twuid to local user $user->id");
+
+ // Return to Twitter connection settings tab
+ common_redirect(common_local_url('twittersettings'), 303);
+ }
+
+ function tryLogin()
+ {
+ common_debug('TwitterBridge Plugin - ' .
+ "Trying login for Twitter user $this->twuid.");
+
+ $flink = Foreign_link::getByForeignID($this->twuid,
+ TWITTER_SERVICE);
+
+ if (!empty($flink)) {
+ $user = $flink->getUser();
+
+ if (!empty($user)) {
+
+ common_debug('TwitterBridge Plugin - ' .
+ "Logged in Twitter user $flink->foreign_id as user $user->id ($user->nickname)");
+
+ common_set_user($user);
+ common_real_login(true);
+ $this->goHome($user->nickname);
+ }
+
+ } else {
+
+ common_debug('TwitterBridge Plugin - ' .
+ "No flink found for twuid: $this->twuid - new user");
+
+ $this->showForm(null, $this->bestNewNickname());
+ }
+ }
+
+ function goHome($nickname)
+ {
+ $url = common_get_returnto();
+ if ($url) {
+ // We don't have to return to it again
+ common_set_returnto(null);
+ } else {
+ $url = common_local_url('all',
+ array('nickname' =>
+ $nickname));
+ }
+
+ common_redirect($url, 303);
+ }
+
+ function bestNewNickname()
+ {
+ if (!empty($this->tw_fields['fullname'])) {
+ $nickname = $this->nicknamize($this->tw_fields['fullname']);
+ if ($this->isNewNickname($nickname)) {
+ return $nickname;
+ }
+ }
+
+ return null;
+ }
+
+ // Given a string, try to make it work as a nickname
+
+ function nicknamize($str)
+ {
+ $str = preg_replace('/\W/', '', $str);
+ $str = str_replace(array('-', '_'), '', $str);
+ return strtolower($str);
+ }
+
+ function isNewNickname($str)
+ {
+ if (!Nickname::isValid($str)) {
+ return false;
+ }
+ if (!User::allowed_nickname($str)) {
+ return false;
+ }
+ if (User::getKV('nickname', $str)) {
+ return false;
+ }
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * 'Sign in with Twitter' login page
+ *
+ * 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 Login
+ * @package StatusNet
+ * @author Julien Chaumond <chaumond@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
+
+/**
+ * Page for logging in with Twitter
+ *
+ * @category Login
+ * @package StatusNet
+ * @author Julien Chaumond <chaumond@gmail.com>
+ * @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
+ * @link http://status.net/
+ *
+ * @see SettingsAction
+ */
+class TwitterloginAction extends Action
+{
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (common_is_real_login()) {
+ // TRANS: Client error displayed when trying to log in using Twitter while already logged in to StatusNet.
+ $this->clientError(_m('Already logged in.'));
+ }
+
+ $this->showPage();
+ }
+
+ function title()
+ {
+ // TRANS: Title for login using Twitter page.
+ return _m('TITLE','Twitter Login');
+ }
+
+ function getInstructions()
+ {
+ // TRANS: Instructions for login using Twitter page.
+ return _m('Login with your Twitter account');
+ }
+
+ function showPageNotice()
+ {
+ $instr = $this->getInstructions();
+ $output = common_markup_to_html($instr);
+ $this->elementStart('div', 'instructions');
+ $this->raw($output);
+ $this->elementEnd('div');
+ }
+
+ function showContent()
+ {
+ $this->elementStart('a', array('href' => common_local_url('twitterauthorization',
+ null,
+ array('signin' => true))));
+ $this->element('img', array('src' => Plugin::staticPath('TwitterBridge', 'Sign-in-with-Twitter-lighter.png'),
+ // TRANS: Alternative text for "sign in with Twitter" image.
+ 'alt' => _m('Sign in with Twitter')));
+ $this->elementEnd('a');
+ }
+
+ function showLocalNav()
+ {
+ $nav = new LoginGroupNav($this);
+ $nav->show();
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Settings for Twitter integration
+ *
+ * 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 Settings
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
+
+/**
+ * Settings for Twitter integration
+ *
+ * @category Settings
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ * @see SettingsAction
+ */
+class TwittersettingsAction extends ProfileSettingsAction
+{
+ /**
+ * Title of the page
+ *
+ * @return string Title of the page
+ */
+
+ function title()
+ {
+ // TRANS: Title for page with Twitter integration settings.
+ return _m('Twitter settings');
+ }
+
+ /**
+ * Instructions for use
+ *
+ * @return instructions for use
+ */
+
+ function getInstructions()
+ {
+ // TRANS: Instructions for page with Twitter integration settings.
+ return _m('Connect your Twitter account to share your updates ' .
+ 'with your Twitter friends and vice-versa.');
+ }
+
+ /**
+ * Content area of the page
+ *
+ * Shows a form for associating a Twitter account with this
+ * StatusNet account. Also lets the user set preferences.
+ *
+ * @return void
+ */
+ function showContent()
+ {
+
+ $user = common_current_user();
+
+ $profile = $user->getProfile();
+
+ $fuser = null;
+
+ $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
+
+ if (!empty($flink)) {
+ $fuser = $flink->getForeignUser();
+ }
+
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'form_settings_twitter',
+ 'class' => 'form_settings',
+ 'action' =>
+ common_local_url('twittersettings')));
+
+ $this->hidden('token', common_session_token());
+
+ $this->elementStart('fieldset', array('id' => 'settings_twitter_account'));
+
+ if (empty($fuser)) {
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li', array('id' => 'settings_twitter_login_button'));
+ $this->element('a', array('href' => common_local_url('twitterauthorization')),
+ // TRANS: Link description to connect to a Twitter account.
+ 'Connect my Twitter account');
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+
+ $this->elementEnd('fieldset');
+ } else {
+ // TRANS: Fieldset legend.
+ $this->element('legend', null, _m('Twitter account'));
+ $this->elementStart('p', array('id' => 'form_confirmed'));
+ $this->element('a', array('href' => $fuser->uri), $fuser->nickname);
+ $this->elementEnd('p');
+ $this->element('p', 'form_note',
+ // TRANS: Form note when a Twitter account has been connected.
+ _m('Connected Twitter account'));
+ $this->elementEnd('fieldset');
+
+ $this->elementStart('fieldset');
+
+ // TRANS: Fieldset legend.
+ $this->element('legend', null, _m('Disconnect my account from Twitter'));
+
+ if (!$user->password) {
+ $this->elementStart('p', array('class' => 'form_guide'));
+ // TRANS: Form guide. %s is a URL to the password settings.
+ // TRANS: This message contains a Markdown link in the form [description](link).
+ $message = sprintf(_m('Disconnecting your Twitter account ' .
+ 'could make it impossible to log in! Please ' .
+ '[set a password](%s) first.'),
+ common_local_url('passwordsettings'));
+ $message = common_markup_to_html($message);
+ $this->text($message);
+ $this->elementEnd('p');
+ } else {
+ // TRANS: Form instructions. %1$s is the StatusNet sitename.
+ $note = _m('Keep your %1$s account but disconnect from Twitter. ' .
+ 'You can use your %1$s password to log in.');
+ $site = common_config('site', 'name');
+
+ $this->element('p', 'instructions',
+ sprintf($note, $site));
+
+ // TRANS: Button text for disconnecting a Twitter account.
+ $this->submit('disconnect', _m('BUTTON','Disconnect'));
+ }
+
+ $this->elementEnd('fieldset');
+
+ $this->elementStart('fieldset', array('id' => 'settings_twitter_preferences'));
+
+ // TRANS: Fieldset legend.
+ $this->element('legend', null, _m('Preferences'));
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->checkbox('noticesend',
+ // TRANS: Checkbox label.
+ _m('Automatically send my notices to Twitter.'),
+ ($flink) ?
+ ($flink->noticesync & FOREIGN_NOTICE_SEND) :
+ true);
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ $this->checkbox('replysync',
+ // TRANS: Checkbox label.
+ _m('Send local "@" replies to Twitter.'),
+ ($flink) ?
+ ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) :
+ true);
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ $this->checkbox('friendsync',
+ // TRANS: Checkbox label.
+ _m('Subscribe to my Twitter friends here.'),
+ ($flink) ?
+ ($flink->friendsync & FOREIGN_FRIEND_RECV) :
+ false);
+ $this->elementEnd('li');
+
+ if (common_config('twitterimport','enabled')) {
+ $this->elementStart('li');
+ $this->checkbox('noticerecv',
+ // TRANS: Checkbox label.
+ _m('Import my friends timeline.'),
+ ($flink) ?
+ ($flink->noticesync & FOREIGN_NOTICE_RECV) :
+ false);
+ $this->elementEnd('li');
+ } else {
+ // preserve setting even if bidrection bridge toggled off
+
+ if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) {
+ $this->hidden('noticerecv', true, 'noticerecv');
+ }
+ }
+
+ $this->elementEnd('ul');
+
+ if ($flink) {
+ // TRANS: Button text for saving Twitter integration settings.
+ $this->submit('save', _m('BUTTON','Save'));
+ } else {
+ // TRANS: Button text for adding Twitter integration.
+ $this->submit('add', _m('BUTTON','Add'));
+ }
+
+ $this->elementEnd('fieldset');
+ }
+
+ $this->elementEnd('form');
+ }
+
+ /**
+ * Handle posts to this form
+ *
+ * Based on the button that was pressed, muxes out to other functions
+ * to do the actual task requested.
+ *
+ * All sub-functions reload the form with a message -- success or failure.
+ *
+ * @return void
+ */
+ function handlePost()
+ {
+ // CSRF protection
+ $token = $this->trimmed('token');
+ if (!$token || $token != common_session_token()) {
+ // TRANS: Client error displayed when the session token does not match or is not given.
+ $this->showForm(_m('There was a problem with your session token. '.
+ 'Try again, please.'));
+ return;
+ }
+
+ if ($this->arg('save')) {
+ $this->savePreferences();
+ } else if ($this->arg('disconnect')) {
+ $this->removeTwitterAccount();
+ } else {
+ // TRANS: Client error displayed when the submitted form contains unexpected data.
+ $this->showForm(_m('Unexpected form submission.'));
+ }
+ }
+
+ /**
+ * Disassociate an existing Twitter account from this account
+ *
+ * @return void
+ */
+ function removeTwitterAccount()
+ {
+ $user = common_current_user();
+ $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
+
+ if (empty($flink)) {
+ // TRANS: Client error displayed when trying to remove a connected Twitter account when there isn't one connected.
+ $this->clientError(_m('No Twitter connection to remove.'));
+ return;
+ }
+
+ $result = $flink->safeDelete();
+
+ if (empty($result)) {
+ common_log_db_error($flink, 'DELETE', __FILE__);
+ // TRANS: Server error displayed when trying to remove a connected Twitter account fails.
+ $this->serverError(_m('Could not remove Twitter user.'));
+ return;
+ }
+
+ // TRANS: Success message displayed after disconnecting a Twitter account.
+ $this->showForm(_m('Twitter account disconnected.'), true);
+ }
+
+ /**
+ * Save user's Twitter-bridging preferences
+ *
+ * @return void
+ */
+ function savePreferences()
+ {
+ $noticesend = $this->boolean('noticesend');
+ $noticerecv = $this->boolean('noticerecv');
+ $friendsync = $this->boolean('friendsync');
+ $replysync = $this->boolean('replysync');
+
+ $user = common_current_user();
+ $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
+
+ if (empty($flink)) {
+ common_log_db_error($flink, 'SELECT', __FILE__);
+ // @todo FIXME: Shouldn't this be a serverError()?
+ // TRANS: Server error displayed when saving Twitter integration preferences fails.
+ $this->showForm(_m('Could not save Twitter preferences.'));
+ return;
+ }
+
+ $original = clone($flink);
+ $wasReceiving = (bool)($original->noticesync & FOREIGN_NOTICE_RECV);
+ $flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
+ $result = $flink->update($original);
+
+ if ($result === false) {
+ common_log_db_error($flink, 'UPDATE', __FILE__);
+ // @todo FIXME: Shouldn't this be a serverError()?
+ // TRANS: Server error displayed when saving Twitter integration preferences fails.
+ $this->showForm(_m('Could not save Twitter preferences.'));
+ return;
+ }
+
+ if ($wasReceiving xor $noticerecv) {
+ $this->notifyDaemon($flink->foreign_id, $noticerecv);
+ }
+
+ // TRANS: Success message after saving Twitter integration preferences.
+ $this->showForm(_m('Twitter preferences saved.'), true);
+ }
+
+ /**
+ * Tell the import daemon that we've updated a user's receive status.
+ */
+ function notifyDaemon($twitterUserId, $receiving)
+ {
+ // @todo... should use control signals rather than queues
+ }
+}
--- /dev/null
+<?php
+/**
+ * Data class for remembering notice-to-status mappings
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for mapping notices to statuses
+ *
+ * Notices flow back and forth between Twitter and StatusNet. We use this
+ * table to remember which StatusNet notice corresponds to which Twitter
+ * status.
+ *
+ * Note that notice_id is unique only within a single database; if you
+ * want to share this data for some reason, get the notice's URI and use
+ * that instead, since it's universally unique.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+
+class Notice_to_status extends Managed_DataObject
+{
+ public $__table = 'notice_to_status'; // table name
+ public $notice_id; // int(4) primary_key not_null
+ public $status_id; // bigint not_null
+ public $created; // datetime() not_null
+ public $modified; // datetime not_null default_0000-00-00%2000%3A00%3A00
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'notice_id' => array('type' => 'int', 'not null' => true, 'description' => 'local notice id'),
+ 'status_id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'twitter status id'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('notice_id'),
+ 'unique keys' => array(
+ 'status_id_key' => array('status_id'),
+ ),
+ 'foreign keys' => array(
+ 'notice_to_status_notice_id_fkey' => array('notice', array('notice_id' => 'id')),
+ ),
+ );
+ }
+
+ /**
+ * Save a mapping between a notice and a status
+ * Warning: status_id values may not fit in 32-bit integers.
+ *
+ * @param integer $notice_id ID of the notice in StatusNet
+ * @param integer $status_id ID of the status in Twitter
+ *
+ * @return Notice_to_status new object for this value
+ */
+ static function saveNew($notice_id, $status_id)
+ {
+ if (empty($notice_id)) {
+ throw new Exception("Invalid notice_id $notice_id");
+ }
+ $n2s = Notice_to_status::getKV('notice_id', $notice_id);
+
+ if (!empty($n2s)) {
+ return $n2s;
+ }
+
+ if (empty($status_id)) {
+ throw new Exception("Invalid status_id $status_id");
+ }
+ $n2s = Notice_to_status::getKV('status_id', $status_id);
+
+ if (!empty($n2s)) {
+ return $n2s;
+ }
+
+ common_debug("Mapping notice {$notice_id} to Twitter status {$status_id}");
+
+ $n2s = new Notice_to_status();
+
+ $n2s->notice_id = $notice_id;
+ $n2s->status_id = $status_id;
+ $n2s->created = common_sql_now();
+
+ $n2s->insert();
+
+ return $n2s;
+ }
+}
--- /dev/null
+<?php
+/**
+ * Store last-touched ID for various timelines
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Store various timeline data
+ *
+ * We don't want to keep re-fetching the same statuses and direct messages from Twitter.
+ * So, we store the last ID we see from a timeline, and store it. Next time
+ * around, we use that ID in the since_id parameter.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * @see DB_DataObject
+ */
+class Twitter_synch_status extends Managed_DataObject
+{
+ public $__table = 'twitter_synch_status'; // table name
+ public $foreign_id; // bigint primary_key not_null
+ public $timeline; // varchar(255) primary_key not_null
+ public $last_id; // bigint not_null
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'foreign_id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'Foreign message ID'),
+ 'timeline' => array('type' => 'varchar', 'length' => 255, 'description' => 'timeline name'),
+ 'last_id' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'last id fetched'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('foreign_id', 'timeline'),
+ );
+ }
+
+ static function getLastId($foreign_id, $timeline)
+ {
+ $tss = self::pkeyGet(array('foreign_id' => $foreign_id,
+ 'timeline' => $timeline));
+
+ if (empty($tss)) {
+ return null;
+ } else {
+ return $tss->last_id;
+ }
+ }
+
+ static function setLastId($foreign_id, $timeline, $last_id)
+ {
+ $tss = self::pkeyGet(array('foreign_id' => $foreign_id,
+ 'timeline' => $timeline));
+
+ if (empty($tss)) {
+ $tss = new Twitter_synch_status();
+
+ $tss->foreign_id = $foreign_id;
+ $tss->timeline = $timeline;
+ $tss->last_id = $last_id;
+ $tss->created = common_sql_now();
+ $tss->modified = $tss->created;
+
+ $tss->insert();
+
+ return true;
+ } else {
+ $orig = clone($tss);
+
+ $tss->last_id = $last_id;
+ $tss->modified = common_sql_now();
+
+ $tss->update();
+
+ return true;
+ }
+ }
+}
require_once INSTALLDIR . '/lib/common.php';
require_once INSTALLDIR . '/lib/daemon.php';
require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
-require_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php';
+require_once INSTALLDIR . '/plugins/TwitterBridge/lib/twitteroauthclient.php';
/**
* Fetch statuses from Twitter
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * 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
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-class OAuthData
-{
- public $consumer_key, $consumer_secret, $token, $token_secret;
-}
-
-/**
- *
- */
-abstract class JsonStreamReader
-{
- const CRLF = "\r\n";
-
- public $id;
- protected $socket = null;
- protected $state = 'init'; // 'init', 'connecting', 'waiting', 'headers', 'active'
-
- public function __construct()
- {
- $this->id = get_class($this) . '.' . substr(md5(mt_rand()), 0, 8);
- }
-
- /**
- * Starts asynchronous connect operation...
- *
- * @fixme Can we do the open-socket fully async to? (need write select infrastructure)
- *
- * @param string $url
- */
- public function connect($url)
- {
- common_log(LOG_DEBUG, "$this->id opening connection to $url");
-
- $scheme = parse_url($url, PHP_URL_SCHEME);
- if ($scheme == 'http') {
- $rawScheme = 'tcp';
- } else if ($scheme == 'https') {
- $rawScheme = 'ssl';
- } else {
- // TRANS: Server exception thrown when an invalid URL scheme is detected.
- throw new ServerException(_m('Invalid URL scheme for HTTP stream reader.'));
- }
-
- $host = parse_url($url, PHP_URL_HOST);
- $port = parse_url($url, PHP_URL_PORT);
- if (!$port) {
- if ($scheme == 'https') {
- $port = 443;
- } else {
- $port = 80;
- }
- }
-
- $path = parse_url($url, PHP_URL_PATH);
- $query = parse_url($url, PHP_URL_QUERY);
- if ($query) {
- $path .= '?' . $query;
- }
-
- $errno = $errstr = null;
- $timeout = 5;
- //$flags = STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT;
- $flags = STREAM_CLIENT_CONNECT;
- // @fixme add SSL params
- $this->socket = stream_socket_client("$rawScheme://$host:$port", $errno, $errstr, $timeout, $flags);
-
- $this->send($this->httpOpen($host, $path));
-
- stream_set_blocking($this->socket, false);
- $this->state = 'waiting';
- }
-
- /**
- * Send some fun data off to the server.
- *
- * @param string $buffer
- */
- function send($buffer)
- {
- fwrite($this->socket, $buffer);
- }
-
- /**
- * Read next packet of data from the socket.
- *
- * @return string
- */
- function read()
- {
- $buffer = fread($this->socket, 65536);
- return $buffer;
- }
-
- /**
- * Build HTTP request headers.
- *
- * @param string $host
- * @param string $path
- * @return string
- */
- protected function httpOpen($host, $path)
- {
- $lines = array(
- "GET $path HTTP/1.1",
- "Host: $host",
- "User-Agent: StatusNet/" . STATUSNET_VERSION . " (TwitterBridgePlugin)",
- "Connection: close",
- "",
- ""
- );
- return implode(self::CRLF, $lines);
- }
-
- /**
- * Close the current connection, if open.
- */
- public function close()
- {
- if ($this->isConnected()) {
- common_log(LOG_DEBUG, "$this->id closing connection.");
- fclose($this->socket);
- $this->socket = null;
- }
- }
-
- /**
- * Are we currently connected?
- *
- * @return boolean
- */
- public function isConnected()
- {
- return $this->socket !== null;
- }
-
- /**
- * Send any sockets we're listening on to the IO manager
- * to wait for input.
- *
- * @return array of resources
- */
- public function getSockets()
- {
- if ($this->isConnected()) {
- return array($this->socket);
- }
- return array();
- }
-
- /**
- * Take a chunk of input over the horn and go go go! :D
- *
- * @param string $buffer
- */
- public function handleInput($socket)
- {
- if ($this->socket !== $socket) {
- // TRANS: Exception thrown when input from an inexpected socket is encountered.
- throw new Exception(_m('Got input from unexpected socket!'));
- }
-
- try {
- $buffer = $this->read();
- $lines = explode(self::CRLF, $buffer);
- foreach ($lines as $line) {
- $this->handleLine($line);
- }
- } catch (Exception $e) {
- common_log(LOG_ERR, "$this->id aborting connection due to error: " . $e->getMessage());
- fclose($this->socket);
- throw $e;
- }
- }
-
- protected function handleLine($line)
- {
- switch ($this->state)
- {
- case 'waiting':
- $this->handleLineWaiting($line);
- break;
- case 'headers':
- $this->handleLineHeaders($line);
- break;
- case 'active':
- $this->handleLineActive($line);
- break;
- default:
- // TRANS: Exception thrown when an invalid state is encountered in handleLine.
- // TRANS: %s is the invalid state.
- throw new Exception(sprintf(_m('Invalid state in handleLine: %s.'),$this->state));
- }
- }
-
- /**
- *
- * @param <type> $line
- */
- protected function handleLineWaiting($line)
- {
- $bits = explode(' ', $line, 3);
- if (count($bits) != 3) {
- // TRANS: Exception thrown when an invalid response line is encountered.
- // TRANS: %s is the invalid line.
- throw new Exception(sprintf(_m('Invalid HTTP response line: %s.'),$line));
- }
-
- list($http, $status, $text) = $bits;
- if (substr($http, 0, 5) != 'HTTP/') {
- // TRANS: Exception thrown when an invalid response line part is encountered.
- // TRANS: %1$s is the chunk, %2$s is the line.
- throw new Exception(sprintf(_m('Invalid HTTP response line chunk "%1$s": %2$s.'),$http, $line));
- }
- if ($status != '200') {
- // TRANS: Exception thrown when an invalid response code is encountered.
- // TRANS: %1$s is the response code, %2$s is the line.
- throw new Exception(sprintf(_m('Bad HTTP response code %1$s: %2$s.'),$status,$line));
- }
- common_log(LOG_DEBUG, "$this->id $line");
- $this->state = 'headers';
- }
-
- protected function handleLineHeaders($line)
- {
- if ($line == '') {
- $this->state = 'active';
- common_log(LOG_DEBUG, "$this->id connection is active!");
- } else {
- common_log(LOG_DEBUG, "$this->id read HTTP header: $line");
- $this->responseHeaders[] = $line;
- }
- }
-
- protected function handleLineActive($line)
- {
- if ($line == "") {
- // Server sends empty lines as keepalive.
- return;
- }
- $data = json_decode($line);
- if ($data) {
- $this->handleJson($data);
- } else {
- common_log(LOG_ERR, "$this->id received bogus JSON data: " . var_export($line, true));
- }
- }
-
- abstract protected function handleJson(stdClass $data);
-}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * 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
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class OAuthData
+{
+ public $consumer_key, $consumer_secret, $token, $token_secret;
+}
+
+/**
+ *
+ */
+abstract class JsonStreamReader
+{
+ const CRLF = "\r\n";
+
+ public $id;
+ protected $socket = null;
+ protected $state = 'init'; // 'init', 'connecting', 'waiting', 'headers', 'active'
+
+ public function __construct()
+ {
+ $this->id = get_class($this) . '.' . substr(md5(mt_rand()), 0, 8);
+ }
+
+ /**
+ * Starts asynchronous connect operation...
+ *
+ * @fixme Can we do the open-socket fully async to? (need write select infrastructure)
+ *
+ * @param string $url
+ */
+ public function connect($url)
+ {
+ common_log(LOG_DEBUG, "$this->id opening connection to $url");
+
+ $scheme = parse_url($url, PHP_URL_SCHEME);
+ if ($scheme == 'http') {
+ $rawScheme = 'tcp';
+ } else if ($scheme == 'https') {
+ $rawScheme = 'ssl';
+ } else {
+ // TRANS: Server exception thrown when an invalid URL scheme is detected.
+ throw new ServerException(_m('Invalid URL scheme for HTTP stream reader.'));
+ }
+
+ $host = parse_url($url, PHP_URL_HOST);
+ $port = parse_url($url, PHP_URL_PORT);
+ if (!$port) {
+ if ($scheme == 'https') {
+ $port = 443;
+ } else {
+ $port = 80;
+ }
+ }
+
+ $path = parse_url($url, PHP_URL_PATH);
+ $query = parse_url($url, PHP_URL_QUERY);
+ if ($query) {
+ $path .= '?' . $query;
+ }
+
+ $errno = $errstr = null;
+ $timeout = 5;
+ //$flags = STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT;
+ $flags = STREAM_CLIENT_CONNECT;
+ // @fixme add SSL params
+ $this->socket = stream_socket_client("$rawScheme://$host:$port", $errno, $errstr, $timeout, $flags);
+
+ $this->send($this->httpOpen($host, $path));
+
+ stream_set_blocking($this->socket, false);
+ $this->state = 'waiting';
+ }
+
+ /**
+ * Send some fun data off to the server.
+ *
+ * @param string $buffer
+ */
+ function send($buffer)
+ {
+ fwrite($this->socket, $buffer);
+ }
+
+ /**
+ * Read next packet of data from the socket.
+ *
+ * @return string
+ */
+ function read()
+ {
+ $buffer = fread($this->socket, 65536);
+ return $buffer;
+ }
+
+ /**
+ * Build HTTP request headers.
+ *
+ * @param string $host
+ * @param string $path
+ * @return string
+ */
+ protected function httpOpen($host, $path)
+ {
+ $lines = array(
+ "GET $path HTTP/1.1",
+ "Host: $host",
+ "User-Agent: StatusNet/" . STATUSNET_VERSION . " (TwitterBridgePlugin)",
+ "Connection: close",
+ "",
+ ""
+ );
+ return implode(self::CRLF, $lines);
+ }
+
+ /**
+ * Close the current connection, if open.
+ */
+ public function close()
+ {
+ if ($this->isConnected()) {
+ common_log(LOG_DEBUG, "$this->id closing connection.");
+ fclose($this->socket);
+ $this->socket = null;
+ }
+ }
+
+ /**
+ * Are we currently connected?
+ *
+ * @return boolean
+ */
+ public function isConnected()
+ {
+ return $this->socket !== null;
+ }
+
+ /**
+ * Send any sockets we're listening on to the IO manager
+ * to wait for input.
+ *
+ * @return array of resources
+ */
+ public function getSockets()
+ {
+ if ($this->isConnected()) {
+ return array($this->socket);
+ }
+ return array();
+ }
+
+ /**
+ * Take a chunk of input over the horn and go go go! :D
+ *
+ * @param string $buffer
+ */
+ public function handleInput($socket)
+ {
+ if ($this->socket !== $socket) {
+ // TRANS: Exception thrown when input from an inexpected socket is encountered.
+ throw new Exception(_m('Got input from unexpected socket!'));
+ }
+
+ try {
+ $buffer = $this->read();
+ $lines = explode(self::CRLF, $buffer);
+ foreach ($lines as $line) {
+ $this->handleLine($line);
+ }
+ } catch (Exception $e) {
+ common_log(LOG_ERR, "$this->id aborting connection due to error: " . $e->getMessage());
+ fclose($this->socket);
+ throw $e;
+ }
+ }
+
+ protected function handleLine($line)
+ {
+ switch ($this->state)
+ {
+ case 'waiting':
+ $this->handleLineWaiting($line);
+ break;
+ case 'headers':
+ $this->handleLineHeaders($line);
+ break;
+ case 'active':
+ $this->handleLineActive($line);
+ break;
+ default:
+ // TRANS: Exception thrown when an invalid state is encountered in handleLine.
+ // TRANS: %s is the invalid state.
+ throw new Exception(sprintf(_m('Invalid state in handleLine: %s.'),$this->state));
+ }
+ }
+
+ /**
+ *
+ * @param <type> $line
+ */
+ protected function handleLineWaiting($line)
+ {
+ $bits = explode(' ', $line, 3);
+ if (count($bits) != 3) {
+ // TRANS: Exception thrown when an invalid response line is encountered.
+ // TRANS: %s is the invalid line.
+ throw new Exception(sprintf(_m('Invalid HTTP response line: %s.'),$line));
+ }
+
+ list($http, $status, $text) = $bits;
+ if (substr($http, 0, 5) != 'HTTP/') {
+ // TRANS: Exception thrown when an invalid response line part is encountered.
+ // TRANS: %1$s is the chunk, %2$s is the line.
+ throw new Exception(sprintf(_m('Invalid HTTP response line chunk "%1$s": %2$s.'),$http, $line));
+ }
+ if ($status != '200') {
+ // TRANS: Exception thrown when an invalid response code is encountered.
+ // TRANS: %1$s is the response code, %2$s is the line.
+ throw new Exception(sprintf(_m('Bad HTTP response code %1$s: %2$s.'),$status,$line));
+ }
+ common_log(LOG_DEBUG, "$this->id $line");
+ $this->state = 'headers';
+ }
+
+ protected function handleLineHeaders($line)
+ {
+ if ($line == '') {
+ $this->state = 'active';
+ common_log(LOG_DEBUG, "$this->id connection is active!");
+ } else {
+ common_log(LOG_DEBUG, "$this->id read HTTP header: $line");
+ $this->responseHeaders[] = $line;
+ }
+ }
+
+ protected function handleLineActive($line)
+ {
+ if ($line == "") {
+ // Server sends empty lines as keepalive.
+ return;
+ }
+ $data = json_decode($line);
+ if ($data) {
+ $this->handleJson($data);
+ } else {
+ common_log(LOG_ERR, "$this->id received bogus JSON data: " . var_export($line, true));
+ }
+ }
+
+ abstract protected function handleJson(stdClass $data);
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
+
+/**
+ * Queue handler to deal with incoming Twitter status updates, as retrieved by
+ * TwitterDaemon (twitterdaemon.php).
+ *
+ * The queue handler passes the status through TwitterImporter for import into the
+ * local database (if necessary), then adds the imported notice to the local inbox
+ * of the attached Twitter user.
+ *
+ * Warning: the way we do inbox distribution manually means that realtime, XMPP, etc
+ * don't work on Twitter-borne messages. When TwitterImporter is changed to handle
+ * that correctly, we'll only need to do this once...?
+ */
+class TweetInQueueHandler extends QueueHandler
+{
+ function transport()
+ {
+ return 'tweetin';
+ }
+
+ function handle($data)
+ {
+ // JSON object with Twitter data
+ $status = $data['status'];
+
+ // Twitter user ID this incoming data belongs to.
+ $receiver = $data['for_user'];
+
+ $importer = new TwitterImport();
+ $notice = $importer->importStatus($status);
+ if ($notice) {
+ $flink = Foreign_link::getByForeignID($receiver, TWITTER_SERVICE);
+ if ($flink) {
+ common_log(LOG_DEBUG, "TweetInQueueHandler - Got flink so add notice ".
+ $notice->id." to inbox ".$flink->user_id);
+ // @fixme this should go through more regular channels?
+ Inbox::insertNotice($flink->user_id, $notice->id);
+ }else {
+ common_log(LOG_DEBUG, "TweetInQueueHandler - No flink found for foreign user ".$receiver);
+ }
+ }
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * 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
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Julien C <chaumond@gmail.com>
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2009-2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
+
+/**
+ * Encapsulation of the Twitter status -> notice incoming bridge import.
+ * Is used by both the polling twitterstatusfetcher.php daemon, and the
+ * in-progress streaming import.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Julien C <chaumond@gmail.com>
+ * @author Brion Vibber <brion@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ * @link http://twitter.com/
+ */
+class TwitterImport
+{
+ public function importStatus($status)
+ {
+ // Hacktastic: filter out stuff coming from this StatusNet
+ $source = mb_strtolower(common_config('integration', 'source'));
+
+ if (preg_match("/$source/", mb_strtolower($status->source))) {
+ common_debug($this->name() . ' - Skipping import of status ' .
+ twitter_id($status) . ' with source ' . $source);
+ return null;
+ }
+
+ // Don't save it if the user is protected
+ // FIXME: save it but treat it as private
+ if ($status->user->protected) {
+ return null;
+ }
+
+ $notice = $this->saveStatus($status);
+
+ return $notice;
+ }
+
+ function name()
+ {
+ return get_class($this);
+ }
+
+ function saveStatus($status)
+ {
+ $profile = $this->ensureProfile($status->user);
+
+ if (empty($profile)) {
+ common_log(LOG_ERR, $this->name() .
+ ' - Problem saving notice. No associated Profile.');
+ return null;
+ }
+
+ $statusId = twitter_id($status);
+ $statusUri = $this->makeStatusURI($status->user->screen_name, $statusId);
+
+ // check to see if we've already imported the status
+ $n2s = Notice_to_status::getKV('status_id', $statusId);
+
+ if (!empty($n2s)) {
+ common_log(
+ LOG_INFO,
+ $this->name() .
+ " - Ignoring duplicate import: {$statusId}"
+ );
+ return Notice::getKV('id', $n2s->notice_id);
+ }
+
+ // If it's a retweet, save it as a repeat!
+ if (!empty($status->retweeted_status)) {
+ common_log(LOG_INFO, "Status {$statusId} is a retweet of " . twitter_id($status->retweeted_status) . ".");
+ $original = $this->saveStatus($status->retweeted_status);
+ if (empty($original)) {
+ return null;
+ } else {
+ $author = $original->getProfile();
+ // TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
+ // TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
+ $content = sprintf(_m('RT @%1$s %2$s'),
+ $author->nickname,
+ $original->content);
+
+ if (Notice::contentTooLong($content)) {
+ $contentlimit = Notice::maxContent();
+ $content = mb_substr($content, 0, $contentlimit - 4) . ' ...';
+ }
+
+ $repeat = Notice::saveNew($profile->id,
+ $content,
+ 'twitter',
+ array('repeat_of' => $original->id,
+ 'uri' => $statusUri,
+ 'is_local' => Notice::GATEWAY));
+ common_log(LOG_INFO, "Saved {$repeat->id} as a repeat of {$original->id}");
+ Notice_to_status::saveNew($repeat->id, $statusId);
+ return $repeat;
+ }
+ }
+
+ $notice = new Notice();
+
+ $notice->profile_id = $profile->id;
+ $notice->uri = $statusUri;
+ $notice->url = $statusUri;
+ $notice->created = strftime(
+ '%Y-%m-%d %H:%M:%S',
+ strtotime($status->created_at)
+ );
+
+ $notice->source = 'twitter';
+
+ $notice->reply_to = null;
+
+ $replyTo = twitter_id($status, 'in_reply_to_status_id');
+ if (!empty($replyTo)) {
+ common_log(LOG_INFO, "Status {$statusId} is a reply to status {$replyTo}");
+ $n2s = Notice_to_status::getKV('status_id', $replyTo);
+ if (empty($n2s)) {
+ common_log(LOG_INFO, "Couldn't find local notice for status {$replyTo}");
+ } else {
+ $reply = Notice::getKV('id', $n2s->notice_id);
+ if (empty($reply)) {
+ common_log(LOG_INFO, "Couldn't find local notice for status {$replyTo}");
+ } else {
+ common_log(LOG_INFO, "Found local notice {$reply->id} for status {$replyTo}");
+ $notice->reply_to = $reply->id;
+ $notice->conversation = $reply->conversation;
+ }
+ }
+ }
+
+ if (empty($notice->conversation)) {
+ $conv = Conversation::create();
+ $notice->conversation = $conv->id;
+ common_log(LOG_INFO, "No known conversation for status {$statusId} so making a new one {$conv->id}.");
+ }
+
+ $notice->is_local = Notice::GATEWAY;
+
+ $notice->content = html_entity_decode($this->linkify($status, FALSE), ENT_QUOTES, 'UTF-8');
+ $notice->rendered = $this->linkify($status, TRUE);
+
+ if (Event::handle('StartNoticeSave', array(&$notice))) {
+
+ $id = $notice->insert();
+
+ if (!$id) {
+ common_log_db_error($notice, 'INSERT', __FILE__);
+ common_log(LOG_ERR, $this->name() .
+ ' - Problem saving notice.');
+ }
+
+ Event::handle('EndNoticeSave', array($notice));
+ }
+
+ Notice_to_status::saveNew($notice->id, $statusId);
+
+ $this->saveStatusMentions($notice, $status);
+ $this->saveStatusAttachments($notice, $status);
+
+ $notice->blowOnInsert();
+
+ return $notice;
+ }
+
+ /**
+ * Make an URI for a status.
+ *
+ * @param object $status status object
+ *
+ * @return string URI
+ */
+ function makeStatusURI($username, $id)
+ {
+ return 'http://twitter.com/#!/'
+ . $username
+ . '/status/'
+ . $id;
+ }
+
+
+ /**
+ * Look up a Profile by profileurl field. Profile::getKV() was
+ * not working consistently.
+ *
+ * @param string $nickname local nickname of the Twitter user
+ * @param string $profileurl the profile url
+ *
+ * @return mixed value the first Profile with that url, or null
+ */
+ function getProfileByUrl($nickname, $profileurl)
+ {
+ $profile = new Profile();
+ $profile->nickname = $nickname;
+ $profile->profileurl = $profileurl;
+ $profile->limit(1);
+
+ if ($profile->find()) {
+ $profile->fetch();
+ return $profile;
+ }
+
+ return null;
+ }
+
+ /**
+ * Check to see if this Twitter status has already been imported
+ *
+ * @param Profile $profile Twitter user's local profile
+ * @param string $statusUri URI of the status on Twitter
+ *
+ * @return mixed value a matching Notice or null
+ */
+ function checkDupe($profile, $statusUri)
+ {
+ $notice = new Notice();
+ $notice->uri = $statusUri;
+ $notice->profile_id = $profile->id;
+ $notice->limit(1);
+
+ if ($notice->find()) {
+ $notice->fetch();
+ return $notice;
+ }
+
+ return null;
+ }
+
+ function ensureProfile($user)
+ {
+ // check to see if there's already a profile for this user
+ $profileurl = 'http://twitter.com/' . $user->screen_name;
+ $profile = $this->getProfileByUrl($user->screen_name, $profileurl);
+
+ if (!empty($profile)) {
+ common_debug($this->name() .
+ " - Profile for $profile->nickname found.");
+
+ // Check to see if the user's Avatar has changed
+
+ $this->checkAvatar($user, $profile);
+ return $profile;
+
+ } else {
+ common_debug($this->name() . ' - Adding profile and remote profile ' .
+ "for Twitter user: $profileurl.");
+
+ $profile = new Profile();
+ $profile->query("BEGIN");
+
+ $profile->nickname = $user->screen_name;
+ $profile->fullname = $user->name;
+ $profile->homepage = $user->url;
+ $profile->bio = $user->description;
+ $profile->location = $user->location;
+ $profile->profileurl = $profileurl;
+ $profile->created = common_sql_now();
+
+ try {
+ $id = $profile->insert();
+ } catch(Exception $e) {
+ common_log(LOG_WARNING, $this->name() . ' Couldn\'t insert profile - ' . $e->getMessage());
+ }
+
+ if (empty($id)) {
+ common_log_db_error($profile, 'INSERT', __FILE__);
+ $profile->query("ROLLBACK");
+ return false;
+ }
+
+ // check for remote profile
+
+ $remote_pro = Remote_profile::getKV('uri', $profileurl);
+
+ if (empty($remote_pro)) {
+ $remote_pro = new Remote_profile();
+
+ $remote_pro->id = $id;
+ $remote_pro->uri = $profileurl;
+ $remote_pro->created = common_sql_now();
+
+ try {
+ $rid = $remote_pro->insert();
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $this->name() . ' Couldn\'t save remote profile - ' . $e->getMessage());
+ }
+
+ if (empty($rid)) {
+ common_log_db_error($profile, 'INSERT', __FILE__);
+ $profile->query("ROLLBACK");
+ return false;
+ }
+ }
+
+ $profile->query("COMMIT");
+
+ $this->saveAvatars($user, $id);
+
+ return $profile;
+ }
+ }
+
+ function checkAvatar($twitter_user, $profile)
+ {
+ global $config;
+
+ $newname = 'Twitter_' . $twitter_user->id . '_' . basename($twitter_user->profile_image_url);
+
+ $oldname = $profile->getAvatar(48)->filename;
+
+ if ($newname != $oldname) {
+ common_debug($this->name() . ' - Avatar for Twitter user ' .
+ "$profile->nickname has changed.");
+ common_debug($this->name() . " - old: $oldname new: $newname");
+
+ $this->updateAvatars($twitter_user, $profile);
+ }
+
+ if ($this->missingAvatarFile($profile)) {
+ common_debug($this->name() . ' - Twitter user ' .
+ $profile->nickname .
+ ' is missing one or more local avatars.');
+ common_debug($this->name() ." - old: $oldname new: $newname");
+
+ $this->updateAvatars($twitter_user, $profile);
+ }
+ }
+
+ function updateAvatars($twitter_user, $profile) {
+
+ global $config;
+
+ $path_parts = pathinfo($twitter_user->profile_image_url);
+
+ $ext = (isset($path_parts['extension']) ? '.'.$path_parts['extension'] : ''); // some lack extension
+ $img_root = basename($path_parts['basename'], '_normal'.$ext); // cut off extension
+ $mediatype = $this->getMediatype(substr($ext, 1));
+
+ foreach (array('mini', 'normal', 'bigger') as $size) {
+ $url = $path_parts['dirname'] . '/' .
+ $img_root . '_' . $size . $ext;
+ $filename = 'Twitter_' . $twitter_user->id . '_' .
+ $img_root . '_' . $size . $ext;
+
+ $this->updateAvatar($profile->id, $size, $mediatype, $filename);
+ $this->fetchAvatar($url, $filename);
+ }
+ }
+
+ function missingAvatarFile($profile) {
+ foreach (array(24, 48, 73) as $size) {
+ $filename = $profile->getAvatar($size)->filename;
+ $avatarpath = Avatar::path($filename);
+ if (file_exists($avatarpath) == FALSE) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ function getMediatype($ext)
+ {
+ $mediatype = null;
+
+ switch (strtolower($ext)) {
+ case 'jpeg':
+ case 'jpg':
+ $mediatype = 'image/jpeg';
+ break;
+ case 'gif':
+ $mediatype = 'image/gif';
+ break;
+ default:
+ $mediatype = 'image/png';
+ }
+
+ return $mediatype;
+ }
+
+ function saveAvatars($user, $id)
+ {
+ global $config;
+
+ $path_parts = pathinfo($user->profile_image_url);
+ $ext = (isset($path_parts['extension']) ? '.'.$path_parts['extension'] : '');
+ $img_root = basename($path_parts['basename'], '_normal'.$ext);
+ $mediatype = $this->getMediatype(substr($ext, 1));
+
+ foreach (array('mini', 'normal', 'bigger') as $size) {
+ $url = $path_parts['dirname'] . '/' .
+ $img_root . '_' . $size . $ext;
+ $filename = 'Twitter_' . $user->id . '_' .
+ $img_root . '_' . $size . $ext;
+
+ if ($this->fetchAvatar($url, $filename)) {
+ $this->newAvatar($id, $size, $mediatype, $filename);
+ } else {
+ common_log(LOG_WARNING, $id() .
+ " - Problem fetching Avatar: $url");
+ }
+ }
+ }
+
+ function updateAvatar($profile_id, $size, $mediatype, $filename) {
+
+ common_debug($this->name() . " - Updating avatar: $size");
+
+ $profile = Profile::getKV($profile_id);
+
+ if (empty($profile)) {
+ common_debug($this->name() . " - Couldn't get profile: $profile_id!");
+ return;
+ }
+
+ $sizes = array('mini' => 24, 'normal' => 48, 'bigger' => 73);
+ $avatar = $profile->getAvatar($sizes[$size]);
+
+ // Delete the avatar, if present
+ if ($avatar) {
+ $avatar->delete();
+ }
+
+ $this->newAvatar($profile->id, $size, $mediatype, $filename);
+ }
+
+ function newAvatar($profile_id, $size, $mediatype, $filename)
+ {
+ global $config;
+
+ $avatar = new Avatar();
+ $avatar->profile_id = $profile_id;
+
+ switch($size) {
+ case 'mini':
+ $avatar->width = 24;
+ $avatar->height = 24;
+ break;
+ case 'normal':
+ $avatar->width = 48;
+ $avatar->height = 48;
+ break;
+ default:
+ // Note: Twitter's big avatars are a different size than
+ // StatusNet's (StatusNet's = 96)
+ $avatar->width = 73;
+ $avatar->height = 73;
+ }
+
+ $avatar->original = 0; // we don't have the original
+ $avatar->mediatype = $mediatype;
+ $avatar->filename = $filename;
+ $avatar->url = Avatar::url($filename);
+
+ $avatar->created = common_sql_now();
+
+ try {
+ $id = $avatar->insert();
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $this->name() . ' Couldn\'t insert avatar - ' . $e->getMessage());
+ }
+
+ if (empty($id)) {
+ common_log_db_error($avatar, 'INSERT', __FILE__);
+ return null;
+ }
+
+ common_debug($this->name() .
+ " - Saved new $size avatar for $profile_id.");
+
+ return $id;
+ }
+
+ /**
+ * Fetch a remote avatar image and save to local storage.
+ *
+ * @param string $url avatar source URL
+ * @param string $filename bare local filename for download
+ * @return bool true on success, false on failure
+ */
+ function fetchAvatar($url, $filename)
+ {
+ common_debug($this->name() . " - Fetching Twitter avatar: $url");
+
+ $request = HTTPClient::start();
+ $response = $request->get($url);
+ if ($response->isOk()) {
+ $avatarfile = Avatar::path($filename);
+ $ok = file_put_contents($avatarfile, $response->getBody());
+ if (!$ok) {
+ common_log(LOG_WARNING, $this->name() .
+ " - Couldn't open file $filename");
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ const URL = 1;
+ const HASHTAG = 2;
+ const MENTION = 3;
+
+ function linkify($status, $html = FALSE)
+ {
+ $text = $status->text;
+
+ if (empty($status->entities)) {
+ $statusId = twitter_id($status);
+ common_log(LOG_WARNING, "No entities data for {$statusId}; trying to fake up links ourselves.");
+ $text = common_replace_urls_callback($text, 'common_linkify');
+ $text = preg_replace('/(^|\"\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/e', "'\\1#'.TwitterStatusFetcher::tagLink('\\2')", $text);
+ $text = preg_replace('/(^|\s+)@([a-z0-9A-Z_]{1,64})/e', "'\\1@'.TwitterStatusFetcher::atLink('\\2')", $text);
+ return $text;
+ }
+
+ // Move all the entities into order so we can
+ // replace them and escape surrounding plaintext
+ // in order
+
+ $toReplace = array();
+
+ if (!empty($status->entities->urls)) {
+ foreach ($status->entities->urls as $url) {
+ $toReplace[$url->indices[0]] = array(self::URL, $url);
+ }
+ }
+
+ if (!empty($status->entities->hashtags)) {
+ foreach ($status->entities->hashtags as $hashtag) {
+ $toReplace[$hashtag->indices[0]] = array(self::HASHTAG, $hashtag);
+ }
+ }
+
+ if (!empty($status->entities->user_mentions)) {
+ foreach ($status->entities->user_mentions as $mention) {
+ $toReplace[$mention->indices[0]] = array(self::MENTION, $mention);
+ }
+ }
+
+ // sort in forward order by key
+
+ ksort($toReplace);
+
+ $result = '';
+ $cursor = 0;
+
+ foreach ($toReplace as $part) {
+ list($type, $object) = $part;
+ $start = $object->indices[0];
+ $end = $object->indices[1];
+ if ($cursor < $start) {
+ // Copy in the preceding plaintext
+ $result .= $this->twitEscape(mb_substr($text, $cursor, $start - $cursor));
+ $cursor = $start;
+ }
+ $orig = $this->twitEscape(mb_substr($text, $start, $end - $start));
+ switch($type) {
+ case self::URL:
+ $linkText = $this->makeUrlLink($object, $orig, $html);
+ break;
+ case self::HASHTAG:
+ if ($html) {
+ $linkText = $this->makeHashtagLink($object, $orig);
+ }else{
+ $linkText = $orig;
+ }
+ break;
+ case self::MENTION:
+ if ($html) {
+ $linkText = $this->makeMentionLink($object, $orig);
+ }else{
+ $linkText = $orig;
+ }
+ break;
+ default:
+ $linkText = $orig;
+ continue;
+ }
+ $result .= $linkText;
+ $cursor = $end;
+ }
+ $last = $this->twitEscape(mb_substr($text, $cursor));
+ $result .= $last;
+
+ return $result;
+ }
+
+ function twitEscape($str)
+ {
+ // Twitter seems to preemptive turn < and > into < and >
+ // but doesn't for &, so while you may have some magic protection
+ // against XSS by not bothing to escape manually, you still get
+ // invalid XHTML. Thanks!
+ //
+ // Looks like their web interface pretty much sends anything
+ // through intact, so.... to do equivalent, decode all entities
+ // and then re-encode the special ones.
+ return htmlspecialchars(html_entity_decode($str, ENT_COMPAT, 'UTF-8'));
+ }
+
+ function makeUrlLink($object, $orig, $html)
+ {
+ if ($html) {
+ return '<a href="'.htmlspecialchars($object->expanded_url).'" class="extlink">'.htmlspecialchars($object->display_url).'</a>';
+ }else{
+ return htmlspecialchars($object->expanded_url);
+ }
+ }
+
+ function makeHashtagLink($object, $orig)
+ {
+ return "#" . self::tagLink($object->text, substr($orig, 1));
+ }
+
+ function makeMentionLink($object, $orig)
+ {
+ return "@".self::atLink($object->screen_name, $object->name, substr($orig, 1));
+ }
+
+ static function tagLink($tag, $orig)
+ {
+ return "<a href='https://search.twitter.com/search?q=%23{$tag}' class='hashtag'>{$orig}</a>";
+ }
+
+ static function atLink($screenName, $fullName, $orig)
+ {
+ if (!empty($fullName)) {
+ return "<a href='http://twitter.com/#!/{$screenName}' title='{$fullName}'>{$orig}</a>";
+ } else {
+ return "<a href='http://twitter.com/#!/{$screenName}'>{$orig}</a>";
+ }
+ }
+
+ function saveStatusMentions($notice, $status)
+ {
+ $mentions = array();
+
+ if (empty($status->entities) || empty($status->entities->user_mentions)) {
+ return;
+ }
+
+ foreach ($status->entities->user_mentions as $mention) {
+ $flink = Foreign_link::getByForeignID($mention->id, TWITTER_SERVICE);
+ if (!empty($flink)) {
+ $user = User::getKV('id', $flink->user_id);
+ if (!empty($user)) {
+ $reply = new Reply();
+ $reply->notice_id = $notice->id;
+ $reply->profile_id = $user->id;
+ $reply->modified = $notice->created;
+ common_log(LOG_INFO, __METHOD__ . ": saving reply: notice {$notice->id} to profile {$user->id}");
+ $id = $reply->insert();
+ }
+ }
+ }
+ }
+
+ /**
+ * Record URL links from the notice. Needed to get thumbnail records
+ * for referenced photo and video posts, etc.
+ *
+ * @param Notice $notice
+ * @param object $status
+ */
+ function saveStatusAttachments($notice, $status)
+ {
+ if (common_config('attachments', 'process_links')) {
+ if (!empty($status->entities) && !empty($status->entities->urls)) {
+ foreach ($status->entities->urls as $url) {
+ File::processNew($url->url, $notice->id);
+ }
+ }
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Class for doing OAuth calls against Twitter
+ *
+ * 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 Integration
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009-2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Class for talking to the Twitter API with OAuth.
+ *
+ * @category Integration
+ * @package StatusNet
+ * @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
+ * @link http://status.net/
+ *
+ */
+class TwitterOAuthClient extends OAuthClient
+{
+ public static $requestTokenURL = 'https://api.twitter.com/oauth/request_token';
+ public static $authorizeURL = 'https://api.twitter.com/oauth/authorize';
+ public static $signinUrl = 'https://api.twitter.com/oauth/authenticate';
+ public static $accessTokenURL = 'https://api.twitter.com/oauth/access_token';
+
+ /**
+ * Constructor
+ *
+ * @param string $oauth_token the user's token
+ * @param string $oauth_token_secret the user's token secret
+ *
+ * @return nothing
+ */
+ function __construct($oauth_token = null, $oauth_token_secret = null)
+ {
+ $consumer_key = common_config('twitter', 'consumer_key');
+ $consumer_secret = common_config('twitter', 'consumer_secret');
+
+ if (empty($consumer_key) && empty($consumer_secret)) {
+ $consumer_key = common_config(
+ 'twitter',
+ 'global_consumer_key'
+ );
+ $consumer_secret = common_config(
+ 'twitter',
+ 'global_consumer_secret'
+ );
+ }
+
+ parent::__construct(
+ $consumer_key,
+ $consumer_secret,
+ $oauth_token,
+ $oauth_token_secret
+ );
+ }
+
+ // XXX: the following two functions are to support the horrible hack
+ // of using the credentils field in Foreign_link to store both
+ // the access token and token secret. This hack should go away with
+ // 0.9, in which we can make DB changes and add a new column for the
+ // token itself.
+
+ static function packToken($token)
+ {
+ return implode(chr(0), array($token->key, $token->secret));
+ }
+
+ static function unpackToken($str)
+ {
+ $vals = explode(chr(0), $str);
+ return new OAuthToken($vals[0], $vals[1]);
+ }
+
+ static function isPackedToken($str)
+ {
+ if (strpos($str, chr(0)) === false) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Gets a request token from Twitter
+ *
+ * @return OAuthToken $token the request token
+ */
+ function getRequestToken()
+ {
+ return parent::getRequestToken(
+ self::$requestTokenURL,
+ common_local_url('twitterauthorization')
+ );
+ }
+
+ /**
+ * Builds a link to Twitter's endpoint for authorizing a request token
+ *
+ * @param OAuthToken $request_token token to authorize
+ *
+ * @return the link
+ */
+ function getAuthorizeLink($request_token, $signin = false)
+ {
+ $url = ($signin) ? self::$signinUrl : self::$authorizeURL;
+
+ return parent::getAuthorizeLink($url,
+ $request_token,
+ common_local_url('twitterauthorization'));
+ }
+
+ /**
+ * Fetches an access token from Twitter
+ *
+ * @param string $verifier 1.0a verifier
+ *
+ * @return OAuthToken $token the access token
+ */
+ function getAccessToken($verifier = null)
+ {
+ return parent::getAccessToken(
+ self::$accessTokenURL,
+ $verifier
+ );
+ }
+
+ /**
+ * Calls Twitter's /account/verify_credentials API method
+ *
+ * @return mixed the Twitter user
+ */
+ function verifyCredentials()
+ {
+ $url = 'https://api.twitter.com/1.1/account/verify_credentials.json';
+ $response = $this->oAuthGet($url);
+ $twitter_user = json_decode($response);
+ return $twitter_user;
+ }
+
+ /**
+ * Calls Twitter's /statuses/update API method
+ *
+ * @param string $status text of the status
+ * @param mixed $params optional other parameters to pass to Twitter,
+ * as defined. For back-compatibility, if an int
+ * is passed we'll consider it a reply-to ID.
+ *
+ * @return mixed the status
+ */
+ function statusesUpdate($status, $params=array())
+ {
+ $url = 'https://api.twitter.com/1.1/statuses/update.json';
+ if (is_numeric($params)) {
+ $params = array('in_reply_to_status_id' => intval($params));
+ }
+ $params['status'] = $status;
+ // We don't have to pass 'source' as the oauth key is tied to an app.
+
+ $response = $this->oAuthPost($url, $params);
+ $status = json_decode($response);
+ return $status;
+ }
+
+ /**
+ * Calls Twitter's /statuses/home_timeline API method
+ *
+ * @param int $since_id show statuses after this id
+ * @param string $timelineUri timeline to poll statuses from
+ * @param int $max_id show statuses before this id
+ * @param int $cnt number of statuses to show
+ * @param int $page page number
+ *
+ * @return mixed an array of statuses
+ */
+ function statusesTimeline($since_id = null, $timelineUri = 'home_timeline',
+ $max_id = null, $cnt = 200, $page = null)
+ {
+ $url = 'https://api.twitter.com/1.1/statuses/'.$timelineUri.'.json';
+
+ $params = array('include_entities' => 'true',
+ 'include_rts' => 'true');
+
+ if (!empty($since_id)) {
+ $params['since_id'] = $since_id;
+ }
+ if (!empty($max_id)) {
+ $params['max_id'] = $max_id;
+ }
+ if (!empty($cnt)) {
+ $params['count'] = $cnt;
+ }
+ if (!empty($page)) {
+ $params['page'] = $page;
+ }
+
+ $response = $this->oAuthGet($url, $params);
+ $statuses = json_decode($response);
+ return $statuses;
+ }
+
+ /**
+ * Calls Twitter's /statuses/friends API method
+ *
+ * @param int $id id of the user whom you wish to see friends of
+ * @param int $user_id numerical user id
+ * @param int $screen_name screen name
+ * @param int $page page number
+ *
+ * @return mixed an array of twitter users and their latest status
+ */
+ function statusesFriends($id = null, $user_id = null, $screen_name = null,
+ $page = null)
+ {
+ $url = "https://api.twitter.com/1.1/friends/list.json";
+
+ $params = array();
+
+ if (!empty($id)) {
+ $params['id'] = $id;
+ }
+
+ if (!empty($user_id)) {
+ $params['user_id'] = $user_id;
+ }
+
+ if (!empty($screen_name)) {
+ $params['screen_name'] = $screen_name;
+ }
+
+ if (!empty($page)) {
+ $params['page'] = $page;
+ }
+
+ $response = $this->oAuthGet($url, $params);
+ $friends = json_decode($response);
+ return $friends;
+ }
+
+ /**
+ * Calls Twitter's /statuses/friends/ids API method
+ *
+ * @param int $id id of the user whom you wish to see friends of
+ * @param int $user_id numerical user id
+ * @param int $screen_name screen name
+ * @param int $page page number
+ *
+ * @return mixed a list of ids, 100 per page
+ */
+ function friendsIds($id = null, $user_id = null, $screen_name = null,
+ $page = null)
+ {
+ $url = "https://api.twitter.com/1.1/friends/ids.json";
+
+ $params = array();
+
+ if (!empty($id)) {
+ $params['id'] = $id;
+ }
+
+ if (!empty($user_id)) {
+ $params['user_id'] = $user_id;
+ }
+
+ if (!empty($screen_name)) {
+ $params['screen_name'] = $screen_name;
+ }
+
+ if (!empty($page)) {
+ $params['page'] = $page;
+ }
+
+ $response = $this->oAuthGet($url, $params);
+ $ids = json_decode($response);
+ return $ids;
+ }
+
+ /**
+ * Calls Twitter's /statuses/retweet/id.json API method
+ *
+ * @param int $id id of the notice to retweet
+ *
+ * @return retweeted status
+ */
+
+ function statusesRetweet($id)
+ {
+ $url = "http://api.twitter.com/1.1/statuses/retweet/$id.json";
+ $response = $this->oAuthPost($url);
+ $status = json_decode($response);
+ return $status;
+ }
+
+ /**
+ * Calls Twitter's /favorites/create API method
+ *
+ * @param int $id ID of the status to favorite
+ *
+ * @return object faved status
+ */
+
+ function favoritesCreate($id)
+ {
+ $url = "http://api.twitter.com/1.1/favorites/create.json";
+ $params=array();
+ $params['id'] = $id;
+ $response = $this->oAuthPost($url, $params);
+ $status = json_decode($response);
+ return $status;
+ }
+
+ /**
+ * Calls Twitter's /favorites/destroy API method
+ *
+ * @param int $id ID of the status to unfavorite
+ *
+ * @return object unfaved status
+ */
+
+ function favoritesDestroy($id)
+ {
+ $url = "http://api.twitter.com/1.1/favorites/destroy.json";
+ $params=array();
+ $params['id'] = $id;
+ $response = $this->oAuthPost($url,$params);
+ $status = json_decode($response);
+ return $status;
+ }
+
+ /**
+ * Calls Twitter's /statuses/destroy API method
+ *
+ * @param int $id ID of the status to destroy
+ *
+ * @return object destroyed
+ */
+
+ function statusesDestroy($id)
+ {
+ $url = "http://api.twitter.com/1.1/statuses/destroy/$id.json";
+ $response = $this->oAuthPost($url);
+ $status = json_decode($response);
+ return $status;
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
+
+class TwitterQueueHandler extends QueueHandler
+{
+ function transport()
+ {
+ return 'twitter';
+ }
+
+ function handle($notice)
+ {
+ $ok = broadcast_twitter($notice);
+ return $ok || common_config('twitter', 'ignore_errors');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * 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
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+/**
+ * Multiuser stream listener for Twitter Site Streams API
+ * http://dev.twitter.com/pages/site_streams
+ *
+ * The site streams API allows listening to updates for multiple users.
+ * Pass in the user IDs to listen to in via followUser() -- note they
+ * must each have a valid OAuth token for the application ID we're
+ * connecting as.
+ *
+ * You'll need to be connecting with the auth keys for the user who
+ * owns the application registration.
+ *
+ * The user each message is destined for will be passed to event handlers
+ * in $context['for_user_id'].
+ */
+class TwitterSiteStream extends TwitterStreamReader
+{
+ protected $userIds;
+
+ public function __construct(TwitterOAuthClient $auth, $baseUrl='https://sitestream.twitter.com')
+ {
+ parent::__construct($auth, $baseUrl);
+ }
+
+ public function connect($method='2b/site.json')
+ {
+ $params = array();
+ if ($this->userIds) {
+ $params['follow'] = implode(',', $this->userIds);
+ }
+ return parent::connect($method, $params);
+ }
+
+ /**
+ * Set the users whose home streams should be pulled.
+ * They all must have valid oauth tokens for this application.
+ *
+ * Must be called before connect().
+ *
+ * @param array $userIds
+ */
+ function followUsers($userIds)
+ {
+ $this->userIds = $userIds;
+ }
+
+ /**
+ * Each message in the site stream tells us which user ID it should be
+ * routed to; we'll need that to let the caller know what to do.
+ *
+ * @param array $data
+ */
+ function routeMessage(stdClass $data)
+ {
+ $context = array(
+ 'source' => 'sitestream',
+ 'for_user' => $data->for_user
+ );
+ parent::handleMessage($data->message, $context);
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * 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
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+/**
+ * Base class for reading Twitter's User Streams and Site Streams
+ * real-time streaming APIs.
+ *
+ * Caller can hook event callbacks for various types of messages;
+ * the data from the stream and some context info will be passed
+ * on to the callbacks.
+ */
+abstract class TwitterStreamReader extends JsonStreamReader
+{
+ protected $callbacks = array();
+
+ function __construct(TwitterOAuthClient $auth, $baseUrl)
+ {
+ $this->baseUrl = $baseUrl;
+ $this->oauth = $auth;
+ }
+
+ public function connect($method, $params=array())
+ {
+ $url = $this->oAuthUrl($this->baseUrl . '/' . $method, $params);
+ return parent::connect($url);
+ }
+
+ /**
+ * Sign our target URL with OAuth auth stuff.
+ *
+ * @param string $url
+ * @param array $params
+ * @return string
+ */
+ protected function oAuthUrl($url, $params=array())
+ {
+ // In an ideal world this would be better encapsulated. :)
+ $request = OAuthRequest::from_consumer_and_token($this->oauth->consumer,
+ $this->oauth->token, 'GET', $url, $params);
+ $request->sign_request($this->oauth->sha1_method,
+ $this->oauth->consumer, $this->oauth->token);
+
+ return $request->to_url();
+ }
+
+ /**
+ * Add an event callback to receive notifications when things come in
+ * over the wire.
+ *
+ * Callbacks should be in the form: function(object $data, array $context)
+ * where $context may list additional data on some streams, such as the
+ * user to whom the message should be routed.
+ *
+ * Available events:
+ *
+ * Messaging:
+ *
+ * 'status': $data contains a status update in standard Twitter JSON format.
+ * $data->user: sending user in standard Twitter JSON format.
+ * $data->text... etc
+ *
+ * 'direct_message': $data contains a direct message in standard Twitter JSON format.
+ * $data->sender: sending user in standard Twitter JSON format.
+ * $data->recipient: receiving user in standard Twitter JSON format.
+ * $data->text... etc
+ *
+ *
+ * Out of band events:
+ *
+ * 'follow': User has either started following someone, or is being followed.
+ * $data->source: following user in standard Twitter JSON format.
+ * $data->target: followed user in standard Twitter JSON format.
+ *
+ * 'favorite': Someone has favorited a status update.
+ * $data->source: user doing the favoriting, in standard Twitter JSON format.
+ * $data->target: user whose status was favorited, in standard Twitter JSON format.
+ * $data->target_object: the favorited status update in standard Twitter JSON format.
+ *
+ * 'unfavorite': Someone has unfavorited a status update.
+ * $data->source: user doing the unfavoriting, in standard Twitter JSON format.
+ * $data->target: user whose status was unfavorited, in standard Twitter JSON format.
+ * $data->target_object: the unfavorited status update in standard Twitter JSON format.
+ *
+ *
+ * Meta information:
+ *
+ * 'friends':
+ * $data->friends: array of user IDs of the current user's friends.
+ *
+ * 'delete': Advisory that a Twitter status has been deleted; nice clients
+ * should follow suit.
+ * $data->id: ID of status being deleted
+ * $data->user_id: ID of its owning user
+ *
+ * 'scrub_geo': Advisory that a user is clearing geo data from their status
+ * stream; nice clients should follow suit.
+ * $data->user_id: ID of user
+ * $data->up_to_status_id: any notice older than this should be scrubbed.
+ *
+ * 'limit': Advisory that tracking has hit a resource limit.
+ * $data->track
+ *
+ * 'raw': receives the full JSON data for all message types.
+ *
+ * @param string $event
+ * @param callable $callback
+ */
+ public function hookEvent($event, $callback)
+ {
+ $this->callbacks[$event][] = $callback;
+ }
+
+ /**
+ * Call event handler callbacks for the given event.
+ *
+ * @param string $event
+ * @param mixed $arg1 ... one or more params to pass on
+ */
+ protected function fireEvent($event, $arg1)
+ {
+ if (array_key_exists($event, $this->callbacks)) {
+ $args = array_slice(func_get_args(), 1);
+ foreach ($this->callbacks[$event] as $callback) {
+ call_user_func_array($callback, $args);
+ }
+ }
+ }
+
+ protected function handleJson(stdClass $data)
+ {
+ $this->routeMessage($data);
+ }
+
+ abstract protected function routeMessage(stdClass $data);
+
+ /**
+ * Send the decoded JSON object out to any event listeners.
+ *
+ * @param array $data
+ * @param array $context optional additional context data to pass on
+ */
+ protected function handleMessage(stdClass $data, array $context=array())
+ {
+ $this->fireEvent('raw', $data, $context);
+
+ if (isset($data->text)) {
+ $this->fireEvent('status', $data, $context);
+ return;
+ }
+ if (isset($data->event)) {
+ $this->fireEvent($data->event, $data, $context);
+ return;
+ }
+ if (isset($data->friends)) {
+ $this->fireEvent('friends', $data, $context);
+ }
+
+ $knownMeta = array('delete', 'scrub_geo', 'limit', 'direct_message');
+ foreach ($knownMeta as $key) {
+ if (isset($data->$key)) {
+ $this->fireEvent($key, $data->$key, $context);
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * Multiuser stream listener for Twitter Site Streams API
+ * http://dev.twitter.com/pages/site_streams
+ *
+ * The site streams API allows listening to updates for multiple users.
+ * Pass in the user IDs to listen to in via followUser() -- note they
+ * must each have a valid OAuth token for the application ID we're
+ * connecting as.
+ *
+ * You'll need to be connecting with the auth keys for the user who
+ * owns the application registration.
+ *
+ * The user each message is destined for will be passed to event handlers
+ * in $context['for_user_id'].
+ */
+class TwitterSiteStream extends TwitterStreamReader
+{
+ protected $userIds;
+
+ public function __construct(TwitterOAuthClient $auth, $baseUrl='https://sitestream.twitter.com')
+ {
+ parent::__construct($auth, $baseUrl);
+ }
+
+ public function connect($method='2b/site.json')
+ {
+ $params = array();
+ if ($this->userIds) {
+ $params['follow'] = implode(',', $this->userIds);
+ }
+ return parent::connect($method, $params);
+ }
+
+ /**
+ * Set the users whose home streams should be pulled.
+ * They all must have valid oauth tokens for this application.
+ *
+ * Must be called before connect().
+ *
+ * @param array $userIds
+ */
+ function followUsers($userIds)
+ {
+ $this->userIds = $userIds;
+ }
+
+ /**
+ * Each message in the site stream tells us which user ID it should be
+ * routed to; we'll need that to let the caller know what to do.
+ *
+ * @param array $data
+ */
+ function routeMessage(stdClass $data)
+ {
+ $context = array(
+ 'source' => 'sitestream',
+ 'for_user' => $data->for_user
+ );
+ parent::handleMessage($data->message, $context);
+ }
+}
+
+/**
+ * Stream listener for Twitter User Streams API
+ * http://dev.twitter.com/pages/user_streams
+ *
+ * This will pull the home stream and additional events just for the user
+ * we've authenticated as.
+ */
+class TwitterUserStream extends TwitterStreamReader
+{
+ public function __construct(TwitterOAuthClient $auth, $baseUrl='https://userstream.twitter.com')
+ {
+ parent::__construct($auth, $baseUrl);
+ }
+
+ public function connect($method='2/user.json')
+ {
+ return parent::connect($method);
+ }
+
+ /**
+ * Each message in the user stream is just ready to go.
+ *
+ * @param array $data
+ */
+ function routeMessage(stdClass $data)
+ {
+ $context = array(
+ 'source' => 'userstream'
+ );
+ parent::handleMessage($data, $context);
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * 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
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+/**
+ * Stream listener for Twitter User Streams API
+ * http://dev.twitter.com/pages/user_streams
+ *
+ * This will pull the home stream and additional events just for the user
+ * we've authenticated as.
+ */
+class TwitterUserStream extends TwitterStreamReader
+{
+ public function __construct(TwitterOAuthClient $auth, $baseUrl='https://userstream.twitter.com')
+ {
+ parent::__construct($auth, $baseUrl);
+ }
+
+ public function connect($method='2/user.json')
+ {
+ return parent::connect($method);
+ }
+
+ /**
+ * Each message in the user stream is just ready to go.
+ *
+ * @param array $data
+ */
+ function routeMessage(stdClass $data)
+ {
+ $context = array(
+ 'source' => 'userstream'
+ );
+ parent::handleMessage($data, $context);
+ }
+}
ENDOFHELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
-require_once dirname(dirname(__FILE__)) . '/jsonstreamreader.php';
-require_once dirname(dirname(__FILE__)) . '/twitterstreamreader.php';
+require_once dirname(dirname(__FILE__)) . '/lib/jsonstreamreader.php';
+require_once dirname(dirname(__FILE__)) . '/lib/twitterstreamreader.php';
if (have_option('n')) {
$nickname = get_option_value('n');
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
-
-/**
- * Queue handler to deal with incoming Twitter status updates, as retrieved by
- * TwitterDaemon (twitterdaemon.php).
- *
- * The queue handler passes the status through TwitterImporter for import into the
- * local database (if necessary), then adds the imported notice to the local inbox
- * of the attached Twitter user.
- *
- * Warning: the way we do inbox distribution manually means that realtime, XMPP, etc
- * don't work on Twitter-borne messages. When TwitterImporter is changed to handle
- * that correctly, we'll only need to do this once...?
- */
-class TweetInQueueHandler extends QueueHandler
-{
- function transport()
- {
- return 'tweetin';
- }
-
- function handle($data)
- {
- // JSON object with Twitter data
- $status = $data['status'];
-
- // Twitter user ID this incoming data belongs to.
- $receiver = $data['for_user'];
-
- $importer = new TwitterImport();
- $notice = $importer->importStatus($status);
- if ($notice) {
- $flink = Foreign_link::getByForeignID($receiver, TWITTER_SERVICE);
- if ($flink) {
- common_log(LOG_DEBUG, "TweetInQueueHandler - Got flink so add notice ".
- $notice->id." to inbox ".$flink->user_id);
- // @fixme this should go through more regular channels?
- Inbox::insertNotice($flink->user_id, $notice->id);
- }else {
- common_log(LOG_DEBUG, "TweetInQueueHandler - No flink found for foreign user ".$receiver);
- }
- }
-
- return true;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Twitter bridge administration panel
- *
- * 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 Settings
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Administer global Twitter bridge settings
- *
- * @category Admin
- * @package StatusNet
- * @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
- * @link http://status.net/
- */
-class TwitteradminpanelAction extends AdminPanelAction
-{
- /**
- * Returns the page title
- *
- * @return string page title
- */
- function title()
- {
- // TRANS: Page title for Twitter administration panel.
- return _m('TITLE','Twitter');
- }
-
- /**
- * Instructions for using this form.
- *
- * @return string instructions
- */
- function getInstructions()
- {
- // TRANS: Instructions for Twitter bridge administration page.
- return _m('Twitter bridge settings');
- }
-
- /**
- * Show the Twitter admin panel form
- *
- * @return void
- */
- function showForm()
- {
- $form = new TwitterAdminPanelForm($this);
- $form->show();
- return;
- }
-
- /**
- * Save settings from the form
- *
- * @return void
- */
- function saveSettings()
- {
- static $settings = array(
- 'twitter' => array('consumer_key', 'consumer_secret'),
- 'integration' => array('source')
- );
-
- static $booleans = array(
- 'twitter' => array('signin')
- );
- if (Event::handle('TwitterBridgeAdminImportControl')) {
- $booleans['twitterimport'] = array('enabled');
- }
-
- $values = array();
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- $values[$section][$setting]
- = $this->trimmed($setting);
- }
- }
-
- foreach ($booleans as $section => $parts) {
- foreach ($parts as $setting) {
- $values[$section][$setting]
- = ($this->boolean($setting)) ? 1 : 0;
- }
- }
-
- // This throws an exception on validation errors
-
- $this->validate($values);
-
- // assert(all values are valid);
-
- $config = new Config();
-
- $config->query('BEGIN');
-
- foreach ($settings as $section => $parts) {
- foreach ($parts as $setting) {
- Config::save($section, $setting, $values[$section][$setting]);
- }
- }
-
- foreach ($booleans as $section => $parts) {
- foreach ($parts as $setting) {
- Config::save($section, $setting, $values[$section][$setting]);
- }
- }
-
- $config->query('COMMIT');
-
- // Flush the router cache: we may have enabled/disabled bridging,
- // which will add or remove some actions.
- $cache = Cache::instance();
- $cache->delete(Router::cacheKey());
-
- return;
- }
-
- function validate(&$values)
- {
- // Validate consumer key and secret (can't be too long)
-
- if (mb_strlen($values['twitter']['consumer_key']) > 255) {
- $this->clientError(
- // TRANS: Client error displayed when a consumer key is invalid because it is too long.
- _m('Invalid consumer key. Maximum length is 255 characters.')
- );
- }
-
- if (mb_strlen($values['twitter']['consumer_secret']) > 255) {
- $this->clientError(
- // TRANS: Client error displayed when a consumer secret is invalid because it is too long.
- _m('Invalid consumer secret. Maximum length is 255 characters.')
- );
- }
- }
-
- function isImportEnabled()
- {
- // Since daemon setup isn't automated yet...
- // @todo: if merged into main queues, detect presence of daemon config
- return true;
- }
-}
-
-class TwitterAdminPanelForm extends AdminForm
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
- function id()
- {
- return 'twitteradminpanel';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_settings';
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('twitteradminpanel');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->elementStart(
- 'fieldset',
- array('id' => 'settings_twitter-application')
- );
- // TRANS: Fieldset legend for Twitter application settings.
- $this->out->element('legend', null, _m('Twitter application settings'));
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
- $this->input(
- 'consumer_key',
- // TRANS: Field label for Twitter assigned consumer key.
- _m('Consumer key'),
- // TRANS: Field title for Twitter assigned consumer key.
- _m('The consumer key assigned by Twitter.'),
- 'twitter'
- );
- $this->unli();
-
- $this->li();
- $this->input(
- 'consumer_secret',
- // TRANS: Field label for Twitter assigned consumer secret.
- _m('Consumer secret'),
- // TRANS: Field title for Twitter assigned consumer secret.
- _m('The consumer secret assigned by Twitter.'),
- 'twitter'
- );
- $this->unli();
-
- $globalConsumerKey = common_config('twitter', 'global_consumer_key');
- $globalConsumerSec = common_config('twitter', 'global_consumer_secret');
-
- if (!empty($globalConsumerKey) && !empty($globalConsumerSec)) {
- $this->li();
- // TRANS: Form guide displayed when two required fields have already been provided.
- $this->out->element('p', 'form_guide', _m('Note: A global consumer key and secret are set.'));
- $this->unli();
- }
-
- $this->li();
- $this->input(
- 'source',
- // TRANS: Field label for Twitter application name.
- _m('Integration source'),
- // TRANS: Field title for Twitter application name.
- _m('The name of your Twitter application.'),
- 'integration'
- );
- $this->unli();
-
- $this->out->elementEnd('ul');
- $this->out->elementEnd('fieldset');
-
- $this->out->elementStart(
- 'fieldset',
- array('id' => 'settings_twitter-options')
- );
- // TRANS: Fieldset legend for Twitter integration options.
- $this->out->element('legend', null, _m('Options'));
-
- $this->out->elementStart('ul', 'form_data');
-
- $this->li();
-
- $this->out->checkbox(
- // TRANS: Checkbox label for global setting.
- 'signin', _m('Enable "Sign-in with Twitter"'),
- (bool) $this->value('signin', 'twitter'),
- // TRANS: Checkbox title.
- _m('This allow users to login with their Twitter credentials.')
- );
- $this->unli();
-
- if (Event::handle('TwitterBridgeAdminImportControl')) {
- $this->li();
- $this->out->checkbox(
- // TRANS: Checkbox label for global setting.
- 'enabled', _m('Enable Twitter import'),
- (bool) $this->value('enabled', 'twitterimport'),
- // TRANS: Checkbox title for global setting.
- _m('Allow users to import their Twitter friends\' timelines. Requires daemons to be manually configured.')
- );
- $this->unli();
- }
-
- $this->out->elementEnd('ul');
-
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
- function formActions()
- {
- // TRANS: Button text for saving the administrative Twitter bridge settings.
- $this->out->submit('submit', _m('BUTTON','Save'), 'submit', null,
- // TRANS: Button title for saving the administrative Twitter bridge settings.
- _m('Save the Twitter bridge settings.'));
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Class for doing OAuth authentication against Twitter
- *
- * 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
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @author Julien C <chaumond@gmail.com>
- * @copyright 2009-2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
-
-/**
- * Class for doing OAuth authentication against Twitter
- *
- * Peforms the OAuth "dance" between StatusNet and Twitter -- requests a token,
- * authorizes it, and exchanges it for an access token. It also creates a link
- * (Foreign_link) between the StatusNet user and Twitter user and stores the
- * access token and secret in the link.
- *
- * @category Plugin
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @author Julien C <chaumond@gmail.com>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- *
- */
-class TwitterauthorizationAction extends Action
-{
- var $twuid = null;
- var $tw_fields = null;
- var $access_token = null;
- var $signin = null;
- var $verifier = null;
-
- /**
- * Initialize class members. Looks for 'oauth_token' parameter.
- *
- * @param array $args misc. arguments
- *
- * @return boolean true
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $this->signin = $this->boolean('signin');
- $this->oauth_token = $this->arg('oauth_token');
- $this->verifier = $this->arg('oauth_verifier');
-
- return true;
- }
-
- /**
- * Handler method
- *
- * @param array $args is ignored since it's now passed in in prepare()
- *
- * @return nothing
- */
- function handle($args)
- {
- parent::handle($args);
-
- if (common_logged_in()) {
- $user = common_current_user();
- $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
-
- // If there's already a foreign link record and a foreign user
- // it means the accounts are already linked, and this is unecessary.
- // So go back.
-
- if (isset($flink)) {
- $fuser = $flink->getForeignUser();
- if (!empty($fuser)) {
- common_redirect(common_local_url('twittersettings'));
- }
- }
- }
-
- if ($_SERVER['REQUEST_METHOD'] == 'POST') {
-
- // User was not logged in to StatusNet before
-
- $this->twuid = $this->trimmed('twuid');
-
- $this->tw_fields = array('screen_name' => $this->trimmed('tw_fields_screen_name'),
- 'fullname' => $this->trimmed('tw_fields_fullname'));
-
- $this->access_token = new OAuthToken($this->trimmed('access_token_key'), $this->trimmed('access_token_secret'));
-
- $token = $this->trimmed('token');
-
- if (!$token || $token != common_session_token()) {
- // TRANS: Client error displayed when the session token does not match or is not given.
- $this->showForm(_m('There was a problem with your session token. Try again, please.'));
- return;
- }
-
- if ($this->arg('create')) {
- if (!$this->boolean('license')) {
- // TRANS: Form validation error displayed when the checkbox to agree to the license has not been checked.
- $this->showForm(_m('You cannot register if you do not agree to the license.'),
- $this->trimmed('newname'));
- return;
- }
- $this->createNewUser();
- } else if ($this->arg('connect')) {
- $this->connectNewUser();
- } else {
- common_debug('Twitter bridge - ' . print_r($this->args, true));
- // TRANS: Form validation error displayed when an unhandled error occurs.
- $this->showForm(_m('Something weird happened.'),
- $this->trimmed('newname'));
- }
- } else {
- // $this->oauth_token is only populated once Twitter authorizes our
- // request token. If it's empty we're at the beginning of the auth
- // process
-
- if (empty($this->oauth_token)) {
- $this->authorizeRequestToken();
- } else {
- $this->saveAccessToken();
- }
- }
- }
-
- /**
- * Asks Twitter for a request token, and then redirects to Twitter
- * to authorize it.
- *
- * @return nothing
- */
- function authorizeRequestToken()
- {
- try {
- // Get a new request token and authorize it
-
- $client = new TwitterOAuthClient();
- $req_tok = $client->getRequestToken();
-
- // Sock the request token away in the session temporarily
-
- $_SESSION['twitter_request_token'] = $req_tok->key;
- $_SESSION['twitter_request_token_secret'] = $req_tok->secret;
-
- $auth_link = $client->getAuthorizeLink($req_tok, $this->signin);
- } catch (OAuthClientException $e) {
- $msg = sprintf(
- 'OAuth client error - code: %1s, msg: %2s',
- $e->getCode(),
- $e->getMessage()
- );
- common_log(LOG_INFO, 'Twitter bridge - ' . $msg);
- $this->serverError(
- // TRANS: Server error displayed when linking to a Twitter account fails.
- _m('Could not link your Twitter account.')
- );
- }
-
- common_redirect($auth_link);
- }
-
- /**
- * Called when Twitter returns an authorized request token. Exchanges
- * it for an access token and stores it.
- *
- * @return nothing
- */
- function saveAccessToken()
- {
- // Check to make sure Twitter returned the same request
- // token we sent them
-
- if ($_SESSION['twitter_request_token'] != $this->oauth_token) {
- $this->serverError(
- // TRANS: Server error displayed when linking to a Twitter account fails because of an incorrect oauth_token.
- _m('Could not link your Twitter account: oauth_token mismatch.')
- );
- }
-
- $twitter_user = null;
-
- try {
-
- $client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
- $_SESSION['twitter_request_token_secret']);
-
- // Exchange the request token for an access token
-
- $atok = $client->getAccessToken($this->verifier);
-
- // Test the access token and get the user's Twitter info
-
- $client = new TwitterOAuthClient($atok->key, $atok->secret);
- $twitter_user = $client->verifyCredentials();
-
- } catch (OAuthClientException $e) {
- $msg = sprintf(
- 'OAuth client error - code: %1$s, msg: %2$s',
- $e->getCode(),
- $e->getMessage()
- );
- common_log(LOG_INFO, 'Twitter bridge - ' . $msg);
- $this->serverError(
- // TRANS: Server error displayed when linking to a Twitter account fails.
- _m('Could not link your Twitter account.')
- );
- }
-
- if (common_logged_in()) {
- // Save the access token and Twitter user info
-
- $user = common_current_user();
- $this->saveForeignLink($user->id, $twitter_user->id, $atok);
- save_twitter_user($twitter_user->id, $twitter_user->screen_name);
-
- } else {
-
- $this->twuid = $twitter_user->id;
- $this->tw_fields = array("screen_name" => $twitter_user->screen_name,
- "fullname" => $twitter_user->name);
- $this->access_token = $atok;
- $this->tryLogin();
- }
-
- // Clean up the the mess we made in the session
-
- unset($_SESSION['twitter_request_token']);
- unset($_SESSION['twitter_request_token_secret']);
-
- if (common_logged_in()) {
- common_redirect(common_local_url('twittersettings'));
- }
- }
-
- /**
- * Saves a Foreign_link between Twitter user and local user,
- * which includes the access token and secret.
- *
- * @param int $user_id StatusNet user ID
- * @param int $twuid Twitter user ID
- * @param OAuthToken $token the access token to save
- *
- * @return nothing
- */
- function saveForeignLink($user_id, $twuid, $access_token)
- {
- $flink = new Foreign_link();
-
- $flink->user_id = $user_id;
- $flink->service = TWITTER_SERVICE;
-
- // delete stale flink, if any
- $result = $flink->find(true);
-
- if (!empty($result)) {
- $flink->safeDelete();
- }
-
- $flink->user_id = $user_id;
- $flink->foreign_id = $twuid;
- $flink->service = TWITTER_SERVICE;
-
- $creds = TwitterOAuthClient::packToken($access_token);
-
- $flink->credentials = $creds;
- $flink->created = common_sql_now();
-
- // Defaults: noticesync on, everything else off
-
- $flink->set_flags(true, false, false, false);
-
- $flink_id = $flink->insert();
-
- if (empty($flink_id)) {
- common_log_db_error($flink, 'INSERT', __FILE__);
- // TRANS: Server error displayed when linking to a Twitter account fails.
- $this->serverError(_m('Could not link your Twitter account.'));
- }
-
- return $flink_id;
- }
-
- function showPageNotice()
- {
- if ($this->error) {
- $this->element('div', array('class' => 'error'), $this->error);
- } else {
- $this->element('div', 'instructions',
- // TRANS: Page instruction. %s is the StatusNet sitename.
- sprintf(_m('This is the first time you have logged into %s so we must connect your Twitter account to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
- }
- }
-
- function title()
- {
- // TRANS: Page title.
- return _m('Twitter Account Setup');
- }
-
- function showForm($error=null, $username=null)
- {
- $this->error = $error;
- $this->username = $username;
-
- $this->showPage();
- }
-
- function showPage()
- {
- parent::showPage();
- }
-
- /**
- * @fixme much of this duplicates core code, which is very fragile.
- * Should probably be replaced with an extensible mini version of
- * the core registration form.
- */
- function showContent()
- {
- if (!empty($this->message_text)) {
- $this->element('p', null, $this->message);
- return;
- }
-
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'form_settings_twitter_connect',
- 'class' => 'form_settings',
- 'action' => common_local_url('twitterauthorization')));
- $this->elementStart('fieldset', array('id' => 'settings_twitter_connect_options'));
- // TRANS: Fieldset legend.
- $this->element('legend', null, _m('Connection options'));
-
- $this->hidden('access_token_key', $this->access_token->key);
- $this->hidden('access_token_secret', $this->access_token->secret);
- $this->hidden('twuid', $this->twuid);
- $this->hidden('tw_fields_screen_name', $this->tw_fields['screen_name']);
- $this->hidden('tw_fields_name', $this->tw_fields['fullname']);
- $this->hidden('token', common_session_token());
-
- // Don't allow new account creation if site is flagged as invite only
- if (common_config('site', 'inviteonly') == false) {
- $this->elementStart('fieldset');
- $this->element('legend', null,
- // TRANS: Fieldset legend.
- _m('Create new account'));
- $this->element('p', null,
- // TRANS: Sub form introduction text.
- _m('Create a new user with this nickname.'));
- $this->elementStart('ul', 'form_data');
-
- // Hook point for captcha etc
- Event::handle('StartRegistrationFormData', array($this));
-
- $this->elementStart('li');
- // TRANS: Field label.
- $this->input('newname', _m('New nickname'),
- ($this->username) ? $this->username : '',
- // TRANS: Field title for nickname field.
- _m('1-64 lowercase letters or numbers, no punctuation or spaces.'));
- $this->elementEnd('li');
- $this->elementStart('li');
- // TRANS: Field label.
- $this->input('email', _m('LABEL','Email'), $this->getEmail(),
- // TRANS: Field title for e-mail address field.
- _m('Used only for updates, announcements, '.
- 'and password recovery'));
- $this->elementEnd('li');
-
- // Hook point for captcha etc
- Event::handle('EndRegistrationFormData', array($this));
-
- $this->elementEnd('ul');
- // TRANS: Button text for creating a new StatusNet account in the Twitter connect page.
- $this->submit('create', _m('BUTTON','Create'));
- $this->elementEnd('fieldset');
- }
-
- $this->elementStart('fieldset');
- $this->element('legend', null,
- // TRANS: Fieldset legend.
- _m('Connect existing account'));
- $this->element('p', null,
- // TRANS: Sub form introduction text.
- _m('If you already have an account, login with your username and password to connect it to your Twitter account.'));
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li');
- // TRANS: Field label.
- $this->input('nickname', _m('Existing nickname'));
- $this->elementEnd('li');
- $this->elementStart('li');
- // TRANS: Field label.
- $this->password('password', _m('Password'));
- $this->elementEnd('li');
- $this->elementEnd('ul');
- $this->elementEnd('fieldset');
-
- $this->elementStart('fieldset');
- $this->element('legend', null,
- // TRANS: Fieldset legend.
- _m('License'));
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li');
- $this->element('input', array('type' => 'checkbox',
- 'id' => 'license',
- 'class' => 'checkbox',
- 'name' => 'license',
- 'value' => 'true'));
- $this->elementStart('label', array('class' => 'checkbox', 'for' => 'license'));
- // TRANS: Text for license agreement checkbox.
- // TRANS: %s is the license as configured for the StatusNet site.
- $message = _m('My text and files are available under %s ' .
- 'except this private data: password, ' .
- 'email address, IM address, and phone number.');
- $link = '<a href="' .
- htmlspecialchars(common_config('license', 'url')) .
- '">' .
- htmlspecialchars(common_config('license', 'title')) .
- '</a>';
- $this->raw(sprintf(htmlspecialchars($message), $link));
- $this->elementEnd('label');
- $this->elementEnd('li');
- $this->elementEnd('ul');
- $this->elementEnd('fieldset');
- // TRANS: Button text for connecting an existing StatusNet account in the Twitter connect page..
- $this->submit('connect', _m('BUTTON','Connect'));
- $this->elementEnd('fieldset');
- $this->elementEnd('form');
- }
-
- /**
- * Get specified e-mail from the form, or the invite code.
- *
- * @return string
- */
- function getEmail()
- {
- $email = $this->trimmed('email');
- if (!empty($email)) {
- return $email;
- }
-
- // Terrible hack for invites...
- if (common_config('site', 'inviteonly')) {
- $code = $_SESSION['invitecode'];
- if ($code) {
- $invite = Invitation::getKV($code);
-
- if ($invite && $invite->address_type == 'email') {
- return $invite->address;
- }
- }
- }
- return '';
- }
-
- function message($msg)
- {
- $this->message_text = $msg;
- $this->showPage();
- }
-
- function createNewUser()
- {
- if (!Event::handle('StartRegistrationTry', array($this))) {
- return;
- }
-
- if (common_config('site', 'closed')) {
- // TRANS: Client error displayed when trying to create a new user while creating new users is not allowed.
- $this->clientError(_m('Registration not allowed.'));
- return;
- }
-
- $invite = null;
-
- if (common_config('site', 'inviteonly')) {
- $code = $_SESSION['invitecode'];
- if (empty($code)) {
- // TRANS: Client error displayed when trying to create a new user while creating new users is not allowed.
- $this->clientError(_m('Registration not allowed.'));
- return;
- }
-
- $invite = Invitation::getKV($code);
-
- if (empty($invite)) {
- // TRANS: Client error displayed when trying to create a new user with an invalid invitation code.
- $this->clientError(_m('Not a valid invitation code.'));
- return;
- }
- }
-
- try {
- $nickname = Nickname::normalize($this->trimmed('newname'));
- } catch (NicknameException $e) {
- $this->showForm($e->getMessage());
- return;
- }
-
- if (!User::allowed_nickname($nickname)) {
- // TRANS: Client error displayed when trying to create a new user with an invalid username.
- $this->showForm(_m('Nickname not allowed.'));
- return;
- }
-
- if (User::getKV('nickname', $nickname)) {
- // TRANS: Client error displayed when trying to create a new user with a username that is already in use.
- $this->showForm(_m('Nickname already in use. Try another one.'));
- return;
- }
-
- $fullname = trim($this->tw_fields['fullname']);
-
- $args = array('nickname' => $nickname, 'fullname' => $fullname);
-
- if (!empty($invite)) {
- $args['code'] = $invite->code;
- }
-
- $email = $this->getEmail();
- if (!empty($email)) {
- $args['email'] = $email;
- }
-
- $user = User::register($args);
-
- if (empty($user)) {
- // TRANS: Server error displayed when creating a new user has failed.
- $this->serverError(_m('Error registering user.'));
- return;
- }
-
- $result = $this->saveForeignLink($user->id,
- $this->twuid,
- $this->access_token);
-
- save_twitter_user($this->twuid, $this->tw_fields['screen_name']);
-
- if (!$result) {
- // TRANS: Server error displayed when connecting a user to a Twitter user has failed.
- $this->serverError(_m('Error connecting user to Twitter.'));
- return;
- }
-
- common_set_user($user);
- common_real_login(true);
-
- common_debug('TwitterBridge Plugin - ' .
- "Registered new user $user->id from Twitter user $this->twuid");
-
- Event::handle('EndRegistrationTry', array($this));
-
- common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
- 303);
- }
-
- function connectNewUser()
- {
- $nickname = $this->trimmed('nickname');
- $password = $this->trimmed('password');
-
- if (!common_check_user($nickname, $password)) {
- // TRANS: Form validation error displayed when connecting an existing user to a Twitter user fails because
- // TRANS: the provided username and/or password are incorrect.
- $this->showForm(_m('Invalid username or password.'));
- return;
- }
-
- $user = User::getKV('nickname', $nickname);
-
- if (!empty($user)) {
- common_debug('TwitterBridge Plugin - ' .
- "Legit user to connect to Twitter: $nickname");
- }
-
- $result = $this->saveForeignLink($user->id,
- $this->twuid,
- $this->access_token);
-
- save_twitter_user($this->twuid, $this->tw_fields['screen_name']);
-
- if (!$result) {
- // TRANS: Server error displayed connecting a user to a Twitter user has failed.
- $this->serverError(_m('Error connecting user to Twitter.'));
- return;
- }
-
- common_debug('TwitterBridge Plugin - ' .
- "Connected Twitter user $this->twuid to local user $user->id");
-
- common_set_user($user);
- common_real_login(true);
-
- $this->goHome($user->nickname);
- }
-
- function connectUser()
- {
- $user = common_current_user();
-
- $result = $this->flinkUser($user->id, $this->twuid);
-
- if (empty($result)) {
- // TRANS: Server error displayed connecting a user to a Twitter user has failed.
- $this->serverError(_m('Error connecting user to Twitter.'));
- return;
- }
-
- common_debug('TwitterBridge Plugin - ' .
- "Connected Twitter user $this->twuid to local user $user->id");
-
- // Return to Twitter connection settings tab
- common_redirect(common_local_url('twittersettings'), 303);
- }
-
- function tryLogin()
- {
- common_debug('TwitterBridge Plugin - ' .
- "Trying login for Twitter user $this->twuid.");
-
- $flink = Foreign_link::getByForeignID($this->twuid,
- TWITTER_SERVICE);
-
- if (!empty($flink)) {
- $user = $flink->getUser();
-
- if (!empty($user)) {
-
- common_debug('TwitterBridge Plugin - ' .
- "Logged in Twitter user $flink->foreign_id as user $user->id ($user->nickname)");
-
- common_set_user($user);
- common_real_login(true);
- $this->goHome($user->nickname);
- }
-
- } else {
-
- common_debug('TwitterBridge Plugin - ' .
- "No flink found for twuid: $this->twuid - new user");
-
- $this->showForm(null, $this->bestNewNickname());
- }
- }
-
- function goHome($nickname)
- {
- $url = common_get_returnto();
- if ($url) {
- // We don't have to return to it again
- common_set_returnto(null);
- } else {
- $url = common_local_url('all',
- array('nickname' =>
- $nickname));
- }
-
- common_redirect($url, 303);
- }
-
- function bestNewNickname()
- {
- if (!empty($this->tw_fields['fullname'])) {
- $nickname = $this->nicknamize($this->tw_fields['fullname']);
- if ($this->isNewNickname($nickname)) {
- return $nickname;
- }
- }
-
- return null;
- }
-
- // Given a string, try to make it work as a nickname
-
- function nicknamize($str)
- {
- $str = preg_replace('/\W/', '', $str);
- $str = str_replace(array('-', '_'), '', $str);
- return strtolower($str);
- }
-
- function isNewNickname($str)
- {
- if (!Nickname::isValid($str)) {
- return false;
- }
- if (!User::allowed_nickname($str)) {
- return false;
- }
- if (User::getKV('nickname', $str)) {
- return false;
- }
- return true;
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * 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
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @author Julien C <chaumond@gmail.com>
- * @author Brion Vibber <brion@status.net>
- * @copyright 2009-2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
-
-/**
- * Encapsulation of the Twitter status -> notice incoming bridge import.
- * Is used by both the polling twitterstatusfetcher.php daemon, and the
- * in-progress streaming import.
- *
- * @category Plugin
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @author Julien C <chaumond@gmail.com>
- * @author Brion Vibber <brion@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- * @link http://twitter.com/
- */
-class TwitterImport
-{
- public function importStatus($status)
- {
- // Hacktastic: filter out stuff coming from this StatusNet
- $source = mb_strtolower(common_config('integration', 'source'));
-
- if (preg_match("/$source/", mb_strtolower($status->source))) {
- common_debug($this->name() . ' - Skipping import of status ' .
- twitter_id($status) . ' with source ' . $source);
- return null;
- }
-
- // Don't save it if the user is protected
- // FIXME: save it but treat it as private
- if ($status->user->protected) {
- return null;
- }
-
- $notice = $this->saveStatus($status);
-
- return $notice;
- }
-
- function name()
- {
- return get_class($this);
- }
-
- function saveStatus($status)
- {
- $profile = $this->ensureProfile($status->user);
-
- if (empty($profile)) {
- common_log(LOG_ERR, $this->name() .
- ' - Problem saving notice. No associated Profile.');
- return null;
- }
-
- $statusId = twitter_id($status);
- $statusUri = $this->makeStatusURI($status->user->screen_name, $statusId);
-
- // check to see if we've already imported the status
- $n2s = Notice_to_status::getKV('status_id', $statusId);
-
- if (!empty($n2s)) {
- common_log(
- LOG_INFO,
- $this->name() .
- " - Ignoring duplicate import: {$statusId}"
- );
- return Notice::getKV('id', $n2s->notice_id);
- }
-
- // If it's a retweet, save it as a repeat!
- if (!empty($status->retweeted_status)) {
- common_log(LOG_INFO, "Status {$statusId} is a retweet of " . twitter_id($status->retweeted_status) . ".");
- $original = $this->saveStatus($status->retweeted_status);
- if (empty($original)) {
- return null;
- } else {
- $author = $original->getProfile();
- // TRANS: Message used to repeat a notice. RT is the abbreviation of 'retweet'.
- // TRANS: %1$s is the repeated user's name, %2$s is the repeated notice.
- $content = sprintf(_m('RT @%1$s %2$s'),
- $author->nickname,
- $original->content);
-
- if (Notice::contentTooLong($content)) {
- $contentlimit = Notice::maxContent();
- $content = mb_substr($content, 0, $contentlimit - 4) . ' ...';
- }
-
- $repeat = Notice::saveNew($profile->id,
- $content,
- 'twitter',
- array('repeat_of' => $original->id,
- 'uri' => $statusUri,
- 'is_local' => Notice::GATEWAY));
- common_log(LOG_INFO, "Saved {$repeat->id} as a repeat of {$original->id}");
- Notice_to_status::saveNew($repeat->id, $statusId);
- return $repeat;
- }
- }
-
- $notice = new Notice();
-
- $notice->profile_id = $profile->id;
- $notice->uri = $statusUri;
- $notice->url = $statusUri;
- $notice->created = strftime(
- '%Y-%m-%d %H:%M:%S',
- strtotime($status->created_at)
- );
-
- $notice->source = 'twitter';
-
- $notice->reply_to = null;
-
- $replyTo = twitter_id($status, 'in_reply_to_status_id');
- if (!empty($replyTo)) {
- common_log(LOG_INFO, "Status {$statusId} is a reply to status {$replyTo}");
- $n2s = Notice_to_status::getKV('status_id', $replyTo);
- if (empty($n2s)) {
- common_log(LOG_INFO, "Couldn't find local notice for status {$replyTo}");
- } else {
- $reply = Notice::getKV('id', $n2s->notice_id);
- if (empty($reply)) {
- common_log(LOG_INFO, "Couldn't find local notice for status {$replyTo}");
- } else {
- common_log(LOG_INFO, "Found local notice {$reply->id} for status {$replyTo}");
- $notice->reply_to = $reply->id;
- $notice->conversation = $reply->conversation;
- }
- }
- }
-
- if (empty($notice->conversation)) {
- $conv = Conversation::create();
- $notice->conversation = $conv->id;
- common_log(LOG_INFO, "No known conversation for status {$statusId} so making a new one {$conv->id}.");
- }
-
- $notice->is_local = Notice::GATEWAY;
-
- $notice->content = html_entity_decode($this->linkify($status, FALSE), ENT_QUOTES, 'UTF-8');
- $notice->rendered = $this->linkify($status, TRUE);
-
- if (Event::handle('StartNoticeSave', array(&$notice))) {
-
- $id = $notice->insert();
-
- if (!$id) {
- common_log_db_error($notice, 'INSERT', __FILE__);
- common_log(LOG_ERR, $this->name() .
- ' - Problem saving notice.');
- }
-
- Event::handle('EndNoticeSave', array($notice));
- }
-
- Notice_to_status::saveNew($notice->id, $statusId);
-
- $this->saveStatusMentions($notice, $status);
- $this->saveStatusAttachments($notice, $status);
-
- $notice->blowOnInsert();
-
- return $notice;
- }
-
- /**
- * Make an URI for a status.
- *
- * @param object $status status object
- *
- * @return string URI
- */
- function makeStatusURI($username, $id)
- {
- return 'http://twitter.com/#!/'
- . $username
- . '/status/'
- . $id;
- }
-
-
- /**
- * Look up a Profile by profileurl field. Profile::getKV() was
- * not working consistently.
- *
- * @param string $nickname local nickname of the Twitter user
- * @param string $profileurl the profile url
- *
- * @return mixed value the first Profile with that url, or null
- */
- function getProfileByUrl($nickname, $profileurl)
- {
- $profile = new Profile();
- $profile->nickname = $nickname;
- $profile->profileurl = $profileurl;
- $profile->limit(1);
-
- if ($profile->find()) {
- $profile->fetch();
- return $profile;
- }
-
- return null;
- }
-
- /**
- * Check to see if this Twitter status has already been imported
- *
- * @param Profile $profile Twitter user's local profile
- * @param string $statusUri URI of the status on Twitter
- *
- * @return mixed value a matching Notice or null
- */
- function checkDupe($profile, $statusUri)
- {
- $notice = new Notice();
- $notice->uri = $statusUri;
- $notice->profile_id = $profile->id;
- $notice->limit(1);
-
- if ($notice->find()) {
- $notice->fetch();
- return $notice;
- }
-
- return null;
- }
-
- function ensureProfile($user)
- {
- // check to see if there's already a profile for this user
- $profileurl = 'http://twitter.com/' . $user->screen_name;
- $profile = $this->getProfileByUrl($user->screen_name, $profileurl);
-
- if (!empty($profile)) {
- common_debug($this->name() .
- " - Profile for $profile->nickname found.");
-
- // Check to see if the user's Avatar has changed
-
- $this->checkAvatar($user, $profile);
- return $profile;
-
- } else {
- common_debug($this->name() . ' - Adding profile and remote profile ' .
- "for Twitter user: $profileurl.");
-
- $profile = new Profile();
- $profile->query("BEGIN");
-
- $profile->nickname = $user->screen_name;
- $profile->fullname = $user->name;
- $profile->homepage = $user->url;
- $profile->bio = $user->description;
- $profile->location = $user->location;
- $profile->profileurl = $profileurl;
- $profile->created = common_sql_now();
-
- try {
- $id = $profile->insert();
- } catch(Exception $e) {
- common_log(LOG_WARNING, $this->name() . ' Couldn\'t insert profile - ' . $e->getMessage());
- }
-
- if (empty($id)) {
- common_log_db_error($profile, 'INSERT', __FILE__);
- $profile->query("ROLLBACK");
- return false;
- }
-
- // check for remote profile
-
- $remote_pro = Remote_profile::getKV('uri', $profileurl);
-
- if (empty($remote_pro)) {
- $remote_pro = new Remote_profile();
-
- $remote_pro->id = $id;
- $remote_pro->uri = $profileurl;
- $remote_pro->created = common_sql_now();
-
- try {
- $rid = $remote_pro->insert();
- } catch (Exception $e) {
- common_log(LOG_WARNING, $this->name() . ' Couldn\'t save remote profile - ' . $e->getMessage());
- }
-
- if (empty($rid)) {
- common_log_db_error($profile, 'INSERT', __FILE__);
- $profile->query("ROLLBACK");
- return false;
- }
- }
-
- $profile->query("COMMIT");
-
- $this->saveAvatars($user, $id);
-
- return $profile;
- }
- }
-
- function checkAvatar($twitter_user, $profile)
- {
- global $config;
-
- $newname = 'Twitter_' . $twitter_user->id . '_' . basename($twitter_user->profile_image_url);
-
- $oldname = $profile->getAvatar(48)->filename;
-
- if ($newname != $oldname) {
- common_debug($this->name() . ' - Avatar for Twitter user ' .
- "$profile->nickname has changed.");
- common_debug($this->name() . " - old: $oldname new: $newname");
-
- $this->updateAvatars($twitter_user, $profile);
- }
-
- if ($this->missingAvatarFile($profile)) {
- common_debug($this->name() . ' - Twitter user ' .
- $profile->nickname .
- ' is missing one or more local avatars.');
- common_debug($this->name() ." - old: $oldname new: $newname");
-
- $this->updateAvatars($twitter_user, $profile);
- }
- }
-
- function updateAvatars($twitter_user, $profile) {
-
- global $config;
-
- $path_parts = pathinfo($twitter_user->profile_image_url);
-
- $ext = (isset($path_parts['extension']) ? '.'.$path_parts['extension'] : ''); // some lack extension
- $img_root = basename($path_parts['basename'], '_normal'.$ext); // cut off extension
- $mediatype = $this->getMediatype(substr($ext, 1));
-
- foreach (array('mini', 'normal', 'bigger') as $size) {
- $url = $path_parts['dirname'] . '/' .
- $img_root . '_' . $size . $ext;
- $filename = 'Twitter_' . $twitter_user->id . '_' .
- $img_root . '_' . $size . $ext;
-
- $this->updateAvatar($profile->id, $size, $mediatype, $filename);
- $this->fetchAvatar($url, $filename);
- }
- }
-
- function missingAvatarFile($profile) {
- foreach (array(24, 48, 73) as $size) {
- $filename = $profile->getAvatar($size)->filename;
- $avatarpath = Avatar::path($filename);
- if (file_exists($avatarpath) == FALSE) {
- return true;
- }
- }
- return false;
- }
-
- function getMediatype($ext)
- {
- $mediatype = null;
-
- switch (strtolower($ext)) {
- case 'jpeg':
- case 'jpg':
- $mediatype = 'image/jpeg';
- break;
- case 'gif':
- $mediatype = 'image/gif';
- break;
- default:
- $mediatype = 'image/png';
- }
-
- return $mediatype;
- }
-
- function saveAvatars($user, $id)
- {
- global $config;
-
- $path_parts = pathinfo($user->profile_image_url);
- $ext = (isset($path_parts['extension']) ? '.'.$path_parts['extension'] : '');
- $img_root = basename($path_parts['basename'], '_normal'.$ext);
- $mediatype = $this->getMediatype(substr($ext, 1));
-
- foreach (array('mini', 'normal', 'bigger') as $size) {
- $url = $path_parts['dirname'] . '/' .
- $img_root . '_' . $size . $ext;
- $filename = 'Twitter_' . $user->id . '_' .
- $img_root . '_' . $size . $ext;
-
- if ($this->fetchAvatar($url, $filename)) {
- $this->newAvatar($id, $size, $mediatype, $filename);
- } else {
- common_log(LOG_WARNING, $id() .
- " - Problem fetching Avatar: $url");
- }
- }
- }
-
- function updateAvatar($profile_id, $size, $mediatype, $filename) {
-
- common_debug($this->name() . " - Updating avatar: $size");
-
- $profile = Profile::getKV($profile_id);
-
- if (empty($profile)) {
- common_debug($this->name() . " - Couldn't get profile: $profile_id!");
- return;
- }
-
- $sizes = array('mini' => 24, 'normal' => 48, 'bigger' => 73);
- $avatar = $profile->getAvatar($sizes[$size]);
-
- // Delete the avatar, if present
- if ($avatar) {
- $avatar->delete();
- }
-
- $this->newAvatar($profile->id, $size, $mediatype, $filename);
- }
-
- function newAvatar($profile_id, $size, $mediatype, $filename)
- {
- global $config;
-
- $avatar = new Avatar();
- $avatar->profile_id = $profile_id;
-
- switch($size) {
- case 'mini':
- $avatar->width = 24;
- $avatar->height = 24;
- break;
- case 'normal':
- $avatar->width = 48;
- $avatar->height = 48;
- break;
- default:
- // Note: Twitter's big avatars are a different size than
- // StatusNet's (StatusNet's = 96)
- $avatar->width = 73;
- $avatar->height = 73;
- }
-
- $avatar->original = 0; // we don't have the original
- $avatar->mediatype = $mediatype;
- $avatar->filename = $filename;
- $avatar->url = Avatar::url($filename);
-
- $avatar->created = common_sql_now();
-
- try {
- $id = $avatar->insert();
- } catch (Exception $e) {
- common_log(LOG_WARNING, $this->name() . ' Couldn\'t insert avatar - ' . $e->getMessage());
- }
-
- if (empty($id)) {
- common_log_db_error($avatar, 'INSERT', __FILE__);
- return null;
- }
-
- common_debug($this->name() .
- " - Saved new $size avatar for $profile_id.");
-
- return $id;
- }
-
- /**
- * Fetch a remote avatar image and save to local storage.
- *
- * @param string $url avatar source URL
- * @param string $filename bare local filename for download
- * @return bool true on success, false on failure
- */
- function fetchAvatar($url, $filename)
- {
- common_debug($this->name() . " - Fetching Twitter avatar: $url");
-
- $request = HTTPClient::start();
- $response = $request->get($url);
- if ($response->isOk()) {
- $avatarfile = Avatar::path($filename);
- $ok = file_put_contents($avatarfile, $response->getBody());
- if (!$ok) {
- common_log(LOG_WARNING, $this->name() .
- " - Couldn't open file $filename");
- return false;
- }
- } else {
- return false;
- }
-
- return true;
- }
-
- const URL = 1;
- const HASHTAG = 2;
- const MENTION = 3;
-
- function linkify($status, $html = FALSE)
- {
- $text = $status->text;
-
- if (empty($status->entities)) {
- $statusId = twitter_id($status);
- common_log(LOG_WARNING, "No entities data for {$statusId}; trying to fake up links ourselves.");
- $text = common_replace_urls_callback($text, 'common_linkify');
- $text = preg_replace('/(^|\"\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/e', "'\\1#'.TwitterStatusFetcher::tagLink('\\2')", $text);
- $text = preg_replace('/(^|\s+)@([a-z0-9A-Z_]{1,64})/e', "'\\1@'.TwitterStatusFetcher::atLink('\\2')", $text);
- return $text;
- }
-
- // Move all the entities into order so we can
- // replace them and escape surrounding plaintext
- // in order
-
- $toReplace = array();
-
- if (!empty($status->entities->urls)) {
- foreach ($status->entities->urls as $url) {
- $toReplace[$url->indices[0]] = array(self::URL, $url);
- }
- }
-
- if (!empty($status->entities->hashtags)) {
- foreach ($status->entities->hashtags as $hashtag) {
- $toReplace[$hashtag->indices[0]] = array(self::HASHTAG, $hashtag);
- }
- }
-
- if (!empty($status->entities->user_mentions)) {
- foreach ($status->entities->user_mentions as $mention) {
- $toReplace[$mention->indices[0]] = array(self::MENTION, $mention);
- }
- }
-
- // sort in forward order by key
-
- ksort($toReplace);
-
- $result = '';
- $cursor = 0;
-
- foreach ($toReplace as $part) {
- list($type, $object) = $part;
- $start = $object->indices[0];
- $end = $object->indices[1];
- if ($cursor < $start) {
- // Copy in the preceding plaintext
- $result .= $this->twitEscape(mb_substr($text, $cursor, $start - $cursor));
- $cursor = $start;
- }
- $orig = $this->twitEscape(mb_substr($text, $start, $end - $start));
- switch($type) {
- case self::URL:
- $linkText = $this->makeUrlLink($object, $orig, $html);
- break;
- case self::HASHTAG:
- if ($html) {
- $linkText = $this->makeHashtagLink($object, $orig);
- }else{
- $linkText = $orig;
- }
- break;
- case self::MENTION:
- if ($html) {
- $linkText = $this->makeMentionLink($object, $orig);
- }else{
- $linkText = $orig;
- }
- break;
- default:
- $linkText = $orig;
- continue;
- }
- $result .= $linkText;
- $cursor = $end;
- }
- $last = $this->twitEscape(mb_substr($text, $cursor));
- $result .= $last;
-
- return $result;
- }
-
- function twitEscape($str)
- {
- // Twitter seems to preemptive turn < and > into < and >
- // but doesn't for &, so while you may have some magic protection
- // against XSS by not bothing to escape manually, you still get
- // invalid XHTML. Thanks!
- //
- // Looks like their web interface pretty much sends anything
- // through intact, so.... to do equivalent, decode all entities
- // and then re-encode the special ones.
- return htmlspecialchars(html_entity_decode($str, ENT_COMPAT, 'UTF-8'));
- }
-
- function makeUrlLink($object, $orig, $html)
- {
- if ($html) {
- return '<a href="'.htmlspecialchars($object->expanded_url).'" class="extlink">'.htmlspecialchars($object->display_url).'</a>';
- }else{
- return htmlspecialchars($object->expanded_url);
- }
- }
-
- function makeHashtagLink($object, $orig)
- {
- return "#" . self::tagLink($object->text, substr($orig, 1));
- }
-
- function makeMentionLink($object, $orig)
- {
- return "@".self::atLink($object->screen_name, $object->name, substr($orig, 1));
- }
-
- static function tagLink($tag, $orig)
- {
- return "<a href='https://search.twitter.com/search?q=%23{$tag}' class='hashtag'>{$orig}</a>";
- }
-
- static function atLink($screenName, $fullName, $orig)
- {
- if (!empty($fullName)) {
- return "<a href='http://twitter.com/#!/{$screenName}' title='{$fullName}'>{$orig}</a>";
- } else {
- return "<a href='http://twitter.com/#!/{$screenName}'>{$orig}</a>";
- }
- }
-
- function saveStatusMentions($notice, $status)
- {
- $mentions = array();
-
- if (empty($status->entities) || empty($status->entities->user_mentions)) {
- return;
- }
-
- foreach ($status->entities->user_mentions as $mention) {
- $flink = Foreign_link::getByForeignID($mention->id, TWITTER_SERVICE);
- if (!empty($flink)) {
- $user = User::getKV('id', $flink->user_id);
- if (!empty($user)) {
- $reply = new Reply();
- $reply->notice_id = $notice->id;
- $reply->profile_id = $user->id;
- $reply->modified = $notice->created;
- common_log(LOG_INFO, __METHOD__ . ": saving reply: notice {$notice->id} to profile {$user->id}");
- $id = $reply->insert();
- }
- }
- }
- }
-
- /**
- * Record URL links from the notice. Needed to get thumbnail records
- * for referenced photo and video posts, etc.
- *
- * @param Notice $notice
- * @param object $status
- */
- function saveStatusAttachments($notice, $status)
- {
- if (common_config('attachments', 'process_links')) {
- if (!empty($status->entities) && !empty($status->entities->urls)) {
- foreach ($status->entities->urls as $url) {
- File::processNew($url->url, $notice->id);
- }
- }
- }
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * 'Sign in with Twitter' login page
- *
- * 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 Login
- * @package StatusNet
- * @author Julien Chaumond <chaumond@gmail.com>
- * @author Zach Copley <zach@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
-
-/**
- * Page for logging in with Twitter
- *
- * @category Login
- * @package StatusNet
- * @author Julien Chaumond <chaumond@gmail.com>
- * @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
- * @link http://status.net/
- *
- * @see SettingsAction
- */
-class TwitterloginAction extends Action
-{
- function handle($args)
- {
- parent::handle($args);
-
- if (common_is_real_login()) {
- // TRANS: Client error displayed when trying to log in using Twitter while already logged in to StatusNet.
- $this->clientError(_m('Already logged in.'));
- }
-
- $this->showPage();
- }
-
- function title()
- {
- // TRANS: Title for login using Twitter page.
- return _m('TITLE','Twitter Login');
- }
-
- function getInstructions()
- {
- // TRANS: Instructions for login using Twitter page.
- return _m('Login with your Twitter account');
- }
-
- function showPageNotice()
- {
- $instr = $this->getInstructions();
- $output = common_markup_to_html($instr);
- $this->elementStart('div', 'instructions');
- $this->raw($output);
- $this->elementEnd('div');
- }
-
- function showContent()
- {
- $this->elementStart('a', array('href' => common_local_url('twitterauthorization',
- null,
- array('signin' => true))));
- $this->element('img', array('src' => Plugin::staticPath('TwitterBridge', 'Sign-in-with-Twitter-lighter.png'),
- // TRANS: Alternative text for "sign in with Twitter" image.
- 'alt' => _m('Sign in with Twitter')));
- $this->elementEnd('a');
- }
-
- function showLocalNav()
- {
- $nav = new LoginGroupNav($this);
- $nav->show();
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Class for doing OAuth calls against Twitter
- *
- * 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 Integration
- * @package StatusNet
- * @author Zach Copley <zach@status.net>
- * @copyright 2009-2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-/**
- * Class for talking to the Twitter API with OAuth.
- *
- * @category Integration
- * @package StatusNet
- * @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
- * @link http://status.net/
- *
- */
-class TwitterOAuthClient extends OAuthClient
-{
- public static $requestTokenURL = 'https://api.twitter.com/oauth/request_token';
- public static $authorizeURL = 'https://api.twitter.com/oauth/authorize';
- public static $signinUrl = 'https://api.twitter.com/oauth/authenticate';
- public static $accessTokenURL = 'https://api.twitter.com/oauth/access_token';
-
- /**
- * Constructor
- *
- * @param string $oauth_token the user's token
- * @param string $oauth_token_secret the user's token secret
- *
- * @return nothing
- */
- function __construct($oauth_token = null, $oauth_token_secret = null)
- {
- $consumer_key = common_config('twitter', 'consumer_key');
- $consumer_secret = common_config('twitter', 'consumer_secret');
-
- if (empty($consumer_key) && empty($consumer_secret)) {
- $consumer_key = common_config(
- 'twitter',
- 'global_consumer_key'
- );
- $consumer_secret = common_config(
- 'twitter',
- 'global_consumer_secret'
- );
- }
-
- parent::__construct(
- $consumer_key,
- $consumer_secret,
- $oauth_token,
- $oauth_token_secret
- );
- }
-
- // XXX: the following two functions are to support the horrible hack
- // of using the credentils field in Foreign_link to store both
- // the access token and token secret. This hack should go away with
- // 0.9, in which we can make DB changes and add a new column for the
- // token itself.
-
- static function packToken($token)
- {
- return implode(chr(0), array($token->key, $token->secret));
- }
-
- static function unpackToken($str)
- {
- $vals = explode(chr(0), $str);
- return new OAuthToken($vals[0], $vals[1]);
- }
-
- static function isPackedToken($str)
- {
- if (strpos($str, chr(0)) === false) {
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * Gets a request token from Twitter
- *
- * @return OAuthToken $token the request token
- */
- function getRequestToken()
- {
- return parent::getRequestToken(
- self::$requestTokenURL,
- common_local_url('twitterauthorization')
- );
- }
-
- /**
- * Builds a link to Twitter's endpoint for authorizing a request token
- *
- * @param OAuthToken $request_token token to authorize
- *
- * @return the link
- */
- function getAuthorizeLink($request_token, $signin = false)
- {
- $url = ($signin) ? self::$signinUrl : self::$authorizeURL;
-
- return parent::getAuthorizeLink($url,
- $request_token,
- common_local_url('twitterauthorization'));
- }
-
- /**
- * Fetches an access token from Twitter
- *
- * @param string $verifier 1.0a verifier
- *
- * @return OAuthToken $token the access token
- */
- function getAccessToken($verifier = null)
- {
- return parent::getAccessToken(
- self::$accessTokenURL,
- $verifier
- );
- }
-
- /**
- * Calls Twitter's /account/verify_credentials API method
- *
- * @return mixed the Twitter user
- */
- function verifyCredentials()
- {
- $url = 'https://api.twitter.com/1.1/account/verify_credentials.json';
- $response = $this->oAuthGet($url);
- $twitter_user = json_decode($response);
- return $twitter_user;
- }
-
- /**
- * Calls Twitter's /statuses/update API method
- *
- * @param string $status text of the status
- * @param mixed $params optional other parameters to pass to Twitter,
- * as defined. For back-compatibility, if an int
- * is passed we'll consider it a reply-to ID.
- *
- * @return mixed the status
- */
- function statusesUpdate($status, $params=array())
- {
- $url = 'https://api.twitter.com/1.1/statuses/update.json';
- if (is_numeric($params)) {
- $params = array('in_reply_to_status_id' => intval($params));
- }
- $params['status'] = $status;
- // We don't have to pass 'source' as the oauth key is tied to an app.
-
- $response = $this->oAuthPost($url, $params);
- $status = json_decode($response);
- return $status;
- }
-
- /**
- * Calls Twitter's /statuses/home_timeline API method
- *
- * @param int $since_id show statuses after this id
- * @param string $timelineUri timeline to poll statuses from
- * @param int $max_id show statuses before this id
- * @param int $cnt number of statuses to show
- * @param int $page page number
- *
- * @return mixed an array of statuses
- */
- function statusesTimeline($since_id = null, $timelineUri = 'home_timeline',
- $max_id = null, $cnt = 200, $page = null)
- {
- $url = 'https://api.twitter.com/1.1/statuses/'.$timelineUri.'.json';
-
- $params = array('include_entities' => 'true',
- 'include_rts' => 'true');
-
- if (!empty($since_id)) {
- $params['since_id'] = $since_id;
- }
- if (!empty($max_id)) {
- $params['max_id'] = $max_id;
- }
- if (!empty($cnt)) {
- $params['count'] = $cnt;
- }
- if (!empty($page)) {
- $params['page'] = $page;
- }
-
- $response = $this->oAuthGet($url, $params);
- $statuses = json_decode($response);
- return $statuses;
- }
-
- /**
- * Calls Twitter's /statuses/friends API method
- *
- * @param int $id id of the user whom you wish to see friends of
- * @param int $user_id numerical user id
- * @param int $screen_name screen name
- * @param int $page page number
- *
- * @return mixed an array of twitter users and their latest status
- */
- function statusesFriends($id = null, $user_id = null, $screen_name = null,
- $page = null)
- {
- $url = "https://api.twitter.com/1.1/friends/list.json";
-
- $params = array();
-
- if (!empty($id)) {
- $params['id'] = $id;
- }
-
- if (!empty($user_id)) {
- $params['user_id'] = $user_id;
- }
-
- if (!empty($screen_name)) {
- $params['screen_name'] = $screen_name;
- }
-
- if (!empty($page)) {
- $params['page'] = $page;
- }
-
- $response = $this->oAuthGet($url, $params);
- $friends = json_decode($response);
- return $friends;
- }
-
- /**
- * Calls Twitter's /statuses/friends/ids API method
- *
- * @param int $id id of the user whom you wish to see friends of
- * @param int $user_id numerical user id
- * @param int $screen_name screen name
- * @param int $page page number
- *
- * @return mixed a list of ids, 100 per page
- */
- function friendsIds($id = null, $user_id = null, $screen_name = null,
- $page = null)
- {
- $url = "https://api.twitter.com/1.1/friends/ids.json";
-
- $params = array();
-
- if (!empty($id)) {
- $params['id'] = $id;
- }
-
- if (!empty($user_id)) {
- $params['user_id'] = $user_id;
- }
-
- if (!empty($screen_name)) {
- $params['screen_name'] = $screen_name;
- }
-
- if (!empty($page)) {
- $params['page'] = $page;
- }
-
- $response = $this->oAuthGet($url, $params);
- $ids = json_decode($response);
- return $ids;
- }
-
- /**
- * Calls Twitter's /statuses/retweet/id.json API method
- *
- * @param int $id id of the notice to retweet
- *
- * @return retweeted status
- */
-
- function statusesRetweet($id)
- {
- $url = "http://api.twitter.com/1.1/statuses/retweet/$id.json";
- $response = $this->oAuthPost($url);
- $status = json_decode($response);
- return $status;
- }
-
- /**
- * Calls Twitter's /favorites/create API method
- *
- * @param int $id ID of the status to favorite
- *
- * @return object faved status
- */
-
- function favoritesCreate($id)
- {
- $url = "http://api.twitter.com/1.1/favorites/create.json";
- $params=array();
- $params['id'] = $id;
- $response = $this->oAuthPost($url, $params);
- $status = json_decode($response);
- return $status;
- }
-
- /**
- * Calls Twitter's /favorites/destroy API method
- *
- * @param int $id ID of the status to unfavorite
- *
- * @return object unfaved status
- */
-
- function favoritesDestroy($id)
- {
- $url = "http://api.twitter.com/1.1/favorites/destroy.json";
- $params=array();
- $params['id'] = $id;
- $response = $this->oAuthPost($url,$params);
- $status = json_decode($response);
- return $status;
- }
-
- /**
- * Calls Twitter's /statuses/destroy API method
- *
- * @param int $id ID of the status to destroy
- *
- * @return object destroyed
- */
-
- function statusesDestroy($id)
- {
- $url = "http://api.twitter.com/1.1/statuses/destroy/$id.json";
- $response = $this->oAuthPost($url);
- $status = json_decode($response);
- return $status;
- }
-}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
-
-class TwitterQueueHandler extends QueueHandler
-{
- function transport()
- {
- return 'twitter';
- }
-
- function handle($notice)
- {
- $ok = broadcast_twitter($notice);
- return $ok || common_config('twitter', 'ignore_errors');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Settings for Twitter integration
- *
- * 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 Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2008-2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
-
-/**
- * Settings for Twitter integration
- *
- * @category Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- *
- * @see SettingsAction
- */
-class TwittersettingsAction extends ProfileSettingsAction
-{
- /**
- * Title of the page
- *
- * @return string Title of the page
- */
-
- function title()
- {
- // TRANS: Title for page with Twitter integration settings.
- return _m('Twitter settings');
- }
-
- /**
- * Instructions for use
- *
- * @return instructions for use
- */
-
- function getInstructions()
- {
- // TRANS: Instructions for page with Twitter integration settings.
- return _m('Connect your Twitter account to share your updates ' .
- 'with your Twitter friends and vice-versa.');
- }
-
- /**
- * Content area of the page
- *
- * Shows a form for associating a Twitter account with this
- * StatusNet account. Also lets the user set preferences.
- *
- * @return void
- */
- function showContent()
- {
-
- $user = common_current_user();
-
- $profile = $user->getProfile();
-
- $fuser = null;
-
- $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
-
- if (!empty($flink)) {
- $fuser = $flink->getForeignUser();
- }
-
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'form_settings_twitter',
- 'class' => 'form_settings',
- 'action' =>
- common_local_url('twittersettings')));
-
- $this->hidden('token', common_session_token());
-
- $this->elementStart('fieldset', array('id' => 'settings_twitter_account'));
-
- if (empty($fuser)) {
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li', array('id' => 'settings_twitter_login_button'));
- $this->element('a', array('href' => common_local_url('twitterauthorization')),
- // TRANS: Link description to connect to a Twitter account.
- 'Connect my Twitter account');
- $this->elementEnd('li');
- $this->elementEnd('ul');
-
- $this->elementEnd('fieldset');
- } else {
- // TRANS: Fieldset legend.
- $this->element('legend', null, _m('Twitter account'));
- $this->elementStart('p', array('id' => 'form_confirmed'));
- $this->element('a', array('href' => $fuser->uri), $fuser->nickname);
- $this->elementEnd('p');
- $this->element('p', 'form_note',
- // TRANS: Form note when a Twitter account has been connected.
- _m('Connected Twitter account'));
- $this->elementEnd('fieldset');
-
- $this->elementStart('fieldset');
-
- // TRANS: Fieldset legend.
- $this->element('legend', null, _m('Disconnect my account from Twitter'));
-
- if (!$user->password) {
- $this->elementStart('p', array('class' => 'form_guide'));
- // TRANS: Form guide. %s is a URL to the password settings.
- // TRANS: This message contains a Markdown link in the form [description](link).
- $message = sprintf(_m('Disconnecting your Twitter account ' .
- 'could make it impossible to log in! Please ' .
- '[set a password](%s) first.'),
- common_local_url('passwordsettings'));
- $message = common_markup_to_html($message);
- $this->text($message);
- $this->elementEnd('p');
- } else {
- // TRANS: Form instructions. %1$s is the StatusNet sitename.
- $note = _m('Keep your %1$s account but disconnect from Twitter. ' .
- 'You can use your %1$s password to log in.');
- $site = common_config('site', 'name');
-
- $this->element('p', 'instructions',
- sprintf($note, $site));
-
- // TRANS: Button text for disconnecting a Twitter account.
- $this->submit('disconnect', _m('BUTTON','Disconnect'));
- }
-
- $this->elementEnd('fieldset');
-
- $this->elementStart('fieldset', array('id' => 'settings_twitter_preferences'));
-
- // TRANS: Fieldset legend.
- $this->element('legend', null, _m('Preferences'));
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li');
- $this->checkbox('noticesend',
- // TRANS: Checkbox label.
- _m('Automatically send my notices to Twitter.'),
- ($flink) ?
- ($flink->noticesync & FOREIGN_NOTICE_SEND) :
- true);
- $this->elementEnd('li');
- $this->elementStart('li');
- $this->checkbox('replysync',
- // TRANS: Checkbox label.
- _m('Send local "@" replies to Twitter.'),
- ($flink) ?
- ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) :
- true);
- $this->elementEnd('li');
- $this->elementStart('li');
- $this->checkbox('friendsync',
- // TRANS: Checkbox label.
- _m('Subscribe to my Twitter friends here.'),
- ($flink) ?
- ($flink->friendsync & FOREIGN_FRIEND_RECV) :
- false);
- $this->elementEnd('li');
-
- if (common_config('twitterimport','enabled')) {
- $this->elementStart('li');
- $this->checkbox('noticerecv',
- // TRANS: Checkbox label.
- _m('Import my friends timeline.'),
- ($flink) ?
- ($flink->noticesync & FOREIGN_NOTICE_RECV) :
- false);
- $this->elementEnd('li');
- } else {
- // preserve setting even if bidrection bridge toggled off
-
- if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) {
- $this->hidden('noticerecv', true, 'noticerecv');
- }
- }
-
- $this->elementEnd('ul');
-
- if ($flink) {
- // TRANS: Button text for saving Twitter integration settings.
- $this->submit('save', _m('BUTTON','Save'));
- } else {
- // TRANS: Button text for adding Twitter integration.
- $this->submit('add', _m('BUTTON','Add'));
- }
-
- $this->elementEnd('fieldset');
- }
-
- $this->elementEnd('form');
- }
-
- /**
- * Handle posts to this form
- *
- * Based on the button that was pressed, muxes out to other functions
- * to do the actual task requested.
- *
- * All sub-functions reload the form with a message -- success or failure.
- *
- * @return void
- */
- function handlePost()
- {
- // CSRF protection
- $token = $this->trimmed('token');
- if (!$token || $token != common_session_token()) {
- // TRANS: Client error displayed when the session token does not match or is not given.
- $this->showForm(_m('There was a problem with your session token. '.
- 'Try again, please.'));
- return;
- }
-
- if ($this->arg('save')) {
- $this->savePreferences();
- } else if ($this->arg('disconnect')) {
- $this->removeTwitterAccount();
- } else {
- // TRANS: Client error displayed when the submitted form contains unexpected data.
- $this->showForm(_m('Unexpected form submission.'));
- }
- }
-
- /**
- * Disassociate an existing Twitter account from this account
- *
- * @return void
- */
- function removeTwitterAccount()
- {
- $user = common_current_user();
- $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
-
- if (empty($flink)) {
- // TRANS: Client error displayed when trying to remove a connected Twitter account when there isn't one connected.
- $this->clientError(_m('No Twitter connection to remove.'));
- return;
- }
-
- $result = $flink->safeDelete();
-
- if (empty($result)) {
- common_log_db_error($flink, 'DELETE', __FILE__);
- // TRANS: Server error displayed when trying to remove a connected Twitter account fails.
- $this->serverError(_m('Could not remove Twitter user.'));
- return;
- }
-
- // TRANS: Success message displayed after disconnecting a Twitter account.
- $this->showForm(_m('Twitter account disconnected.'), true);
- }
-
- /**
- * Save user's Twitter-bridging preferences
- *
- * @return void
- */
- function savePreferences()
- {
- $noticesend = $this->boolean('noticesend');
- $noticerecv = $this->boolean('noticerecv');
- $friendsync = $this->boolean('friendsync');
- $replysync = $this->boolean('replysync');
-
- $user = common_current_user();
- $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
-
- if (empty($flink)) {
- common_log_db_error($flink, 'SELECT', __FILE__);
- // @todo FIXME: Shouldn't this be a serverError()?
- // TRANS: Server error displayed when saving Twitter integration preferences fails.
- $this->showForm(_m('Could not save Twitter preferences.'));
- return;
- }
-
- $original = clone($flink);
- $wasReceiving = (bool)($original->noticesync & FOREIGN_NOTICE_RECV);
- $flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
- $result = $flink->update($original);
-
- if ($result === false) {
- common_log_db_error($flink, 'UPDATE', __FILE__);
- // @todo FIXME: Shouldn't this be a serverError()?
- // TRANS: Server error displayed when saving Twitter integration preferences fails.
- $this->showForm(_m('Could not save Twitter preferences.'));
- return;
- }
-
- if ($wasReceiving xor $noticerecv) {
- $this->notifyDaemon($flink->foreign_id, $noticerecv);
- }
-
- // TRANS: Success message after saving Twitter integration preferences.
- $this->showForm(_m('Twitter preferences saved.'), true);
- }
-
- /**
- * Tell the import daemon that we've updated a user's receive status.
- */
- function notifyDaemon($twitterUserId, $receiving)
- {
- // @todo... should use control signals rather than queues
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * 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
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-/**
- * Base class for reading Twitter's User Streams and Site Streams
- * real-time streaming APIs.
- *
- * Caller can hook event callbacks for various types of messages;
- * the data from the stream and some context info will be passed
- * on to the callbacks.
- */
-abstract class TwitterStreamReader extends JsonStreamReader
-{
- protected $callbacks = array();
-
- function __construct(TwitterOAuthClient $auth, $baseUrl)
- {
- $this->baseUrl = $baseUrl;
- $this->oauth = $auth;
- }
-
- public function connect($method, $params=array())
- {
- $url = $this->oAuthUrl($this->baseUrl . '/' . $method, $params);
- return parent::connect($url);
- }
-
- /**
- * Sign our target URL with OAuth auth stuff.
- *
- * @param string $url
- * @param array $params
- * @return string
- */
- protected function oAuthUrl($url, $params=array())
- {
- // In an ideal world this would be better encapsulated. :)
- $request = OAuthRequest::from_consumer_and_token($this->oauth->consumer,
- $this->oauth->token, 'GET', $url, $params);
- $request->sign_request($this->oauth->sha1_method,
- $this->oauth->consumer, $this->oauth->token);
-
- return $request->to_url();
- }
-
- /**
- * Add an event callback to receive notifications when things come in
- * over the wire.
- *
- * Callbacks should be in the form: function(object $data, array $context)
- * where $context may list additional data on some streams, such as the
- * user to whom the message should be routed.
- *
- * Available events:
- *
- * Messaging:
- *
- * 'status': $data contains a status update in standard Twitter JSON format.
- * $data->user: sending user in standard Twitter JSON format.
- * $data->text... etc
- *
- * 'direct_message': $data contains a direct message in standard Twitter JSON format.
- * $data->sender: sending user in standard Twitter JSON format.
- * $data->recipient: receiving user in standard Twitter JSON format.
- * $data->text... etc
- *
- *
- * Out of band events:
- *
- * 'follow': User has either started following someone, or is being followed.
- * $data->source: following user in standard Twitter JSON format.
- * $data->target: followed user in standard Twitter JSON format.
- *
- * 'favorite': Someone has favorited a status update.
- * $data->source: user doing the favoriting, in standard Twitter JSON format.
- * $data->target: user whose status was favorited, in standard Twitter JSON format.
- * $data->target_object: the favorited status update in standard Twitter JSON format.
- *
- * 'unfavorite': Someone has unfavorited a status update.
- * $data->source: user doing the unfavoriting, in standard Twitter JSON format.
- * $data->target: user whose status was unfavorited, in standard Twitter JSON format.
- * $data->target_object: the unfavorited status update in standard Twitter JSON format.
- *
- *
- * Meta information:
- *
- * 'friends':
- * $data->friends: array of user IDs of the current user's friends.
- *
- * 'delete': Advisory that a Twitter status has been deleted; nice clients
- * should follow suit.
- * $data->id: ID of status being deleted
- * $data->user_id: ID of its owning user
- *
- * 'scrub_geo': Advisory that a user is clearing geo data from their status
- * stream; nice clients should follow suit.
- * $data->user_id: ID of user
- * $data->up_to_status_id: any notice older than this should be scrubbed.
- *
- * 'limit': Advisory that tracking has hit a resource limit.
- * $data->track
- *
- * 'raw': receives the full JSON data for all message types.
- *
- * @param string $event
- * @param callable $callback
- */
- public function hookEvent($event, $callback)
- {
- $this->callbacks[$event][] = $callback;
- }
-
- /**
- * Call event handler callbacks for the given event.
- *
- * @param string $event
- * @param mixed $arg1 ... one or more params to pass on
- */
- protected function fireEvent($event, $arg1)
- {
- if (array_key_exists($event, $this->callbacks)) {
- $args = array_slice(func_get_args(), 1);
- foreach ($this->callbacks[$event] as $callback) {
- call_user_func_array($callback, $args);
- }
- }
- }
-
- protected function handleJson(stdClass $data)
- {
- $this->routeMessage($data);
- }
-
- abstract protected function routeMessage(stdClass $data);
-
- /**
- * Send the decoded JSON object out to any event listeners.
- *
- * @param array $data
- * @param array $context optional additional context data to pass on
- */
- protected function handleMessage(stdClass $data, array $context=array())
- {
- $this->fireEvent('raw', $data, $context);
-
- if (isset($data->text)) {
- $this->fireEvent('status', $data, $context);
- return;
- }
- if (isset($data->event)) {
- $this->fireEvent($data->event, $data, $context);
- return;
- }
- if (isset($data->friends)) {
- $this->fireEvent('friends', $data, $context);
- }
-
- $knownMeta = array('delete', 'scrub_geo', 'limit', 'direct_message');
- foreach ($knownMeta as $key) {
- if (isset($data->$key)) {
- $this->fireEvent($key, $data->$key, $context);
- return;
- }
- }
- }
-}
-
-/**
- * Multiuser stream listener for Twitter Site Streams API
- * http://dev.twitter.com/pages/site_streams
- *
- * The site streams API allows listening to updates for multiple users.
- * Pass in the user IDs to listen to in via followUser() -- note they
- * must each have a valid OAuth token for the application ID we're
- * connecting as.
- *
- * You'll need to be connecting with the auth keys for the user who
- * owns the application registration.
- *
- * The user each message is destined for will be passed to event handlers
- * in $context['for_user_id'].
- */
-class TwitterSiteStream extends TwitterStreamReader
-{
- protected $userIds;
-
- public function __construct(TwitterOAuthClient $auth, $baseUrl='https://sitestream.twitter.com')
- {
- parent::__construct($auth, $baseUrl);
- }
-
- public function connect($method='2b/site.json')
- {
- $params = array();
- if ($this->userIds) {
- $params['follow'] = implode(',', $this->userIds);
- }
- return parent::connect($method, $params);
- }
-
- /**
- * Set the users whose home streams should be pulled.
- * They all must have valid oauth tokens for this application.
- *
- * Must be called before connect().
- *
- * @param array $userIds
- */
- function followUsers($userIds)
- {
- $this->userIds = $userIds;
- }
-
- /**
- * Each message in the site stream tells us which user ID it should be
- * routed to; we'll need that to let the caller know what to do.
- *
- * @param array $data
- */
- function routeMessage(stdClass $data)
- {
- $context = array(
- 'source' => 'sitestream',
- 'for_user' => $data->for_user
- );
- parent::handleMessage($data->message, $context);
- }
-}
-
-/**
- * Stream listener for Twitter User Streams API
- * http://dev.twitter.com/pages/user_streams
- *
- * This will pull the home stream and additional events just for the user
- * we've authenticated as.
- */
-class TwitterUserStream extends TwitterStreamReader
-{
- public function __construct(TwitterOAuthClient $auth, $baseUrl='https://userstream.twitter.com')
- {
- parent::__construct($auth, $baseUrl);
- }
-
- public function connect($method='2/user.json')
- {
- return parent::connect($method);
- }
-
- /**
- * Each message in the user stream is just ready to go.
- *
- * @param array $data
- */
- function routeMessage(stdClass $data)
- {
- $context = array(
- 'source' => 'userstream'
- );
- parent::handleMessage($data, $context);
- }
-}
return true;
}
- /**
- * Auto-load our classes if called
- *
- * @param string $cls Class to load
- *
- * @return boolean hook return
- */
- function onAutoload($cls)
- {
- switch (strtolower($cls))
- {
- case 'flagprofileaction':
- case 'adminprofileflagaction':
- case 'clearflagaction':
- include_once INSTALLDIR.'/plugins/UserFlag/' .
- strtolower(mb_substr($cls, 0, -6)) . '.php';
- return false;
- case 'flagprofileform':
- case 'clearflagform':
- include_once INSTALLDIR.'/plugins/UserFlag/' . strtolower($cls . '.php');
- return false;
- case 'user_flag_profile':
- include_once INSTALLDIR.'/plugins/UserFlag/'.ucfirst(strtolower($cls)).'.php';
- return false;
- default:
- return true;
- }
- }
-
/**
* Add a 'flag' button to profile page
*
+++ /dev/null
-<?php
-/**
- * Data class for profile flags
- *
- * PHP version 5
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
-
-/**
- * Data class for profile flags
- *
- * A class representing a user flagging another profile for review.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class User_flag_profile extends Managed_DataObject
-{
- ###START_AUTOCODE
- /* the code below is auto generated do not remove the above tag */
-
- public $__table = 'user_flag_profile'; // table name
- public $profile_id; // int(11) primary_key not_null
- public $user_id; // int(11) primary_key not_null
- public $cleared; // datetime default_0000-00-00%2000%3A00%3A00
- public $created; // datetime() not_null
- public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
-
- /* the code above is auto generated do not remove the tag below */
- ###END_AUTOCODE
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile id flagged'),
- 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id of the actor'),
- 'cleared' => array('type' => 'datetime', 'description' => 'when flag was removed'),
- 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
- 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
- ),
- 'primary key' => array('profile_id', 'user_id'),
- 'indexes' => array(
- 'user_flag_profile_cleared_idx' => array('cleared'),
- 'user_flag_profile_created_idx' => array('created'),
- ),
- );
- }
-
- /**
- * Check if a flag exists for given profile and user
- *
- * @param integer $profile_id Profile to check for
- * @param integer $user_id User to check for
- *
- * @return boolean true if exists, else false
- */
- static function exists($profile_id, $user_id)
- {
- $ufp = User_flag_profile::pkeyGet(array('profile_id' => $profile_id,
- 'user_id' => $user_id));
-
- return !empty($ufp);
- }
-
- /**
- * Create a new flag
- *
- * @param integer $user_id ID of user who's flagging
- * @param integer $profile_id ID of profile being flagged
- *
- * @return boolean success flag
- */
- static function create($user_id, $profile_id)
- {
- $ufp = new User_flag_profile();
-
- $ufp->profile_id = $profile_id;
- $ufp->user_id = $user_id;
- $ufp->created = common_sql_now();
-
- if (!$ufp->insert()) {
- // TRANS: Server exception.
- // TRANS: %d is a profile ID (number).
- $msg = sprintf(_m('Could not flag profile "%d" for review.'),
- $profile_id);
- throw new ServerException($msg);
- }
-
- $ufp->free();
-
- return true;
- }
-}
--- /dev/null
+<?php
+/**
+ * Show latest and greatest profile flags
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Show the latest and greatest profile flags
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class AdminprofileflagAction extends Action
+{
+ var $page = null;
+ var $profiles = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $user = common_current_user();
+
+ // User must be logged in.
+
+ if (!common_logged_in()) {
+ // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
+ $this->clientError(_m('Not logged in.'));
+ return;
+ }
+
+ $user = common_current_user();
+
+ // ...because they're logged in
+
+ assert(!empty($user));
+
+ // It must be a "real" login, not saved cookie login
+
+ if (!common_is_real_login()) {
+ // Cookie theft is too easy; we require automatic
+ // logins to re-authenticate before admining the site
+ common_set_returnto($this->selfUrl());
+ if (Event::handle('RedirectToLogin', array($this, $user))) {
+ common_redirect(common_local_url('login'), 303);
+ }
+ }
+
+ // User must have the right to review flags
+
+ if (!$user->hasRight(UserFlagPlugin::REVIEWFLAGS)) {
+ // TRANS: Error message displayed when trying to review profile flags while not authorised.
+ $this->clientError(_m('You cannot review profile flags.'));
+ return false;
+ }
+
+ $this->page = $this->trimmed('page');
+
+ if (empty($this->page)) {
+ $this->page = 1;
+ }
+
+ $this->profiles = $this->getProfiles();
+
+ return true;
+ }
+
+ /**
+ * Handle request
+ *
+ * @param array $args $_REQUEST args; handled in prepare()
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ $this->showPage();
+ }
+
+ /**
+ * Title of this page
+ *
+ * @return string Title of the page
+ */
+ function title()
+ {
+ // TRANS: Title for page with a list of profiles that were flagged for review.
+ return _m('Flagged profiles');
+ }
+
+ /**
+ * save the profile flag
+ *
+ * @return void
+ */
+ function showContent()
+ {
+ $pl = new FlaggedProfileList($this->profiles, $this);
+
+ $cnt = $pl->show();
+
+ $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
+ $this->page, 'adminprofileflag');
+ }
+
+ /**
+ * Retrieve this action's profiles
+ *
+ * @return Profile $profile Profile query results
+ */
+ function getProfiles()
+ {
+ $ufp = new User_flag_profile();
+
+ $ufp->selectAdd();
+ $ufp->selectAdd('profile_id');
+ $ufp->selectAdd('count(*) as flag_count');
+
+ $ufp->whereAdd('cleared is NULL');
+
+ $ufp->groupBy('profile_id');
+ $ufp->orderBy('flag_count DESC, profile_id DESC');
+
+ $offset = ($this->page-1) * PROFILES_PER_PAGE;
+ $limit = PROFILES_PER_PAGE + 1;
+
+ $ufp->limit($offset, $limit);
+
+ $profiles = array();
+
+ if ($ufp->find()) {
+ while ($ufp->fetch()) {
+ $profile = Profile::getKV('id', $ufp->profile_id);
+ if (!empty($profile)) {
+ $profiles[] = $profile;
+ }
+ }
+ }
+
+ $ufp->free();
+
+ return new ArrayWrapper($profiles);
+ }
+}
+
+/**
+ * Specialization of ProfileList to show flagging information
+ *
+ * Most of the hard part is done in FlaggedProfileListItem.
+ *
+ * @category Widget
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class FlaggedProfileList extends ProfileList
+{
+ /**
+ * Factory method for creating new list items
+ *
+ * @param Profile $profile Profile to create an item for
+ *
+ * @return ProfileListItem newly-created item
+ */
+ function newListItem($profile)
+ {
+ return new FlaggedProfileListItem($this->profile, $this->action);
+ }
+}
+
+/**
+ * Specialization of ProfileListItem to show flagging information
+ *
+ * @category Widget
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class FlaggedProfileListItem extends ProfileListItem
+{
+ const MAX_FLAGGERS = 5;
+
+ var $user = null;
+ var $r2args = null;
+
+ /**
+ * Overload parent's action list with our own moderation-oriented buttons
+ *
+ * @return void
+ */
+ function showActions()
+ {
+ $this->user = common_current_user();
+
+ list($action, $this->r2args) = $this->out->returnToArgs();
+
+ $this->r2args['action'] = $action;
+
+ $this->startActions();
+ if (Event::handle('StartProfileListItemActionElements', array($this))) {
+ $this->out->elementStart('li', 'entity_moderation');
+ // TRANS: Header for moderation menu with action buttons for flagged profiles (like 'sandbox', 'silence', ...).
+ $this->out->element('p', null, _m('Moderate'));
+ $this->out->elementStart('ul');
+ $this->showSandboxButton();
+ $this->showSilenceButton();
+ $this->showDeleteButton();
+ $this->showClearButton();
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('li');
+ Event::handle('EndProfileListItemActionElements', array($this));
+ }
+ $this->endActions();
+ }
+
+ /**
+ * Show a button to sandbox the profile
+ *
+ * @return void
+ */
+ function showSandboxButton()
+ {
+ if ($this->user->hasRight(Right::SANDBOXUSER)) {
+ $this->out->elementStart('li', 'entity_sandbox');
+ if ($this->profile->isSandboxed()) {
+ $usf = new UnSandboxForm($this->out, $this->profile, $this->r2args);
+ $usf->show();
+ } else {
+ $sf = new SandboxForm($this->out, $this->profile, $this->r2args);
+ $sf->show();
+ }
+ $this->out->elementEnd('li');
+ }
+ }
+
+ /**
+ * Show a button to silence the profile
+ *
+ * @return void
+ */
+ function showSilenceButton()
+ {
+ if ($this->user->hasRight(Right::SILENCEUSER)) {
+ $this->out->elementStart('li', 'entity_silence');
+ if ($this->profile->isSilenced()) {
+ $usf = new UnSilenceForm($this->out, $this->profile, $this->r2args);
+ $usf->show();
+ } else {
+ $sf = new SilenceForm($this->out, $this->profile, $this->r2args);
+ $sf->show();
+ }
+ $this->out->elementEnd('li');
+ }
+ }
+
+ /**
+ * Show a button to delete user and profile
+ *
+ * @return void
+ */
+ function showDeleteButton()
+ {
+
+ if ($this->user->hasRight(Right::DELETEUSER)) {
+ $this->out->elementStart('li', 'entity_delete');
+ $df = new DeleteUserForm($this->out, $this->profile, $this->r2args);
+ $df->show();
+ $this->out->elementEnd('li');
+ }
+ }
+
+ /**
+ * Show a button to clear flags
+ *
+ * @return void
+ */
+ function showClearButton()
+ {
+ if ($this->user->hasRight(UserFlagPlugin::CLEARFLAGS)) {
+ $this->out->elementStart('li', 'entity_clear');
+ $cf = new ClearFlagForm($this->out, $this->profile, $this->r2args);
+ $cf->show();
+ $this->out->elementEnd('li');
+ }
+ }
+
+ /**
+ * Overload parent function to add flaggers list
+ *
+ * @return void
+ */
+ function endProfile()
+ {
+ $this->showFlaggersList();
+ parent::endProfile();
+ }
+
+ /**
+ * Show a list of people who've flagged this profile
+ *
+ * @return void
+ */
+ function showFlaggersList()
+ {
+ $flaggers = array();
+
+ $ufp = new User_flag_profile();
+
+ $ufp->selectAdd();
+ $ufp->selectAdd('user_id');
+ $ufp->profile_id = $this->profile->id;
+ $ufp->orderBy('created');
+
+ if ($ufp->find()) { // XXX: this should always happen
+ while ($ufp->fetch()) {
+ $user = User::getKV('id', $ufp->user_id);
+ if (!empty($user)) { // XXX: this would also be unusual
+ $flaggers[] = clone($user);
+ }
+ }
+ }
+
+ $cnt = count($flaggers);
+ $others = 0;
+
+ if ($cnt > self::MAX_FLAGGERS) {
+ $flaggers = array_slice($flaggers, 0, self::MAX_FLAGGERS);
+ $others = $cnt - self::MAX_FLAGGERS;
+ }
+
+ $lnks = array();
+
+ foreach ($flaggers as $flagger) {
+
+ $url = common_local_url('showstream',
+ array('nickname' => $flagger->nickname));
+
+ $lnks[] = XMLStringer::estring('a', array('href' => $url,
+ 'class' => 'flagger'),
+ $flagger->nickname);
+ }
+
+ if ($cnt > 0) {
+ if ($others > 0) {
+ $flagging_users = implode(', ', $lnks);
+ // TRANS: Message displayed on a profile if it has been flagged.
+ // TRANS: %1$s is a comma separated list of at most 5 user nicknames that flagged.
+ // TRANS: %2$d is a positive integer of additional flagging users. Also used for plural.
+ $text .= sprintf(_m('Flagged by %1$s and %2$d other', 'Flagged by %1$s and %2$d others', $others), $flagging_users, $others);
+ } else {
+ // TRANS: Message displayed on a profile if it has been flagged.
+ // TRANS: %s is a comma separated list of at most 5 user nicknames that flagged.
+ $text .= sprintf(_m('Flagged by %s'), $flagging_users);
+ }
+
+ $this->out->elementStart('p', array('class' => 'flaggers'));
+ $this->out->raw($text);
+ $this->out->elementEnd('p');
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * Clear all flags for a profile
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Action to clear flags for a profile
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class ClearflagAction extends ProfileFormAction
+{
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ if (!parent::prepare($args)) {
+ return false;
+ }
+
+ $user = common_current_user();
+
+ assert(!empty($user)); // checked above
+ assert(!empty($this->profile)); // checked above
+
+ return true;
+ }
+
+ /**
+ * Handle request
+ *
+ * Overriding the base Action's handle() here to deal check
+ * for Ajax and return an HXR response if necessary
+ *
+ * @param array $args $_REQUEST args; handled in prepare()
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $this->handlePost();
+ if (!$this->boolean('ajax')) {
+ $this->returnToPrevious();
+ }
+ }
+ }
+
+ /**
+ * Handle POST
+ *
+ * Executes the actions; deletes all flags
+ *
+ * @return void
+ */
+ function handlePost()
+ {
+ $ufp = new User_flag_profile();
+
+ $result = $ufp->query('UPDATE user_flag_profile ' .
+ 'SET cleared = now() ' .
+ 'WHERE cleared is null ' .
+ 'AND profile_id = ' . $this->profile->id);
+
+ if ($result == false) {
+ // TRANS: Server exception given when flags could not be cleared.
+ // TRANS: %s is a profile nickname.
+ $msg = sprintf(_m('Could not clear flags for profile "%s".'),
+ $this->profile->nickname);
+ throw new ServerException($msg);
+ }
+
+ $ufp->free();
+
+ if ($this->boolean('ajax')) {
+ $this->ajaxResults();
+ }
+ }
+
+ /**
+ * Return results in ajax form
+ *
+ * @return void
+ */
+ function ajaxResults()
+ {
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Title for AJAX form to indicated that flags were removed.
+ $this->element('title', null, _m('Flags cleared'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ // TRANS: Body element for "flags cleared" form.
+ $this->element('p', 'cleared', _m('Cleared'));
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ }
+}
--- /dev/null
+<?php
+/**
+ * Add a flag to a profile
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+/**
+ * Action to flag a profile.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class FlagprofileAction extends ProfileFormAction
+{
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ */
+ function prepare($args)
+ {
+ if (!parent::prepare($args)) {
+ return false;
+ }
+
+ $user = common_current_user();
+
+ assert(!empty($user)); // checked above
+ assert(!empty($this->profile)); // checked above
+
+ return true;
+ }
+
+ /**
+ * Handle request
+ *
+ * Overriding the base Action's handle() here to deal check
+ * for Ajax and return an HXR response if necessary
+ *
+ * @param array $args $_REQUEST args; handled in prepare()
+ *
+ * @return void
+ */
+ function handle($args)
+ {
+ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $this->handlePost();
+ if (!$this->boolean('ajax')) {
+ $this->returnToPrevious();
+ }
+ }
+ }
+
+ /**
+ * Handle POST
+ *
+ * @return void
+ */
+ function handlePost()
+ {
+ $user = common_current_user();
+
+ assert(!empty($user));
+ assert(!empty($this->profile));
+
+ // throws an exception on error
+
+ if (User_flag_profile::exists($this->profile->id,
+ $user->id)) {
+ // We'll return to the profile page (or return the updated AJAX form)
+ // showing the current state, so no harm done.
+ } else {
+ User_flag_profile::create($user->id, $this->profile->id);
+ }
+
+ if ($this->boolean('ajax')) {
+ $this->ajaxResults();
+ }
+ }
+
+ /**
+ * Return results as AJAX message
+ *
+ * @return void
+ */
+ function ajaxResults()
+ {
+ header('Content-Type: text/xml;charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: AJAX form title for a flagged profile.
+ $this->element('title', null, _m('Flagged for review'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ // TRANS: Body text for AJAX form when a profile has been flagged for review.
+ $this->element('p', 'flagged', _m('Flagged'));
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ }
+}
+++ /dev/null
-<?php
-/**
- * Show latest and greatest profile flags
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Show the latest and greatest profile flags
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class AdminprofileflagAction extends Action
-{
- var $page = null;
- var $profiles = null;
-
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- parent::prepare($args);
-
- $user = common_current_user();
-
- // User must be logged in.
-
- if (!common_logged_in()) {
- // TRANS: Error message displayed when trying to perform an action that requires a logged in user.
- $this->clientError(_m('Not logged in.'));
- return;
- }
-
- $user = common_current_user();
-
- // ...because they're logged in
-
- assert(!empty($user));
-
- // It must be a "real" login, not saved cookie login
-
- if (!common_is_real_login()) {
- // Cookie theft is too easy; we require automatic
- // logins to re-authenticate before admining the site
- common_set_returnto($this->selfUrl());
- if (Event::handle('RedirectToLogin', array($this, $user))) {
- common_redirect(common_local_url('login'), 303);
- }
- }
-
- // User must have the right to review flags
-
- if (!$user->hasRight(UserFlagPlugin::REVIEWFLAGS)) {
- // TRANS: Error message displayed when trying to review profile flags while not authorised.
- $this->clientError(_m('You cannot review profile flags.'));
- return false;
- }
-
- $this->page = $this->trimmed('page');
-
- if (empty($this->page)) {
- $this->page = 1;
- }
-
- $this->profiles = $this->getProfiles();
-
- return true;
- }
-
- /**
- * Handle request
- *
- * @param array $args $_REQUEST args; handled in prepare()
- *
- * @return void
- */
- function handle($args)
- {
- parent::handle($args);
-
- $this->showPage();
- }
-
- /**
- * Title of this page
- *
- * @return string Title of the page
- */
- function title()
- {
- // TRANS: Title for page with a list of profiles that were flagged for review.
- return _m('Flagged profiles');
- }
-
- /**
- * save the profile flag
- *
- * @return void
- */
- function showContent()
- {
- $pl = new FlaggedProfileList($this->profiles, $this);
-
- $cnt = $pl->show();
-
- $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
- $this->page, 'adminprofileflag');
- }
-
- /**
- * Retrieve this action's profiles
- *
- * @return Profile $profile Profile query results
- */
- function getProfiles()
- {
- $ufp = new User_flag_profile();
-
- $ufp->selectAdd();
- $ufp->selectAdd('profile_id');
- $ufp->selectAdd('count(*) as flag_count');
-
- $ufp->whereAdd('cleared is NULL');
-
- $ufp->groupBy('profile_id');
- $ufp->orderBy('flag_count DESC, profile_id DESC');
-
- $offset = ($this->page-1) * PROFILES_PER_PAGE;
- $limit = PROFILES_PER_PAGE + 1;
-
- $ufp->limit($offset, $limit);
-
- $profiles = array();
-
- if ($ufp->find()) {
- while ($ufp->fetch()) {
- $profile = Profile::getKV('id', $ufp->profile_id);
- if (!empty($profile)) {
- $profiles[] = $profile;
- }
- }
- }
-
- $ufp->free();
-
- return new ArrayWrapper($profiles);
- }
-}
-
-/**
- * Specialization of ProfileList to show flagging information
- *
- * Most of the hard part is done in FlaggedProfileListItem.
- *
- * @category Widget
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class FlaggedProfileList extends ProfileList
-{
- /**
- * Factory method for creating new list items
- *
- * @param Profile $profile Profile to create an item for
- *
- * @return ProfileListItem newly-created item
- */
- function newListItem($profile)
- {
- return new FlaggedProfileListItem($this->profile, $this->action);
- }
-}
-
-/**
- * Specialization of ProfileListItem to show flagging information
- *
- * @category Widget
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class FlaggedProfileListItem extends ProfileListItem
-{
- const MAX_FLAGGERS = 5;
-
- var $user = null;
- var $r2args = null;
-
- /**
- * Overload parent's action list with our own moderation-oriented buttons
- *
- * @return void
- */
- function showActions()
- {
- $this->user = common_current_user();
-
- list($action, $this->r2args) = $this->out->returnToArgs();
-
- $this->r2args['action'] = $action;
-
- $this->startActions();
- if (Event::handle('StartProfileListItemActionElements', array($this))) {
- $this->out->elementStart('li', 'entity_moderation');
- // TRANS: Header for moderation menu with action buttons for flagged profiles (like 'sandbox', 'silence', ...).
- $this->out->element('p', null, _m('Moderate'));
- $this->out->elementStart('ul');
- $this->showSandboxButton();
- $this->showSilenceButton();
- $this->showDeleteButton();
- $this->showClearButton();
- $this->out->elementEnd('ul');
- $this->out->elementEnd('li');
- Event::handle('EndProfileListItemActionElements', array($this));
- }
- $this->endActions();
- }
-
- /**
- * Show a button to sandbox the profile
- *
- * @return void
- */
- function showSandboxButton()
- {
- if ($this->user->hasRight(Right::SANDBOXUSER)) {
- $this->out->elementStart('li', 'entity_sandbox');
- if ($this->profile->isSandboxed()) {
- $usf = new UnSandboxForm($this->out, $this->profile, $this->r2args);
- $usf->show();
- } else {
- $sf = new SandboxForm($this->out, $this->profile, $this->r2args);
- $sf->show();
- }
- $this->out->elementEnd('li');
- }
- }
-
- /**
- * Show a button to silence the profile
- *
- * @return void
- */
- function showSilenceButton()
- {
- if ($this->user->hasRight(Right::SILENCEUSER)) {
- $this->out->elementStart('li', 'entity_silence');
- if ($this->profile->isSilenced()) {
- $usf = new UnSilenceForm($this->out, $this->profile, $this->r2args);
- $usf->show();
- } else {
- $sf = new SilenceForm($this->out, $this->profile, $this->r2args);
- $sf->show();
- }
- $this->out->elementEnd('li');
- }
- }
-
- /**
- * Show a button to delete user and profile
- *
- * @return void
- */
- function showDeleteButton()
- {
-
- if ($this->user->hasRight(Right::DELETEUSER)) {
- $this->out->elementStart('li', 'entity_delete');
- $df = new DeleteUserForm($this->out, $this->profile, $this->r2args);
- $df->show();
- $this->out->elementEnd('li');
- }
- }
-
- /**
- * Show a button to clear flags
- *
- * @return void
- */
- function showClearButton()
- {
- if ($this->user->hasRight(UserFlagPlugin::CLEARFLAGS)) {
- $this->out->elementStart('li', 'entity_clear');
- $cf = new ClearFlagForm($this->out, $this->profile, $this->r2args);
- $cf->show();
- $this->out->elementEnd('li');
- }
- }
-
- /**
- * Overload parent function to add flaggers list
- *
- * @return void
- */
- function endProfile()
- {
- $this->showFlaggersList();
- parent::endProfile();
- }
-
- /**
- * Show a list of people who've flagged this profile
- *
- * @return void
- */
- function showFlaggersList()
- {
- $flaggers = array();
-
- $ufp = new User_flag_profile();
-
- $ufp->selectAdd();
- $ufp->selectAdd('user_id');
- $ufp->profile_id = $this->profile->id;
- $ufp->orderBy('created');
-
- if ($ufp->find()) { // XXX: this should always happen
- while ($ufp->fetch()) {
- $user = User::getKV('id', $ufp->user_id);
- if (!empty($user)) { // XXX: this would also be unusual
- $flaggers[] = clone($user);
- }
- }
- }
-
- $cnt = count($flaggers);
- $others = 0;
-
- if ($cnt > self::MAX_FLAGGERS) {
- $flaggers = array_slice($flaggers, 0, self::MAX_FLAGGERS);
- $others = $cnt - self::MAX_FLAGGERS;
- }
-
- $lnks = array();
-
- foreach ($flaggers as $flagger) {
-
- $url = common_local_url('showstream',
- array('nickname' => $flagger->nickname));
-
- $lnks[] = XMLStringer::estring('a', array('href' => $url,
- 'class' => 'flagger'),
- $flagger->nickname);
- }
-
- if ($cnt > 0) {
- if ($others > 0) {
- $flagging_users = implode(', ', $lnks);
- // TRANS: Message displayed on a profile if it has been flagged.
- // TRANS: %1$s is a comma separated list of at most 5 user nicknames that flagged.
- // TRANS: %2$d is a positive integer of additional flagging users. Also used for plural.
- $text .= sprintf(_m('Flagged by %1$s and %2$d other', 'Flagged by %1$s and %2$d others', $others), $flagging_users, $others);
- } else {
- // TRANS: Message displayed on a profile if it has been flagged.
- // TRANS: %s is a comma separated list of at most 5 user nicknames that flagged.
- $text .= sprintf(_m('Flagged by %s'), $flagging_users);
- }
-
- $this->out->elementStart('p', array('class' => 'flaggers'));
- $this->out->raw($text);
- $this->out->elementEnd('p');
- }
- }
-}
--- /dev/null
+<?php
+/**
+ * Data class for profile flags
+ *
+ * PHP version 5
+ *
+ * @category Data
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+/**
+ * Data class for profile flags
+ *
+ * A class representing a user flagging another profile for review.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
+class User_flag_profile extends Managed_DataObject
+{
+ ###START_AUTOCODE
+ /* the code below is auto generated do not remove the above tag */
+
+ public $__table = 'user_flag_profile'; // table name
+ public $profile_id; // int(11) primary_key not_null
+ public $user_id; // int(11) primary_key not_null
+ public $cleared; // datetime default_0000-00-00%2000%3A00%3A00
+ public $created; // datetime() not_null
+ public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
+
+ /* the code above is auto generated do not remove the tag below */
+ ###END_AUTOCODE
+
+ public static function schemaDef()
+ {
+ return array(
+ 'fields' => array(
+ 'profile_id' => array('type' => 'int', 'not null' => true, 'description' => 'profile id flagged'),
+ 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user id of the actor'),
+ 'cleared' => array('type' => 'datetime', 'description' => 'when flag was removed'),
+ 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'),
+ ),
+ 'primary key' => array('profile_id', 'user_id'),
+ 'indexes' => array(
+ 'user_flag_profile_cleared_idx' => array('cleared'),
+ 'user_flag_profile_created_idx' => array('created'),
+ ),
+ );
+ }
+
+ /**
+ * Check if a flag exists for given profile and user
+ *
+ * @param integer $profile_id Profile to check for
+ * @param integer $user_id User to check for
+ *
+ * @return boolean true if exists, else false
+ */
+ static function exists($profile_id, $user_id)
+ {
+ $ufp = User_flag_profile::pkeyGet(array('profile_id' => $profile_id,
+ 'user_id' => $user_id));
+
+ return !empty($ufp);
+ }
+
+ /**
+ * Create a new flag
+ *
+ * @param integer $user_id ID of user who's flagging
+ * @param integer $profile_id ID of profile being flagged
+ *
+ * @return boolean success flag
+ */
+ static function create($user_id, $profile_id)
+ {
+ $ufp = new User_flag_profile();
+
+ $ufp->profile_id = $profile_id;
+ $ufp->user_id = $user_id;
+ $ufp->created = common_sql_now();
+
+ if (!$ufp->insert()) {
+ // TRANS: Server exception.
+ // TRANS: %d is a profile ID (number).
+ $msg = sprintf(_m('Could not flag profile "%d" for review.'),
+ $profile_id);
+ throw new ServerException($msg);
+ }
+
+ $ufp->free();
+
+ return true;
+ }
+}
+++ /dev/null
-<?php
-/**
- * Clear all flags for a profile
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Action to clear flags for a profile
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class ClearflagAction extends ProfileFormAction
-{
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- if (!parent::prepare($args)) {
- return false;
- }
-
- $user = common_current_user();
-
- assert(!empty($user)); // checked above
- assert(!empty($this->profile)); // checked above
-
- return true;
- }
-
- /**
- * Handle request
- *
- * Overriding the base Action's handle() here to deal check
- * for Ajax and return an HXR response if necessary
- *
- * @param array $args $_REQUEST args; handled in prepare()
- *
- * @return void
- */
- function handle($args)
- {
- if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- $this->handlePost();
- if (!$this->boolean('ajax')) {
- $this->returnToPrevious();
- }
- }
- }
-
- /**
- * Handle POST
- *
- * Executes the actions; deletes all flags
- *
- * @return void
- */
- function handlePost()
- {
- $ufp = new User_flag_profile();
-
- $result = $ufp->query('UPDATE user_flag_profile ' .
- 'SET cleared = now() ' .
- 'WHERE cleared is null ' .
- 'AND profile_id = ' . $this->profile->id);
-
- if ($result == false) {
- // TRANS: Server exception given when flags could not be cleared.
- // TRANS: %s is a profile nickname.
- $msg = sprintf(_m('Could not clear flags for profile "%s".'),
- $this->profile->nickname);
- throw new ServerException($msg);
- }
-
- $ufp->free();
-
- if ($this->boolean('ajax')) {
- $this->ajaxResults();
- }
- }
-
- /**
- * Return results in ajax form
- *
- * @return void
- */
- function ajaxResults()
- {
- header('Content-Type: text/xml;charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: Title for AJAX form to indicated that flags were removed.
- $this->element('title', null, _m('Flags cleared'));
- $this->elementEnd('head');
- $this->elementStart('body');
- // TRANS: Body element for "flags cleared" form.
- $this->element('p', 'cleared', _m('Cleared'));
- $this->elementEnd('body');
- $this->elementEnd('html');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for clearing profile flags
- *
- * 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 Form
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/form.php';
-
-/**
- * Form for clearing profile flags
- *
- * @category Form
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class ClearFlagForm extends ProfileActionForm
-{
- /**
- * class of the form
- * Action this form provides
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_user_clearflag';
- }
-
- /**
- * Action this form provides
- *
- * @return string Name of the action, lowercased.
- */
- function target()
- {
- return 'clearflag';
- }
-
- /**
- * Title of the form
- *
- * @return string Title of the form, internationalized
- */
- function title()
- {
- // TRANS: Form title for action on a profile.
- return _m('Clear');
- }
-
- /**
- * Description of the form
- *
- * @return string description of the form, internationalized
- */
-
- function description()
- {
- // TRANS: Form description for clearing flags from a profile.
- return _m('Clear all flags');
- }
-}
+++ /dev/null
-<?php
-/**
- * Add a flag to a profile
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-/**
- * Action to flag a profile.
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- */
-class FlagprofileAction extends ProfileFormAction
-{
- /**
- * Take arguments for running
- *
- * @param array $args $_REQUEST args
- *
- * @return boolean success flag
- */
- function prepare($args)
- {
- if (!parent::prepare($args)) {
- return false;
- }
-
- $user = common_current_user();
-
- assert(!empty($user)); // checked above
- assert(!empty($this->profile)); // checked above
-
- return true;
- }
-
- /**
- * Handle request
- *
- * Overriding the base Action's handle() here to deal check
- * for Ajax and return an HXR response if necessary
- *
- * @param array $args $_REQUEST args; handled in prepare()
- *
- * @return void
- */
- function handle($args)
- {
- if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- $this->handlePost();
- if (!$this->boolean('ajax')) {
- $this->returnToPrevious();
- }
- }
- }
-
- /**
- * Handle POST
- *
- * @return void
- */
- function handlePost()
- {
- $user = common_current_user();
-
- assert(!empty($user));
- assert(!empty($this->profile));
-
- // throws an exception on error
-
- if (User_flag_profile::exists($this->profile->id,
- $user->id)) {
- // We'll return to the profile page (or return the updated AJAX form)
- // showing the current state, so no harm done.
- } else {
- User_flag_profile::create($user->id, $this->profile->id);
- }
-
- if ($this->boolean('ajax')) {
- $this->ajaxResults();
- }
- }
-
- /**
- * Return results as AJAX message
- *
- * @return void
- */
- function ajaxResults()
- {
- header('Content-Type: text/xml;charset=utf-8');
- $this->xw->startDocument('1.0', 'UTF-8');
- $this->elementStart('html');
- $this->elementStart('head');
- // TRANS: AJAX form title for a flagged profile.
- $this->element('title', null, _m('Flagged for review'));
- $this->elementEnd('head');
- $this->elementStart('body');
- // TRANS: Body text for AJAX form when a profile has been flagged for review.
- $this->element('p', 'flagged', _m('Flagged'));
- $this->elementEnd('body');
- $this->elementEnd('html');
- }
-}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Form for flagging a profile
- *
- * 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 Form
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/form.php';
-
-/**
- * Form for flagging a profile
- *
- * A form for flagging a profile
- *
- * @category Form
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-class FlagProfileForm extends ProfileActionForm
-{
- /**
- * class of the form
- * Action this form provides
- *
- * @return string class of the form
- */
- function formClass()
- {
- return 'form_entity_flag ajax';
- }
-
- /**
- * Action this form provides
- *
- * @return string Name of the action, lowercased.
- */
- function target()
- {
- return 'flagprofile';
- }
-
- /**
- * Title of the form
- *
- * @return string Title of the form, internationalized
- */
- function title()
- {
- // TRANS: Form title for flagging a profile for review.
- return _m('Flag');
- }
-
- /**
- * Description of the form
- *
- * @return string description of the form, internationalized
- */
- function description()
- {
- // TRANS: Form description.
- return _m('Flag profile for review.');
- }
-}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for clearing profile flags
+ *
+ * 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 Form
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/form.php';
+
+/**
+ * Form for clearing profile flags
+ *
+ * @category Form
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class ClearFlagForm extends ProfileActionForm
+{
+ /**
+ * class of the form
+ * Action this form provides
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_user_clearflag';
+ }
+
+ /**
+ * Action this form provides
+ *
+ * @return string Name of the action, lowercased.
+ */
+ function target()
+ {
+ return 'clearflag';
+ }
+
+ /**
+ * Title of the form
+ *
+ * @return string Title of the form, internationalized
+ */
+ function title()
+ {
+ // TRANS: Form title for action on a profile.
+ return _m('Clear');
+ }
+
+ /**
+ * Description of the form
+ *
+ * @return string description of the form, internationalized
+ */
+
+ function description()
+ {
+ // TRANS: Form description for clearing flags from a profile.
+ return _m('Clear all flags');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Form for flagging a profile
+ *
+ * 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 Form
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/form.php';
+
+/**
+ * Form for flagging a profile
+ *
+ * A form for flagging a profile
+ *
+ * @category Form
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+class FlagProfileForm extends ProfileActionForm
+{
+ /**
+ * class of the form
+ * Action this form provides
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_entity_flag ajax';
+ }
+
+ /**
+ * Action this form provides
+ *
+ * @return string Name of the action, lowercased.
+ */
+ function target()
+ {
+ return 'flagprofile';
+ }
+
+ /**
+ * Title of the form
+ *
+ * @return string Title of the form, internationalized
+ */
+ function title()
+ {
+ // TRANS: Form title for flagging a profile for review.
+ return _m('Flag');
+ }
+
+ /**
+ * Description of the form
+ *
+ * @return string description of the form, internationalized
+ */
+ function description()
+ {
+ // TRANS: Form description.
+ return _m('Flag profile for review.');
+ }
+}
+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Queue-mediated proxy class for outgoing XMPP messages.
- *
- * 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 Network
- * @package StatusNet
- * @author Brion Vibber <brion@status.net>
- * @copyright 2010 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-class Queued_XMPP extends XMPPHP_XMPP
-{
- /**
- * Reference to the XmppPlugin object we're hooked up to.
- */
- public $plugin;
-
- /**
- * Constructor
- *
- * @param XmppPlugin $plugin
- * @param string $host
- * @param integer $port
- * @param string $user
- * @param string $password
- * @param string $resource
- * @param string $server
- * @param boolean $printlog
- * @param string $loglevel
- */
- public function __construct($plugin, $host, $port, $user, $password, $resource, $server = null, $printlog = false, $loglevel = null)
- {
- $this->plugin = $plugin;
-
- parent::__construct($host, $port, $user, $password, $resource, $server, $printlog, $loglevel);
-
- // We use $host to connect, but $server to build JIDs if specified.
- // This seems to fix an upstream bug where $host was used to build
- // $this->basejid, never seen since it isn't actually used in the base
- // classes.
- if (!$server) {
- $server = $this->host;
- }
- $this->basejid = $this->user . '@' . $server;
-
- // Normally the fulljid is filled out by the server at resource binding
- // time, but we need to do it since we're not talking to a real server.
- $this->fulljid = "{$this->basejid}/{$this->resource}";
- }
-
- /**
- * Send a formatted message to the outgoing queue for later forwarding
- * to a real XMPP connection.
- *
- * @param string $msg
- */
- public function send($msg, $timeout=NULL)
- {
- $this->plugin->enqueueOutgoingRaw($msg);
- }
-
- //@{
- /**
- * Stream i/o functions disabled; only do output
- */
- public function connect($timeout = 30, $persistent = false, $sendinit = true)
- {
- // No i18n needed. Test message.
- throw new Exception('Cannot connect to server from fake XMPP.');
- }
-
- public function disconnect()
- {
- // No i18n needed. Test message.
- throw new Exception('Cannot connect to server from fake XMPP.');
- }
-
- public function process()
- {
- // No i18n needed. Test message.
- throw new Exception('Cannot read stream from fake XMPP.');
- }
-
- public function processUntil($event, $timeout=-1)
- {
- // No i18n needed. Test message.
- throw new Exception('Cannot read stream from fake XMPP.');
- }
-
- public function read()
- {
- // No i18n needed. Test message.
- throw new Exception('Cannot read stream from fake XMPP.');
- }
-
- public function readyToProcess()
- {
- // No i18n needed. Test message.
- throw new Exception('Cannot read stream from fake XMPP.');
- }
- //@}
-}
+++ /dev/null
-<?php
-/**
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2009, StatusNet, Inc.
- *
- * Send and receive notices using the Jabber network
- *
- * PHP version 5
- *
- * 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 Jabber
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
- * @link http://status.net/
- */
-
-if (!defined('STATUSNET')) {
- // This check helps protect against security problems;
- // your code file can't be executed directly from the web.
- exit(1);
-}
-
-class Sharing_XMPP extends XMPPHP_XMPP
-{
- function getSocket()
- {
- return $this->socket;
- }
-}
case 'XMPPHP_XMPP':
require_once $dir . '/extlib/XMPPHP/XMPP.php';
return false;
- case 'Sharing_XMPP':
- case 'Queued_XMPP':
- require_once $dir . '/'.$cls.'.php';
- return false;
- case 'XmppManager':
- require_once $dir . '/'.strtolower($cls).'.php';
- return false;
- default:
- return true;
}
+
+ return parent::onAutoload($cls);
}
function onStartImDaemonIoManagers(&$classes)
--- /dev/null
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Queue-mediated proxy class for outgoing XMPP messages.
+ *
+ * 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 Network
+ * @package StatusNet
+ * @author Brion Vibber <brion@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class Queued_XMPP extends XMPPHP_XMPP
+{
+ /**
+ * Reference to the XmppPlugin object we're hooked up to.
+ */
+ public $plugin;
+
+ /**
+ * Constructor
+ *
+ * @param XmppPlugin $plugin
+ * @param string $host
+ * @param integer $port
+ * @param string $user
+ * @param string $password
+ * @param string $resource
+ * @param string $server
+ * @param boolean $printlog
+ * @param string $loglevel
+ */
+ public function __construct($plugin, $host, $port, $user, $password, $resource, $server = null, $printlog = false, $loglevel = null)
+ {
+ $this->plugin = $plugin;
+
+ parent::__construct($host, $port, $user, $password, $resource, $server, $printlog, $loglevel);
+
+ // We use $host to connect, but $server to build JIDs if specified.
+ // This seems to fix an upstream bug where $host was used to build
+ // $this->basejid, never seen since it isn't actually used in the base
+ // classes.
+ if (!$server) {
+ $server = $this->host;
+ }
+ $this->basejid = $this->user . '@' . $server;
+
+ // Normally the fulljid is filled out by the server at resource binding
+ // time, but we need to do it since we're not talking to a real server.
+ $this->fulljid = "{$this->basejid}/{$this->resource}";
+ }
+
+ /**
+ * Send a formatted message to the outgoing queue for later forwarding
+ * to a real XMPP connection.
+ *
+ * @param string $msg
+ */
+ public function send($msg, $timeout=NULL)
+ {
+ $this->plugin->enqueueOutgoingRaw($msg);
+ }
+
+ //@{
+ /**
+ * Stream i/o functions disabled; only do output
+ */
+ public function connect($timeout = 30, $persistent = false, $sendinit = true)
+ {
+ // No i18n needed. Test message.
+ throw new Exception('Cannot connect to server from fake XMPP.');
+ }
+
+ public function disconnect()
+ {
+ // No i18n needed. Test message.
+ throw new Exception('Cannot connect to server from fake XMPP.');
+ }
+
+ public function process()
+ {
+ // No i18n needed. Test message.
+ throw new Exception('Cannot read stream from fake XMPP.');
+ }
+
+ public function processUntil($event, $timeout=-1)
+ {
+ // No i18n needed. Test message.
+ throw new Exception('Cannot read stream from fake XMPP.');
+ }
+
+ public function read()
+ {
+ // No i18n needed. Test message.
+ throw new Exception('Cannot read stream from fake XMPP.');
+ }
+
+ public function readyToProcess()
+ {
+ // No i18n needed. Test message.
+ throw new Exception('Cannot read stream from fake XMPP.');
+ }
+ //@}
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * Send and receive notices using the Jabber network
+ *
+ * PHP version 5
+ *
+ * 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 Jabber
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+class Sharing_XMPP extends XMPPHP_XMPP
+{
+ function getSocket()
+ {
+ return $this->socket;
+ }
+}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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/>.
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+/**
+ * XMPP background connection manager for XMPP-using queue handlers,
+ * allowing them to send outgoing messages on the right connection.
+ *
+ * Input is handled during socket select loop, keepalive pings during idle.
+ * Any incoming messages will be handled.
+ *
+ * In a multi-site queuedaemon.php run, one connection will be instantiated
+ * for each site being handled by the current process that has XMPP enabled.
+ */
+class XmppManager extends ImManager
+{
+ protected $lastping = null;
+ protected $pingid = null;
+
+ public $conn = null;
+
+ const PING_INTERVAL = 120;
+
+ /**
+ * Initialize connection to server.
+ * @return boolean true on success
+ */
+ public function start($master)
+ {
+ if(parent::start($master))
+ {
+ $this->connect();
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+ function send_raw_message($data)
+ {
+ $this->connect();
+ if (!$this->conn || $this->conn->isDisconnected()) {
+ return false;
+ }
+ $this->conn->send($data);
+ return true;
+ }
+
+ /**
+ * Message pump is triggered on socket input, so we only need an idle()
+ * call often enough to trigger our outgoing pings.
+ */
+ function timeout()
+ {
+ return self::PING_INTERVAL;
+ }
+
+ /**
+ * Process XMPP events that have come in over the wire.
+ * @fixme may kill process on XMPP error
+ * @param resource $socket
+ */
+ public function handleInput($socket)
+ {
+ // Process the queue for as long as needed
+ try {
+ common_log(LOG_DEBUG, "Servicing the XMPP queue.");
+ $this->stats('xmpp_process');
+ $this->conn->processTime(0);
+ } catch (XMPPHP_Exception $e) {
+ common_log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
+ die($e->getMessage());
+ }
+ }
+
+ /**
+ * Lists the IM connection socket to allow i/o master to wake
+ * when input comes in here as well as from the queue source.
+ *
+ * @return array of resources
+ */
+ public function getSockets()
+ {
+ $this->connect();
+ if($this->conn){
+ return array($this->conn->getSocket());
+ }else{
+ return array();
+ }
+ }
+
+ /**
+ * Idle processing for io manager's execution loop.
+ * Send keepalive pings to server.
+ *
+ * Side effect: kills process on exception from XMPP library.
+ *
+ * @todo FIXME: non-dying error handling
+ */
+ public function idle($timeout=0)
+ {
+ $now = time();
+ if (empty($this->lastping) || $now - $this->lastping > self::PING_INTERVAL) {
+ try {
+ $this->send_ping();
+ } catch (XMPPHP_Exception $e) {
+ common_log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
+ die($e->getMessage());
+ }
+ }
+ }
+
+ function connect()
+ {
+ if (!$this->conn || $this->conn->isDisconnected()) {
+ $resource = 'queue' . posix_getpid();
+ $this->conn = new Sharing_XMPP($this->plugin->host ?
+ $this->plugin->host :
+ $this->plugin->server,
+ $this->plugin->port,
+ $this->plugin->user,
+ $this->plugin->password,
+ $this->plugin->resource,
+ $this->plugin->server,
+ $this->plugin->debug ?
+ true : false,
+ $this->plugin->debug ?
+ XMPPHP_Log::LEVEL_VERBOSE : null
+ );
+
+ if (!$this->conn) {
+ return false;
+ }
+ $this->conn->addEventHandler('message', 'handle_xmpp_message', $this);
+ $this->conn->addEventHandler('reconnect', 'handle_xmpp_reconnect', $this);
+ $this->conn->setReconnectTimeout(600);
+
+ $this->conn->autoSubscribe();
+ $this->conn->useEncryption($this->plugin->encryption);
+
+ try {
+ $this->conn->connect(true); // true = persistent connection
+ } catch (XMPPHP_Exception $e) {
+ common_log(LOG_ERR, $e->getMessage());
+ return false;
+ }
+
+ $this->conn->processUntil('session_start');
+ // TRANS: Presence announcement for XMPP.
+ $this->send_presence(_m('Send me a message to post a notice'), 'available', null, 'available', 100);
+ }
+ return $this->conn;
+ }
+
+ function send_ping()
+ {
+ $this->connect();
+ if (!$this->conn || $this->conn->isDisconnected()) {
+ return false;
+ }
+ $now = time();
+ if (!isset($this->pingid)) {
+ $this->pingid = 0;
+ } else {
+ $this->pingid++;
+ }
+
+ common_log(LOG_DEBUG, "Sending ping #{$this->pingid}");
+ $this->conn->send("<iq from='{" . $this->plugin->daemonScreenname() . "}' to='{$this->plugin->server}' id='ping_{$this->pingid}' type='get'><ping xmlns='urn:xmpp:ping'/></iq>");
+ $this->lastping = $now;
+ return true;
+ }
+
+ function handle_xmpp_message(&$pl)
+ {
+ $this->plugin->enqueueIncomingRaw($pl);
+ return true;
+ }
+
+ /**
+ * Callback for Jabber reconnect event
+ * @param $pl
+ */
+ function handle_xmpp_reconnect(&$pl)
+ {
+ common_log(LOG_NOTICE, 'XMPP reconnected');
+
+ $this->conn->processUntil('session_start');
+ // TRANS: Message for XMPP reconnect.
+ $this->send_presence(_m('Send me a message to post a notice'), 'available', null, 'available', 100);
+ }
+
+ /**
+ * sends a presence stanza on the XMPP network
+ *
+ * @param string $status current status, free-form string
+ * @param string $show structured status value
+ * @param string $to recipient of presence, null for general
+ * @param string $type type of status message, related to $show
+ * @param int $priority priority of the presence
+ *
+ * @return boolean success value
+ */
+
+ function send_presence($status, $show='available', $to=null,
+ $type = 'available', $priority=null)
+ {
+ $this->connect();
+ if (!$this->conn || $this->conn->isDisconnected()) {
+ return false;
+ }
+ $this->conn->presence($status, $show, $to, $type, $priority);
+ return true;
+ }
+
+ /**
+ * sends a "special" presence stanza on the XMPP network
+ *
+ * @param string $type Type of presence
+ * @param string $to JID to send presence to
+ * @param string $show show value for presence
+ * @param string $status status value for presence
+ *
+ * @return boolean success flag
+ *
+ * @see send_presence()
+ */
+
+ function special_presence($type, $to=null, $show=null, $status=null)
+ {
+ // @todo FIXME: why use this instead of send_presence()?
+ $this->connect();
+ if (!$this->conn || $this->conn->isDisconnected()) {
+ return false;
+ }
+
+ $to = htmlspecialchars($to);
+ $status = htmlspecialchars($status);
+
+ $out = "<presence";
+ if ($to) {
+ $out .= " to='$to'";
+ }
+ if ($type) {
+ $out .= " type='$type'";
+ }
+ if ($show == 'available' and !$status) {
+ $out .= "/>";
+ } else {
+ $out .= ">";
+ if ($show && ($show != 'available')) {
+ $out .= "<show>$show</show>";
+ }
+ if ($status) {
+ $out .= "<status>$status</status>";
+ }
+ $out .= "</presence>";
+ }
+ $this->conn->send($out);
+ return true;
+ }
+}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * 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/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-/**
- * XMPP background connection manager for XMPP-using queue handlers,
- * allowing them to send outgoing messages on the right connection.
- *
- * Input is handled during socket select loop, keepalive pings during idle.
- * Any incoming messages will be handled.
- *
- * In a multi-site queuedaemon.php run, one connection will be instantiated
- * for each site being handled by the current process that has XMPP enabled.
- */
-class XmppManager extends ImManager
-{
- protected $lastping = null;
- protected $pingid = null;
-
- public $conn = null;
-
- const PING_INTERVAL = 120;
-
- /**
- * Initialize connection to server.
- * @return boolean true on success
- */
- public function start($master)
- {
- if(parent::start($master))
- {
- $this->connect();
- return true;
- }else{
- return false;
- }
- }
-
- function send_raw_message($data)
- {
- $this->connect();
- if (!$this->conn || $this->conn->isDisconnected()) {
- return false;
- }
- $this->conn->send($data);
- return true;
- }
-
- /**
- * Message pump is triggered on socket input, so we only need an idle()
- * call often enough to trigger our outgoing pings.
- */
- function timeout()
- {
- return self::PING_INTERVAL;
- }
-
- /**
- * Process XMPP events that have come in over the wire.
- * @fixme may kill process on XMPP error
- * @param resource $socket
- */
- public function handleInput($socket)
- {
- // Process the queue for as long as needed
- try {
- common_log(LOG_DEBUG, "Servicing the XMPP queue.");
- $this->stats('xmpp_process');
- $this->conn->processTime(0);
- } catch (XMPPHP_Exception $e) {
- common_log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
- die($e->getMessage());
- }
- }
-
- /**
- * Lists the IM connection socket to allow i/o master to wake
- * when input comes in here as well as from the queue source.
- *
- * @return array of resources
- */
- public function getSockets()
- {
- $this->connect();
- if($this->conn){
- return array($this->conn->getSocket());
- }else{
- return array();
- }
- }
-
- /**
- * Idle processing for io manager's execution loop.
- * Send keepalive pings to server.
- *
- * Side effect: kills process on exception from XMPP library.
- *
- * @todo FIXME: non-dying error handling
- */
- public function idle($timeout=0)
- {
- $now = time();
- if (empty($this->lastping) || $now - $this->lastping > self::PING_INTERVAL) {
- try {
- $this->send_ping();
- } catch (XMPPHP_Exception $e) {
- common_log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
- die($e->getMessage());
- }
- }
- }
-
- function connect()
- {
- if (!$this->conn || $this->conn->isDisconnected()) {
- $resource = 'queue' . posix_getpid();
- $this->conn = new Sharing_XMPP($this->plugin->host ?
- $this->plugin->host :
- $this->plugin->server,
- $this->plugin->port,
- $this->plugin->user,
- $this->plugin->password,
- $this->plugin->resource,
- $this->plugin->server,
- $this->plugin->debug ?
- true : false,
- $this->plugin->debug ?
- XMPPHP_Log::LEVEL_VERBOSE : null
- );
-
- if (!$this->conn) {
- return false;
- }
- $this->conn->addEventHandler('message', 'handle_xmpp_message', $this);
- $this->conn->addEventHandler('reconnect', 'handle_xmpp_reconnect', $this);
- $this->conn->setReconnectTimeout(600);
-
- $this->conn->autoSubscribe();
- $this->conn->useEncryption($this->plugin->encryption);
-
- try {
- $this->conn->connect(true); // true = persistent connection
- } catch (XMPPHP_Exception $e) {
- common_log(LOG_ERR, $e->getMessage());
- return false;
- }
-
- $this->conn->processUntil('session_start');
- // TRANS: Presence announcement for XMPP.
- $this->send_presence(_m('Send me a message to post a notice'), 'available', null, 'available', 100);
- }
- return $this->conn;
- }
-
- function send_ping()
- {
- $this->connect();
- if (!$this->conn || $this->conn->isDisconnected()) {
- return false;
- }
- $now = time();
- if (!isset($this->pingid)) {
- $this->pingid = 0;
- } else {
- $this->pingid++;
- }
-
- common_log(LOG_DEBUG, "Sending ping #{$this->pingid}");
- $this->conn->send("<iq from='{" . $this->plugin->daemonScreenname() . "}' to='{$this->plugin->server}' id='ping_{$this->pingid}' type='get'><ping xmlns='urn:xmpp:ping'/></iq>");
- $this->lastping = $now;
- return true;
- }
-
- function handle_xmpp_message(&$pl)
- {
- $this->plugin->enqueueIncomingRaw($pl);
- return true;
- }
-
- /**
- * Callback for Jabber reconnect event
- * @param $pl
- */
- function handle_xmpp_reconnect(&$pl)
- {
- common_log(LOG_NOTICE, 'XMPP reconnected');
-
- $this->conn->processUntil('session_start');
- // TRANS: Message for XMPP reconnect.
- $this->send_presence(_m('Send me a message to post a notice'), 'available', null, 'available', 100);
- }
-
- /**
- * sends a presence stanza on the XMPP network
- *
- * @param string $status current status, free-form string
- * @param string $show structured status value
- * @param string $to recipient of presence, null for general
- * @param string $type type of status message, related to $show
- * @param int $priority priority of the presence
- *
- * @return boolean success value
- */
-
- function send_presence($status, $show='available', $to=null,
- $type = 'available', $priority=null)
- {
- $this->connect();
- if (!$this->conn || $this->conn->isDisconnected()) {
- return false;
- }
- $this->conn->presence($status, $show, $to, $type, $priority);
- return true;
- }
-
- /**
- * sends a "special" presence stanza on the XMPP network
- *
- * @param string $type Type of presence
- * @param string $to JID to send presence to
- * @param string $show show value for presence
- * @param string $status status value for presence
- *
- * @return boolean success flag
- *
- * @see send_presence()
- */
-
- function special_presence($type, $to=null, $show=null, $status=null)
- {
- // @todo FIXME: why use this instead of send_presence()?
- $this->connect();
- if (!$this->conn || $this->conn->isDisconnected()) {
- return false;
- }
-
- $to = htmlspecialchars($to);
- $status = htmlspecialchars($status);
-
- $out = "<presence";
- if ($to) {
- $out .= " to='$to'";
- }
- if ($type) {
- $out .= " type='$type'";
- }
- if ($show == 'available' and !$status) {
- $out .= "/>";
- } else {
- $out .= ">";
- if ($show && ($show != 'available')) {
- $out .= "<show>$show</show>";
- }
- if ($status) {
- $out .= "<status>$status</status>";
- }
- $out .= "</presence>";
- }
- $this->conn->send($out);
- return true;
- }
-}
return true;
}
-
- /**
- * Automatically load the actions and libraries used by the plugin
- *
- * @param Class $cls the class
- *
- * @return boolean hook return
- *
- */
- function onAutoload($cls)
- {
- $base = dirname(__FILE__);
- $lower = strtolower($cls);
- switch ($lower) {
- case 'sn_yammerclient':
- case 'yammerimporter':
- case 'yammerrunner':
- case 'yammerapikeyform':
- case 'yammerauthinitform':
- case 'yammerauthverifyform':
- case 'yammerprogressform':
- case 'yammerqueuehandler':
- require_once "$base/lib/$lower.php";
- return false;
- case 'yammeradminpanelaction':
- $crop = substr($lower, 0, strlen($lower) - strlen('action'));
- require_once "$base/actions/$crop.php";
- return false;
- case 'yammer_state':
- case 'yammer_notice_stub':
- case 'yammer_common':
- case 'yammer_user':
- case 'yammer_group':
- case 'yammer_notice':
- require_once "$base/classes/$cls.php";
- return false;
- default:
- return true;
- }
- }
}
--- /dev/null
+<?php
+
+class YammerApikeyForm extends Form
+{
+ private $runner;
+
+ function __construct($out)
+ {
+ parent::__construct($out);
+ $this->runner = $runner;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'yammer-apikey-form';
+ }
+
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+
+ function formClass()
+ {
+ return 'form_yammer_apikey form_settings';
+ }
+
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('yammeradminpanel');
+ }
+
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend for adding details to connect to a remote Yammer API.
+ $this->out->element('legend', null, _m('Yammer API registration'));
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->out->hidden('subaction', 'apikey');
+
+ $this->out->elementStart('fieldset');
+
+ $this->out->elementStart('p');
+ // TRANS: Explanation of what needs to be done to connect to a Yammer network.
+ $this->out->text(_m('Before we can connect to your Yammer network, ' .
+ 'you will need to register the importer as an ' .
+ 'application authorized to pull data on your behalf. ' .
+ 'This registration will work only for your own network. ' .
+ 'Follow this link to register the app at Yammer; ' .
+ 'you will be prompted to log in if necessary:'));
+ $this->out->elementEnd('p');
+
+ $this->out->elementStart('p', array('class' => 'magiclink'));
+ $this->out->element('a',
+ array('href' => 'https://www.yammer.com/client_applications/new',
+ 'target' => '_blank'),
+ // TRANS: Link description to a Yammer application registration form.
+ _m('Open Yammer application registration form'));
+ $this->out->elementEnd('p');
+
+ // TRANS: Instructions.
+ $this->out->element('p', array(), _m('Copy the consumer key and secret you are given into the form below:'));
+
+ $this->out->elementStart('ul', array('class' => 'form_data'));
+ $this->out->elementStart('li');
+ // TRANS: Field label for a Yammer consumer key.
+ $this->out->input('consumer_key', _m('Consumer key:'), common_config('yammer', 'consumer_key'));
+ $this->out->elementEnd('li');
+ $this->out->elementStart('li');
+ // TRANS: Field label for a Yammer consumer secret.
+ $this->out->input('consumer_secret', _m('Consumer secret:'), common_config('yammer', 'consumer_secret'));
+ $this->out->elementEnd('li');
+ $this->out->elementEnd('ul');
+
+ // TRANS: Button text for saving a Yammer API registration.
+ $this->out->submit('submit', _m('BUTTON','Save'),
+ // TRANS: Button title for saving a Yammer API registration.
+ 'submit', null, _m('Save the entered consumer key and consumer secret.'));
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ }
+}
--- /dev/null
+<?php
+
+class YammerAuthInitForm extends Form
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'yammer-auth-init-form';
+ }
+
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+
+ function formClass()
+ {
+ return 'form_yammer_auth_init form_settings';
+ }
+
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('yammeradminpanel');
+ }
+
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend.
+ $this->out->element('legend', null, _m('Connect to Yammer'));
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->out->hidden('subaction', 'authinit');
+
+ $this->out->elementStart('fieldset');
+ // TRANS: Button text for starting Yammer authentication.
+ $this->out->submit('submit', _m('BUTTON','Start authentication'),
+ // TRANS: Button title for starting Yammer authentication.
+ 'submit', null, _m('Request authorization to connect to a Yammer account.'));
+ // TRANS: Button text for starting changing a Yammer API key.
+ $this->out->submit('change-apikey', _m('BUTTON','Change API key'));
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ }
+}
--- /dev/null
+<?php
+
+class YammerAuthVerifyForm extends Form
+{
+ private $runner;
+
+ function __construct($out, YammerRunner $runner)
+ {
+ parent::__construct($out);
+ $this->runner = $runner;
+ }
+
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+
+ function id()
+ {
+ return 'yammer-auth-verify-form';
+ }
+
+
+ /**
+ * class of the form
+ *
+ * @return string of the form class
+ */
+
+ function formClass()
+ {
+ return 'form_yammer_auth_verify form_settings';
+ }
+
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+
+ function action()
+ {
+ return common_local_url('yammeradminpanel');
+ }
+
+
+ /**
+ * Legend of the Form
+ *
+ * @return void
+ */
+ function formLegend()
+ {
+ // TRANS: Form legend.
+ $this->out->element('legend', null, _m('Connect to Yammer'));
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+
+ function formData()
+ {
+ $this->out->hidden('subaction', 'authverify');
+
+ $this->out->elementStart('fieldset');
+
+ $this->out->elementStart('p');
+ // TRANS: Form instructions.
+ $this->out->text(_m('Follow this link to confirm authorization at Yammer; you will be prompted to log in if necessary:'));
+ $this->out->elementEnd('p');
+
+ // iframe would be nice to avoid leaving -- since they don't seem to have callback url O_O
+ /*
+ $this->out->element('iframe', array('id' => 'yammer-oauth',
+ 'src' => $this->runner->getAuthUrl()));
+ */
+ // yeah, it ignores the callback_url
+ // soo... crappy link. :(
+
+ $this->out->elementStart('p', array('class' => 'magiclink'));
+ $this->out->element('a',
+ array('href' => $this->runner->getAuthUrl(),
+ 'target' => '_blank'),
+ // TRANS: Link description for a link in an external Yammer system.
+ _m('Open Yammer authentication window'));
+ $this->out->elementEnd('p');
+
+ // TRANS: Form instructions.
+ $this->out->element('p', array(), _m('Copy the verification code you are given below:'));
+
+ $this->out->elementStart('ul', array('class' => 'form_data'));
+ $this->out->elementStart('li');
+ // TRANS: Field label.
+ $this->out->input('verify_token', _m('Verification code:'));
+ $this->out->elementEnd('li');
+ $this->out->elementEnd('ul');
+
+ // TRANS: Button text for saving Yammer authorisation data and starting Yammer import.
+ $this->out->submit('submit', _m('BUTTON','Continue'),
+ // TRANS: Button title for saving Yammer authorisation data and starting Yammer import.
+ 'submit', null, _m('Save the verification code and begin import.'));
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ }
+}
--- /dev/null
+<?php
+
+class YammerProgressForm extends Form
+{
+ /**
+ * ID of the form
+ *
+ * @return string ID of the form
+ */
+ function id()
+ {
+ return 'yammer-progress-form';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ $classes = array('form_settings');
+ $runner = YammerRunner::init();
+ if ($runner->lastError()) {
+ $classes[] = 'import-error';
+ } else if ($runner->state() == 'done') {
+ $classes[] = 'import-done';
+ } else {
+ $classes[] = 'import-progress';
+ }
+ return implode(' ', $classes);
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('yammeradminpanel');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->hidden('subaction', 'progress');
+
+ $runner = YammerRunner::init();
+
+ $error = $runner->lastError();
+ $userCount = $runner->countUsers();
+ $groupCount = $runner->countGroups();
+ $fetchedCount = $runner->countFetchedNotices();
+ $savedCount = $runner->countSavedNotices();
+
+ $labels = array(
+ 'init' => array(
+ // TRANS: Field label for a Yammer import initialise step.
+ 'label' => _m('Initialize'),
+ // TRANS: "In progress" description.
+ 'progress' => _m('No import running'),
+ // TRANS: "Complete" description for initialize state.
+ 'complete' => _m('Initiated Yammer server connection...'),
+ ),
+ 'requesting-auth' => array(
+ // TRANS: Field label for a Yammer import connect step.
+ 'label' => _m('Connect to Yammer'),
+ // TRANS: "In progress" description.
+ 'progress' => _m('Awaiting authorization...'),
+ // TRANS: "Complete" description for connect state.
+ 'complete' => _m('Connected.'),
+ ),
+ 'import-users' => array(
+ // TRANS: Field label for a Yammer user import users step.
+ 'label' => _m('Import user accounts'),
+ // TRANS: "In progress" description.
+ // TRANS: %d is the number of users to be imported.
+ 'progress' => sprintf(_m('Importing %d user...',
+ 'Importing %d users...',
+ $userCount),
+ $userCount),
+ // TRANS: "Complete" description for step.
+ // TRANS: %d is the number of users imported.
+ 'complete' => sprintf(_m('Imported %d user.',
+ 'Imported %d users.',
+ $userCount),
+ $userCount),
+ ),
+ 'import-groups' => array(
+ // TRANS: Field label for a Yammer group import step.
+ 'label' => _m('Import user groups'),
+ // TRANS: "In progress" description.
+ // TRANS: %d is the number of groups to be imported.
+ 'progress' => sprintf(_m('Importing %d group...',
+ 'Importing %d groups...',
+ $groupCount),
+ $groupCount),
+ // TRANS: "Complete" description for step.
+ // TRANS: %d is the number of groups imported.
+ 'complete' => sprintf(_m('Imported %d group.',
+ 'Imported %d groups.',
+ $groupCount),
+ $groupCount),
+ ),
+ 'fetch-messages' => array(
+ // TRANS: Field label for a Yammer import prepare notices step.
+ 'label' => _m('Prepare public notices for import'),
+ // TRANS: "In progress" description.
+ // TRANS: %d is the number of notices to be prepared for import.
+ 'progress' => sprintf(_m('Preparing %d notice...',
+ 'Preparing %d notices...',
+ $fetchedCount),
+ $fetchedCount),
+ // TRANS: "Complete" description for step.
+ // TRANS: %d is the number of notices prepared for import.
+ 'complete' => sprintf(_m('Prepared %d notice.',
+ 'Prepared %d notices.',
+ $fetchedCount),
+ $fetchedCount),
+ ),
+ 'save-messages' => array(
+ // TRANS: Field label for a Yammer import notices step.
+ 'label' => _m('Import public notices'),
+ // TRANS: "In progress" description.
+ // TRANS: %d is the number of notices to be imported.
+ 'progress' => sprintf(_m('Importing %d notice...',
+ 'Importing %d notices...',
+ $savedCount),
+ $savedCount),
+ // TRANS: "Complete" description for step.
+ // TRANS: %d is the number of notices imported.
+ 'complete' => sprintf(_m('Imported %d notice.',
+ 'Imported %d notices.',
+ $savedCount),
+ $savedCount),
+ ),
+ 'done' => array(
+ // TRANS: Field label for a Yammer import done step.
+ 'label' => _m('Done'),
+ // TRANS: "In progress" description for done step.
+ 'progress' => sprintf(_m('Import is complete!')),
+ // TRANS: "Complete" description for done step.
+ 'complete' => sprintf(_m('Import is complete!')),
+ )
+ );
+ $steps = array_keys($labels);
+ $currentStep = array_search($runner->state(), $steps);
+
+ $classes = array('yammer-import');
+ if ($error) {
+ $classes[] = 'yammer-error';
+ } else {
+ $classes[] = 'yammer-running';
+ }
+ $this->out->elementStart('fieldset', array('class' => implode(' ', $classes)));
+ // TRANS: Fieldset legend.
+ $this->out->element('legend', array(), _m('Import status'));
+ foreach ($steps as $step => $state) {
+ if ($state == 'init') {
+ // Don't show 'init', it's boring.
+ continue;
+ }
+ if ($step < $currentStep) {
+ // This step is done
+ $this->progressBar($state,
+ 'complete',
+ $labels[$state]['label'],
+ $labels[$state]['complete']);
+ } else if ($step == $currentStep) {
+ // This step is in progress
+ $this->progressBar($state,
+ 'progress',
+ $labels[$state]['label'],
+ $labels[$state]['progress'],
+ $error);
+ } else {
+ // This step has not yet been done.
+ $this->progressBar($state,
+ 'waiting',
+ $labels[$state]['label'],
+ // TRANS: Progress bar status.
+ _m('Waiting...'));
+ }
+ }
+ $this->out->elementEnd('fieldset');
+ }
+
+ private function progressBar($state, $class, $label, $status, $error=null)
+ {
+ // @fixme prettify ;)
+ $this->out->elementStart('div', array('class' => "import-step import-step-$state $class"));
+ $this->out->element('div', array('class' => 'import-label'), $label);
+ $this->out->element('div', array('class' => 'import-status'), $status);
+ if ($class == 'progress') {
+ if ($state == 'done') {
+ // TRANS: Button text for resetting the import state.
+ $this->out->submit('abort-import', _m('Reset import state'));
+ } else {
+ if ($error) {
+ $this->errorBox($error);
+ } else {
+ // TRANS: Button text for pausing an import.
+ $this->out->submit('pause-import', _m('Pause import'));
+ }
+ }
+ }
+ $this->out->elementEnd('div');
+ }
+
+ private function errorBox($msg)
+ {
+ // TRANS: Error message. %s are the error details.
+ $errline = sprintf(_m('Encountered error "%s".'), $msg);
+ $this->out->elementStart('fieldset', array('class' => 'import-error'));
+ // TRANS: Fieldset legend for a paused import.
+ $this->out->element('legend', array(), _m('Paused'));
+ $this->out->element('p', array(), $errline);
+ // TRANS: Button text for continuing a paused import.
+ $this->out->submit('continue-import', _m('Continue'));
+ // TRANS: Button text for aborting a paused import.
+ $this->out->submit('abort-import', _m('Abort import'));
+ $this->out->elementEnd('fieldset');
+ }
+}
+++ /dev/null
-<?php
-
-class YammerApikeyForm extends Form
-{
- private $runner;
-
- function __construct($out)
- {
- parent::__construct($out);
- $this->runner = $runner;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
-
- function id()
- {
- return 'yammer-apikey-form';
- }
-
-
- /**
- * class of the form
- *
- * @return string of the form class
- */
-
- function formClass()
- {
- return 'form_yammer_apikey form_settings';
- }
-
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
-
- function action()
- {
- return common_local_url('yammeradminpanel');
- }
-
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend for adding details to connect to a remote Yammer API.
- $this->out->element('legend', null, _m('Yammer API registration'));
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
-
- function formData()
- {
- $this->out->hidden('subaction', 'apikey');
-
- $this->out->elementStart('fieldset');
-
- $this->out->elementStart('p');
- // TRANS: Explanation of what needs to be done to connect to a Yammer network.
- $this->out->text(_m('Before we can connect to your Yammer network, ' .
- 'you will need to register the importer as an ' .
- 'application authorized to pull data on your behalf. ' .
- 'This registration will work only for your own network. ' .
- 'Follow this link to register the app at Yammer; ' .
- 'you will be prompted to log in if necessary:'));
- $this->out->elementEnd('p');
-
- $this->out->elementStart('p', array('class' => 'magiclink'));
- $this->out->element('a',
- array('href' => 'https://www.yammer.com/client_applications/new',
- 'target' => '_blank'),
- // TRANS: Link description to a Yammer application registration form.
- _m('Open Yammer application registration form'));
- $this->out->elementEnd('p');
-
- // TRANS: Instructions.
- $this->out->element('p', array(), _m('Copy the consumer key and secret you are given into the form below:'));
-
- $this->out->elementStart('ul', array('class' => 'form_data'));
- $this->out->elementStart('li');
- // TRANS: Field label for a Yammer consumer key.
- $this->out->input('consumer_key', _m('Consumer key:'), common_config('yammer', 'consumer_key'));
- $this->out->elementEnd('li');
- $this->out->elementStart('li');
- // TRANS: Field label for a Yammer consumer secret.
- $this->out->input('consumer_secret', _m('Consumer secret:'), common_config('yammer', 'consumer_secret'));
- $this->out->elementEnd('li');
- $this->out->elementEnd('ul');
-
- // TRANS: Button text for saving a Yammer API registration.
- $this->out->submit('submit', _m('BUTTON','Save'),
- // TRANS: Button title for saving a Yammer API registration.
- 'submit', null, _m('Save the entered consumer key and consumer secret.'));
-
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
-
- function formActions()
- {
- }
-}
+++ /dev/null
-<?php
-
-class YammerAuthInitForm extends Form
-{
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
-
- function id()
- {
- return 'yammer-auth-init-form';
- }
-
-
- /**
- * class of the form
- *
- * @return string of the form class
- */
-
- function formClass()
- {
- return 'form_yammer_auth_init form_settings';
- }
-
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
-
- function action()
- {
- return common_local_url('yammeradminpanel');
- }
-
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend.
- $this->out->element('legend', null, _m('Connect to Yammer'));
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
-
- function formData()
- {
- $this->out->hidden('subaction', 'authinit');
-
- $this->out->elementStart('fieldset');
- // TRANS: Button text for starting Yammer authentication.
- $this->out->submit('submit', _m('BUTTON','Start authentication'),
- // TRANS: Button title for starting Yammer authentication.
- 'submit', null, _m('Request authorization to connect to a Yammer account.'));
- // TRANS: Button text for starting changing a Yammer API key.
- $this->out->submit('change-apikey', _m('BUTTON','Change API key'));
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
-
- function formActions()
- {
- }
-}
+++ /dev/null
-<?php
-
-class YammerAuthVerifyForm extends Form
-{
- private $runner;
-
- function __construct($out, YammerRunner $runner)
- {
- parent::__construct($out);
- $this->runner = $runner;
- }
-
- /**
- * ID of the form
- *
- * @return int ID of the form
- */
-
- function id()
- {
- return 'yammer-auth-verify-form';
- }
-
-
- /**
- * class of the form
- *
- * @return string of the form class
- */
-
- function formClass()
- {
- return 'form_yammer_auth_verify form_settings';
- }
-
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
-
- function action()
- {
- return common_local_url('yammeradminpanel');
- }
-
-
- /**
- * Legend of the Form
- *
- * @return void
- */
- function formLegend()
- {
- // TRANS: Form legend.
- $this->out->element('legend', null, _m('Connect to Yammer'));
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
-
- function formData()
- {
- $this->out->hidden('subaction', 'authverify');
-
- $this->out->elementStart('fieldset');
-
- $this->out->elementStart('p');
- // TRANS: Form instructions.
- $this->out->text(_m('Follow this link to confirm authorization at Yammer; you will be prompted to log in if necessary:'));
- $this->out->elementEnd('p');
-
- // iframe would be nice to avoid leaving -- since they don't seem to have callback url O_O
- /*
- $this->out->element('iframe', array('id' => 'yammer-oauth',
- 'src' => $this->runner->getAuthUrl()));
- */
- // yeah, it ignores the callback_url
- // soo... crappy link. :(
-
- $this->out->elementStart('p', array('class' => 'magiclink'));
- $this->out->element('a',
- array('href' => $this->runner->getAuthUrl(),
- 'target' => '_blank'),
- // TRANS: Link description for a link in an external Yammer system.
- _m('Open Yammer authentication window'));
- $this->out->elementEnd('p');
-
- // TRANS: Form instructions.
- $this->out->element('p', array(), _m('Copy the verification code you are given below:'));
-
- $this->out->elementStart('ul', array('class' => 'form_data'));
- $this->out->elementStart('li');
- // TRANS: Field label.
- $this->out->input('verify_token', _m('Verification code:'));
- $this->out->elementEnd('li');
- $this->out->elementEnd('ul');
-
- // TRANS: Button text for saving Yammer authorisation data and starting Yammer import.
- $this->out->submit('submit', _m('BUTTON','Continue'),
- // TRANS: Button title for saving Yammer authorisation data and starting Yammer import.
- 'submit', null, _m('Save the verification code and begin import.'));
- $this->out->elementEnd('fieldset');
- }
-
- /**
- * Action elements
- *
- * @return void
- */
-
- function formActions()
- {
- }
-}
+++ /dev/null
-<?php
-
-class YammerProgressForm extends Form
-{
- /**
- * ID of the form
- *
- * @return string ID of the form
- */
- function id()
- {
- return 'yammer-progress-form';
- }
-
- /**
- * class of the form
- *
- * @return string class of the form
- */
- function formClass()
- {
- $classes = array('form_settings');
- $runner = YammerRunner::init();
- if ($runner->lastError()) {
- $classes[] = 'import-error';
- } else if ($runner->state() == 'done') {
- $classes[] = 'import-done';
- } else {
- $classes[] = 'import-progress';
- }
- return implode(' ', $classes);
- }
-
- /**
- * Action of the form
- *
- * @return string URL of the action
- */
- function action()
- {
- return common_local_url('yammeradminpanel');
- }
-
- /**
- * Data elements of the form
- *
- * @return void
- */
- function formData()
- {
- $this->out->hidden('subaction', 'progress');
-
- $runner = YammerRunner::init();
-
- $error = $runner->lastError();
- $userCount = $runner->countUsers();
- $groupCount = $runner->countGroups();
- $fetchedCount = $runner->countFetchedNotices();
- $savedCount = $runner->countSavedNotices();
-
- $labels = array(
- 'init' => array(
- // TRANS: Field label for a Yammer import initialise step.
- 'label' => _m('Initialize'),
- // TRANS: "In progress" description.
- 'progress' => _m('No import running'),
- // TRANS: "Complete" description for initialize state.
- 'complete' => _m('Initiated Yammer server connection...'),
- ),
- 'requesting-auth' => array(
- // TRANS: Field label for a Yammer import connect step.
- 'label' => _m('Connect to Yammer'),
- // TRANS: "In progress" description.
- 'progress' => _m('Awaiting authorization...'),
- // TRANS: "Complete" description for connect state.
- 'complete' => _m('Connected.'),
- ),
- 'import-users' => array(
- // TRANS: Field label for a Yammer user import users step.
- 'label' => _m('Import user accounts'),
- // TRANS: "In progress" description.
- // TRANS: %d is the number of users to be imported.
- 'progress' => sprintf(_m('Importing %d user...',
- 'Importing %d users...',
- $userCount),
- $userCount),
- // TRANS: "Complete" description for step.
- // TRANS: %d is the number of users imported.
- 'complete' => sprintf(_m('Imported %d user.',
- 'Imported %d users.',
- $userCount),
- $userCount),
- ),
- 'import-groups' => array(
- // TRANS: Field label for a Yammer group import step.
- 'label' => _m('Import user groups'),
- // TRANS: "In progress" description.
- // TRANS: %d is the number of groups to be imported.
- 'progress' => sprintf(_m('Importing %d group...',
- 'Importing %d groups...',
- $groupCount),
- $groupCount),
- // TRANS: "Complete" description for step.
- // TRANS: %d is the number of groups imported.
- 'complete' => sprintf(_m('Imported %d group.',
- 'Imported %d groups.',
- $groupCount),
- $groupCount),
- ),
- 'fetch-messages' => array(
- // TRANS: Field label for a Yammer import prepare notices step.
- 'label' => _m('Prepare public notices for import'),
- // TRANS: "In progress" description.
- // TRANS: %d is the number of notices to be prepared for import.
- 'progress' => sprintf(_m('Preparing %d notice...',
- 'Preparing %d notices...',
- $fetchedCount),
- $fetchedCount),
- // TRANS: "Complete" description for step.
- // TRANS: %d is the number of notices prepared for import.
- 'complete' => sprintf(_m('Prepared %d notice.',
- 'Prepared %d notices.',
- $fetchedCount),
- $fetchedCount),
- ),
- 'save-messages' => array(
- // TRANS: Field label for a Yammer import notices step.
- 'label' => _m('Import public notices'),
- // TRANS: "In progress" description.
- // TRANS: %d is the number of notices to be imported.
- 'progress' => sprintf(_m('Importing %d notice...',
- 'Importing %d notices...',
- $savedCount),
- $savedCount),
- // TRANS: "Complete" description for step.
- // TRANS: %d is the number of notices imported.
- 'complete' => sprintf(_m('Imported %d notice.',
- 'Imported %d notices.',
- $savedCount),
- $savedCount),
- ),
- 'done' => array(
- // TRANS: Field label for a Yammer import done step.
- 'label' => _m('Done'),
- // TRANS: "In progress" description for done step.
- 'progress' => sprintf(_m('Import is complete!')),
- // TRANS: "Complete" description for done step.
- 'complete' => sprintf(_m('Import is complete!')),
- )
- );
- $steps = array_keys($labels);
- $currentStep = array_search($runner->state(), $steps);
-
- $classes = array('yammer-import');
- if ($error) {
- $classes[] = 'yammer-error';
- } else {
- $classes[] = 'yammer-running';
- }
- $this->out->elementStart('fieldset', array('class' => implode(' ', $classes)));
- // TRANS: Fieldset legend.
- $this->out->element('legend', array(), _m('Import status'));
- foreach ($steps as $step => $state) {
- if ($state == 'init') {
- // Don't show 'init', it's boring.
- continue;
- }
- if ($step < $currentStep) {
- // This step is done
- $this->progressBar($state,
- 'complete',
- $labels[$state]['label'],
- $labels[$state]['complete']);
- } else if ($step == $currentStep) {
- // This step is in progress
- $this->progressBar($state,
- 'progress',
- $labels[$state]['label'],
- $labels[$state]['progress'],
- $error);
- } else {
- // This step has not yet been done.
- $this->progressBar($state,
- 'waiting',
- $labels[$state]['label'],
- // TRANS: Progress bar status.
- _m('Waiting...'));
- }
- }
- $this->out->elementEnd('fieldset');
- }
-
- private function progressBar($state, $class, $label, $status, $error=null)
- {
- // @fixme prettify ;)
- $this->out->elementStart('div', array('class' => "import-step import-step-$state $class"));
- $this->out->element('div', array('class' => 'import-label'), $label);
- $this->out->element('div', array('class' => 'import-status'), $status);
- if ($class == 'progress') {
- if ($state == 'done') {
- // TRANS: Button text for resetting the import state.
- $this->out->submit('abort-import', _m('Reset import state'));
- } else {
- if ($error) {
- $this->errorBox($error);
- } else {
- // TRANS: Button text for pausing an import.
- $this->out->submit('pause-import', _m('Pause import'));
- }
- }
- }
- $this->out->elementEnd('div');
- }
-
- private function errorBox($msg)
- {
- // TRANS: Error message. %s are the error details.
- $errline = sprintf(_m('Encountered error "%s".'), $msg);
- $this->out->elementStart('fieldset', array('class' => 'import-error'));
- // TRANS: Fieldset legend for a paused import.
- $this->out->element('legend', array(), _m('Paused'));
- $this->out->element('p', array(), $errline);
- // TRANS: Button text for continuing a paused import.
- $this->out->submit('continue-import', _m('Continue'));
- // TRANS: Button text for aborting a paused import.
- $this->out->submit('abort-import', _m('Abort import'));
- $this->out->elementEnd('fieldset');
- }
-}