forked from GNUsocial/gnu-social
		
	Merge branch '0.9.x' into adminpanel
This commit is contained in:
		
							
								
								
									
										44
									
								
								EVENTS.txt
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								EVENTS.txt
									
									
									
									
									
								
							@@ -162,6 +162,42 @@ StartAccountSettingsNav: Before showing the account settings menu
 | 
			
		||||
EndAccountSettingsNav: After showing the account settings menu
 | 
			
		||||
- $action: the current action
 | 
			
		||||
 | 
			
		||||
StartAccountSettingsProfileMenuItem: Before showing the Profile menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
EndAccountSettingsProfileMenuItem: After showing the Profile menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
StartAccountSettingsAvatarMenuItem: Before showing the Avatar menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
EndAccountSettingsAvatarMenuItem: After showing the Avatar menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
StartAccountSettingsPasswordMenuItem: Before showing the Password menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
EndAccountSettingsPasswordMenuItem: After showing the Password menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
StartAccountSettingsEmailMenuItem: Before showing the Email menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
EndAccountSettingsEmailMenuItem: After showing the Email menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
StartAccountSettingsDesignMenuItem: Before showing the Design menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
EndAccountSettingsDesignMenuItem: After showing the Design menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
StartAccountSettingsOtherMenuItem: Before showing the Other menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
EndAccountSettingsOtherMenuItem: After showing the Other menu item
 | 
			
		||||
- $widget: AccountSettingsNav instance being shown
 | 
			
		||||
 | 
			
		||||
Autoload: When trying to autoload a class
 | 
			
		||||
- $cls: the class being sought. A plugin might require_once the file for the class.
 | 
			
		||||
 | 
			
		||||
@@ -491,15 +527,13 @@ EndCheckPassword: After checking a username/password pair
 | 
			
		||||
- $password: The password that was checked
 | 
			
		||||
- $authenticatedUser: User object if credentials match a user, else null.
 | 
			
		||||
 | 
			
		||||
ChangePassword: Handle a password change request
 | 
			
		||||
StartChangePassword: Before changing a password
 | 
			
		||||
- $nickname: user's nickname
 | 
			
		||||
- $oldpassword: the user's old password
 | 
			
		||||
- $newpassword: the desired new password
 | 
			
		||||
- &$errormsg: set this to an error message if the password could not be changed. If the password was changed, leave this as false
 | 
			
		||||
 | 
			
		||||
CanUserChangeField: Determines if a user is allowed to change a specific profile field
 | 
			
		||||
- $nickname: nickname of the user who would like to know which of their profile fields are mutable
 | 
			
		||||
- $field: name of the field the user wants to change (nickname, fullname, password, avatar, etc)
 | 
			
		||||
EndChangePassword: After changing a password
 | 
			
		||||
- $nickname: user's nickname
 | 
			
		||||
 | 
			
		||||
UserDeleteRelated: Specify additional tables to delete entries from when deleting users
 | 
			
		||||
- $user: User object
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								README
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								README
									
									
									
									
									
								
							@@ -389,20 +389,16 @@ the server first.
 | 
			
		||||
Sphinx
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
To use a Sphinx server to search users and notices, you also need
 | 
			
		||||
to install, compile and enable the sphinx pecl extension for php on the
 | 
			
		||||
client side, which itself depends on the sphinx development files.
 | 
			
		||||
"pecl install sphinx" should take care of that. Add "extension=sphinx.so"
 | 
			
		||||
to your php.ini and reload apache to enable it.
 | 
			
		||||
To use a Sphinx server to search users and notices, you'll need to
 | 
			
		||||
enable the SphinxSearch plugin. Add to your config.php:
 | 
			
		||||
 | 
			
		||||
You can update your MySQL or Postgresql databases to drop their fulltext
 | 
			
		||||
search indexes, since they're now provided by sphinx.
 | 
			
		||||
  addPlugin('SphinxSearch');
 | 
			
		||||
  $config['sphinx']['server'] = 'searchhost.local';
 | 
			
		||||
 | 
			
		||||
On the sphinx server side, a script reads the main database and build
 | 
			
		||||
the keyword index. A cron job reads the database and keeps the sphinx
 | 
			
		||||
indexes up to date. scripts/sphinx-cron.sh should be called by cron
 | 
			
		||||
every 5 minutes, for example. scripts/sphinx.sh is an init.d script
 | 
			
		||||
to start and stop the sphinx search daemon.
 | 
			
		||||
You also need to install, compile and enable the sphinx pecl extension for
 | 
			
		||||
php on the client side, which itself depends on the sphinx development files.
 | 
			
		||||
 | 
			
		||||
See plugins/SphinxSearch/README for more details and server setup.
 | 
			
		||||
 | 
			
		||||
SMS
 | 
			
		||||
---
 | 
			
		||||
@@ -1168,17 +1164,6 @@ base: memcached uses key-value pairs to store data. We build long,
 | 
			
		||||
      StatusNet site using your memcached server.
 | 
			
		||||
port: Port to connect to; defaults to 11211.
 | 
			
		||||
 | 
			
		||||
sphinx
 | 
			
		||||
------
 | 
			
		||||
 | 
			
		||||
You can get a significant boost in performance using Sphinx Search
 | 
			
		||||
instead of your database server to search for users and notices.
 | 
			
		||||
<http://sphinxsearch.com/>.
 | 
			
		||||
 | 
			
		||||
enabled: Set to true to enable. Default false.
 | 
			
		||||
server: a string with the hostname of the sphinx server.
 | 
			
		||||
port: an integer with the port number of the sphinx server.
 | 
			
		||||
 | 
			
		||||
emailpost
 | 
			
		||||
---------
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -67,7 +67,7 @@ class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
 | 
			
		||||
 | 
			
		||||
        if (!in_array($this->format, array('xml', 'json'))) {
 | 
			
		||||
            $this->clientError(
 | 
			
		||||
                _('API method not found!'),
 | 
			
		||||
                _('API method not found.'),
 | 
			
		||||
                404,
 | 
			
		||||
                $this->format
 | 
			
		||||
            );
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										157
									
								
								actions/apiaccountupdatedeliverydevice.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								actions/apiaccountupdatedeliverydevice.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,157 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet, the distributed open-source microblogging tool
 | 
			
		||||
 *
 | 
			
		||||
 * Update the authenticating user notification channels
 | 
			
		||||
 *
 | 
			
		||||
 * 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    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
require_once INSTALLDIR . '/lib/apiauth.php';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sets which channel (device) StatusNet delivers updates to for
 | 
			
		||||
 * the authenticating user. Sending none as the device parameter
 | 
			
		||||
 * will disable IM and/or SMS updates.
 | 
			
		||||
 *
 | 
			
		||||
 * @category API
 | 
			
		||||
 * @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 ApiAccountUpdateDeliveryDeviceAction extends ApiAuthAction
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Take arguments for running
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $args $_REQUEST args
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean success flag
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function prepare($args)
 | 
			
		||||
    {
 | 
			
		||||
        parent::prepare($args);
 | 
			
		||||
 | 
			
		||||
        $this->user   = $this->auth_user;
 | 
			
		||||
        $this->device = $this->trimmed('device');
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle the request
 | 
			
		||||
     *
 | 
			
		||||
     * See which request params have been set, and update the user settings
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $args $_REQUEST data (unused)
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function handle($args)
 | 
			
		||||
    {
 | 
			
		||||
        parent::handle($args);
 | 
			
		||||
 | 
			
		||||
        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
 | 
			
		||||
            $this->clientError(
 | 
			
		||||
                _('This method requires a POST.'),
 | 
			
		||||
                400, $this->format
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!in_array($this->format, array('xml', 'json'))) {
 | 
			
		||||
            $this->clientError(
 | 
			
		||||
                _('API method not found.'),
 | 
			
		||||
                404,
 | 
			
		||||
                $this->format
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Note: Twitter no longer supports IM
 | 
			
		||||
 | 
			
		||||
        if (!in_array(strtolower($this->device), array('sms', 'im', 'none'))) {
 | 
			
		||||
            $this->clientError(
 | 
			
		||||
                _(
 | 
			
		||||
                    'You must specify a parameter named ' .
 | 
			
		||||
                    '\'device\' with a value of one of: sms, im, none'
 | 
			
		||||
                )
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (empty($this->user)) {
 | 
			
		||||
            $this->clientError(_('No such user.'), 404, $this->format);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $original = clone($this->user);
 | 
			
		||||
 | 
			
		||||
        if (strtolower($this->device) == 'sms') {
 | 
			
		||||
            $this->user->smsnotify = true;
 | 
			
		||||
        } elseif (strtolower($this->device) == 'im') {
 | 
			
		||||
            $this->user->jabbernotify = true;
 | 
			
		||||
        } elseif (strtolower($this->device == 'none')) {
 | 
			
		||||
            $this->user->smsnotify    = false;
 | 
			
		||||
            $this->user->jabbernotify = false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $result = $this->user->update($original);
 | 
			
		||||
 | 
			
		||||
        if ($result === false) {
 | 
			
		||||
            common_log_db_error($this->user, 'UPDATE', __FILE__);
 | 
			
		||||
            $this->serverError(_('Could not update user.'));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $profile = $this->user->getProfile();
 | 
			
		||||
 | 
			
		||||
        $twitter_user = $this->twitterUserArray($profile, true);
 | 
			
		||||
 | 
			
		||||
        // Note: this Twitter API method is retarded because it doesn't give
 | 
			
		||||
        // any success/failure information. Twitter's docs claim that the
 | 
			
		||||
        // notification field will change to reflect notification choice,
 | 
			
		||||
        // but that's not true; notification> is used to indicate
 | 
			
		||||
        // whether the auth user is following the user in question.
 | 
			
		||||
 | 
			
		||||
        if ($this->format == 'xml') {
 | 
			
		||||
            $this->initDocument('xml');
 | 
			
		||||
            $this->showTwitterXmlUser($twitter_user);
 | 
			
		||||
            $this->endDocument('xml');
 | 
			
		||||
        } elseif ($this->format == 'json') {
 | 
			
		||||
            $this->initDocument('json');
 | 
			
		||||
            $this->showJsonObjects($twitter_user);
 | 
			
		||||
            $this->endDocument('json');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										166
									
								
								actions/apiaccountupdateprofile.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								actions/apiaccountupdateprofile.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,166 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet, the distributed open-source microblogging tool
 | 
			
		||||
 *
 | 
			
		||||
 * Update the authenticating user's 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  API
 | 
			
		||||
 * @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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
require_once INSTALLDIR . '/lib/apiauth.php';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * API analog to the profile settings page
 | 
			
		||||
 * Only the parameters specified will be updated.
 | 
			
		||||
 *
 | 
			
		||||
 * @category API
 | 
			
		||||
 * @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 ApiAccountUpdateProfileAction extends ApiAuthAction
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Take arguments for running
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $args $_REQUEST args
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean success flag
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function prepare($args)
 | 
			
		||||
    {
 | 
			
		||||
        parent::prepare($args);
 | 
			
		||||
 | 
			
		||||
        $this->user = $this->auth_user;
 | 
			
		||||
 | 
			
		||||
        $this->name        = $this->trimmed('name');
 | 
			
		||||
        $this->url         = $this->trimmed('url');
 | 
			
		||||
        $this->location    = $this->trimmed('location');
 | 
			
		||||
        $this->description = $this->trimmed('description');
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle the request
 | 
			
		||||
     *
 | 
			
		||||
     * See which request params have been set, and update the profile
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $args $_REQUEST data (unused)
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function handle($args)
 | 
			
		||||
    {
 | 
			
		||||
        parent::handle($args);
 | 
			
		||||
 | 
			
		||||
        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
 | 
			
		||||
            $this->clientError(
 | 
			
		||||
                _('This method requires a POST.'),
 | 
			
		||||
                400, $this->format
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!in_array($this->format, array('xml', 'json'))) {
 | 
			
		||||
            $this->clientError(
 | 
			
		||||
                _('API method not found.'),
 | 
			
		||||
                404,
 | 
			
		||||
                $this->format
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (empty($this->user)) {
 | 
			
		||||
            $this->clientError(_('No such user.'), 404, $this->format);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $profile = $this->user->getProfile();
 | 
			
		||||
 | 
			
		||||
        if (empty($profile)) {
 | 
			
		||||
            $this->clientError(_('User has no profile.'));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $original = clone($profile);
 | 
			
		||||
 | 
			
		||||
        if (empty($this->name)) {
 | 
			
		||||
            $profile->fullname = $this->name;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (empty($this->url)) {
 | 
			
		||||
            $profile->homepage = $this->url;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!empty($this->description)) {
 | 
			
		||||
            $profile->bio = $this->description;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!empty($this->location)) {
 | 
			
		||||
            $profile->location = $this->location;
 | 
			
		||||
 | 
			
		||||
            $loc = Location::fromName($location);
 | 
			
		||||
 | 
			
		||||
            if (!empty($loc)) {
 | 
			
		||||
                $profile->lat         = $loc->lat;
 | 
			
		||||
                $profile->lon         = $loc->lon;
 | 
			
		||||
                $profile->location_id = $loc->location_id;
 | 
			
		||||
                $profile->location_ns = $loc->location_ns;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $result = $profile->update($original);
 | 
			
		||||
 | 
			
		||||
        if (!$result) {
 | 
			
		||||
            common_log_db_error($profile, 'UPDATE', __FILE__);
 | 
			
		||||
            $this->serverError(_('Could not save profile.'));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        common_broadcast_profile($profile);
 | 
			
		||||
 | 
			
		||||
        $twitter_user = $this->twitterUserArray($profile, true);
 | 
			
		||||
 | 
			
		||||
        if ($this->format == 'xml') {
 | 
			
		||||
            $this->initDocument('xml');
 | 
			
		||||
            $this->showTwitterXmlUser($twitter_user);
 | 
			
		||||
            $this->endDocument('xml');
 | 
			
		||||
        } elseif ($this->format == 'json') {
 | 
			
		||||
            $this->initDocument('json');
 | 
			
		||||
            $this->showJsonObjects($twitter_user);
 | 
			
		||||
            $this->endDocument('json');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										211
									
								
								actions/apiaccountupdateprofilebackgroundimage.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								actions/apiaccountupdateprofilebackgroundimage.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,211 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet, the distributed open-source microblogging tool
 | 
			
		||||
 *
 | 
			
		||||
 * Update the authenticating user's profile background image
 | 
			
		||||
 *
 | 
			
		||||
 * 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    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
require_once INSTALLDIR . '/lib/apiauth.php';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Update the authenticating user's profile background image
 | 
			
		||||
 *
 | 
			
		||||
 * @category API
 | 
			
		||||
 * @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 ApiAccountUpdateProfileBackgroundImageAction extends ApiAuthAction
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    var $tile = false;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Take arguments for running
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $args $_REQUEST args
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean success flag
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function prepare($args)
 | 
			
		||||
    {
 | 
			
		||||
        parent::prepare($args);
 | 
			
		||||
 | 
			
		||||
        $this->user  = $this->auth_user;
 | 
			
		||||
        $this->tile  = $this->arg('tile');
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle the request
 | 
			
		||||
     *
 | 
			
		||||
     * Check whether the credentials are valid and output the result
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $args $_REQUEST data (unused)
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function handle($args)
 | 
			
		||||
    {
 | 
			
		||||
        parent::handle($args);
 | 
			
		||||
 | 
			
		||||
        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
 | 
			
		||||
            $this->clientError(
 | 
			
		||||
                _('This method requires a POST.'),
 | 
			
		||||
                400, $this->format
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!in_array($this->format, array('xml', 'json'))) {
 | 
			
		||||
            $this->clientError(
 | 
			
		||||
                _('API method not found.'),
 | 
			
		||||
                404,
 | 
			
		||||
                $this->format
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 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->clientError(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (empty($this->user)) {
 | 
			
		||||
            $this->clientError(_('No such user.'), 404, $this->format);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $design = $this->user->getDesign();
 | 
			
		||||
 | 
			
		||||
        // XXX: This is kinda gross, but before we can add a background
 | 
			
		||||
        // img we have to make sure there's a Design because design ID
 | 
			
		||||
        // is part of the img filename.
 | 
			
		||||
 | 
			
		||||
        if (empty($design)) {
 | 
			
		||||
 | 
			
		||||
            $this->user->query('BEGIN');
 | 
			
		||||
 | 
			
		||||
            // save new design
 | 
			
		||||
            $design = new Design();
 | 
			
		||||
            $id = $design->insert();
 | 
			
		||||
 | 
			
		||||
            if (empty($id)) {
 | 
			
		||||
                common_log_db_error($id, 'INSERT', __FILE__);
 | 
			
		||||
                $this->clientError(_('Unable to save your design settings.'));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $original              = clone($this->user);
 | 
			
		||||
            $this->user->design_id = $id;
 | 
			
		||||
            $result                = $this->user->update($original);
 | 
			
		||||
 | 
			
		||||
            if (empty($result)) {
 | 
			
		||||
                common_log_db_error($original, 'UPDATE', __FILE__);
 | 
			
		||||
                $this->clientError(_('Unable to save your design settings.'));
 | 
			
		||||
                $this->user->query('ROLLBACK');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $this->user->query('COMMIT');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Okay, now get the image and add it to the design
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $imagefile = ImageFile::fromUpload('image');
 | 
			
		||||
        } catch (Exception $e) {
 | 
			
		||||
            $this->clientError($e->getMessage(), 400, $this->format);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $filename = Design::filename(
 | 
			
		||||
            $design->id,
 | 
			
		||||
            image_type_to_extension($imagefile->type),
 | 
			
		||||
            common_timestamp()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        $filepath = Design::path($filename);
 | 
			
		||||
 | 
			
		||||
        move_uploaded_file($imagefile->filepath, $filepath);
 | 
			
		||||
 | 
			
		||||
        // delete any old backround img laying around
 | 
			
		||||
 | 
			
		||||
        if (isset($design->backgroundimage)) {
 | 
			
		||||
            @unlink(Design::path($design->backgroundimage));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $original = clone($design);
 | 
			
		||||
        $design->backgroundimage = $filename;
 | 
			
		||||
        $design->setDisposition(true, false, ($this->tile == 'true'));
 | 
			
		||||
 | 
			
		||||
        $result = $design->update($original);
 | 
			
		||||
 | 
			
		||||
        if ($result === false) {
 | 
			
		||||
            common_log_db_error($design, 'UPDATE', __FILE__);
 | 
			
		||||
            $this->showForm(_('Could not update your design.'));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $profile = $this->user->getProfile();
 | 
			
		||||
 | 
			
		||||
        if (empty($profile)) {
 | 
			
		||||
            $this->clientError(_('User has no profile.'));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $twitter_user = $this->twitterUserArray($profile, true);
 | 
			
		||||
 | 
			
		||||
        if ($this->format == 'xml') {
 | 
			
		||||
            $this->initDocument('xml');
 | 
			
		||||
            $this->showTwitterXmlUser($twitter_user);
 | 
			
		||||
            $this->endDocument('xml');
 | 
			
		||||
        } elseif ($this->format == 'json') {
 | 
			
		||||
            $this->initDocument('json');
 | 
			
		||||
            $this->showJsonObjects($twitter_user);
 | 
			
		||||
            $this->endDocument('json');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										246
									
								
								actions/apiaccountupdateprofilecolors.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								actions/apiaccountupdateprofilecolors.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,246 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet, the distributed open-source microblogging tool
 | 
			
		||||
 *
 | 
			
		||||
 * Update a user's design colors
 | 
			
		||||
 *
 | 
			
		||||
 * 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    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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
require_once INSTALLDIR . '/lib/apiauth.php';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Sets one or more hex values that control the color scheme of the
 | 
			
		||||
 * authenticating user's design
 | 
			
		||||
 *
 | 
			
		||||
 * @category API
 | 
			
		||||
 * @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 ApiAccountUpdateProfileColorsAction extends ApiAuthAction
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    var $profile_background_color     = null;
 | 
			
		||||
    var $profile_text_color           = null;
 | 
			
		||||
    var $profile_link_color           = null;
 | 
			
		||||
    var $profile_sidebar_fill_color   = null;
 | 
			
		||||
    var $profile_sidebar_border_color = null;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Take arguments for running
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $args $_REQUEST args
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean success flag
 | 
			
		||||
     *
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function prepare($args)
 | 
			
		||||
    {
 | 
			
		||||
        parent::prepare($args);
 | 
			
		||||
 | 
			
		||||
        $this->user   = $this->auth_user;
 | 
			
		||||
 | 
			
		||||
        $this->profile_background_color
 | 
			
		||||
            = $this->trimmed('profile_background_color');
 | 
			
		||||
        $this->profile_text_color
 | 
			
		||||
            = $this->trimmed('profile_text_color');
 | 
			
		||||
        $this->profile_link_color
 | 
			
		||||
            = $this->trimmed('profile_link_color');
 | 
			
		||||
        $this->profile_sidebar_fill_color
 | 
			
		||||
            = $this->trimmed('profile_sidebar_fill_color');
 | 
			
		||||
 | 
			
		||||
        // XXX: we don't support changing the sidebar border color
 | 
			
		||||
        // in our designs.
 | 
			
		||||
 | 
			
		||||
        $this->profile_sidebar_border_color
 | 
			
		||||
            = $this->trimmed('profile_sidebar_border_color');
 | 
			
		||||
 | 
			
		||||
        // XXX: Unlike Twitter, we do allow people to change the 'content color'
 | 
			
		||||
 | 
			
		||||
        $this->profile_content_color = $this->trimmed('profile_content_color');
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle the request
 | 
			
		||||
     *
 | 
			
		||||
     * Try to save the user's colors in her design. Create a new design
 | 
			
		||||
     * if the user doesn't already have one.
 | 
			
		||||
     *
 | 
			
		||||
     * @param array $args $_REQUEST data (unused)
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function handle($args)
 | 
			
		||||
    {
 | 
			
		||||
        parent::handle($args);
 | 
			
		||||
 | 
			
		||||
        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
 | 
			
		||||
            $this->clientError(
 | 
			
		||||
                _('This method requires a POST.'),
 | 
			
		||||
                400, $this->format
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!in_array($this->format, array('xml', 'json'))) {
 | 
			
		||||
            $this->clientError(
 | 
			
		||||
                _('API method not found.'),
 | 
			
		||||
                404,
 | 
			
		||||
                $this->format
 | 
			
		||||
            );
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $design = $this->user->getDesign();
 | 
			
		||||
 | 
			
		||||
        if (!empty($design)) {
 | 
			
		||||
 | 
			
		||||
            $original = clone($design);
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                $this->setColors($design);
 | 
			
		||||
            } catch (WebColorException $e) {
 | 
			
		||||
                $this->clientError($e->getMessage());
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $result = $design->update($original);
 | 
			
		||||
 | 
			
		||||
            if ($result === false) {
 | 
			
		||||
                common_log_db_error($design, 'UPDATE', __FILE__);
 | 
			
		||||
                $this->clientError(_('Could not update your design.'));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
            $this->user->query('BEGIN');
 | 
			
		||||
 | 
			
		||||
            // save new design
 | 
			
		||||
            $design = new Design();
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                $this->setColors($design);
 | 
			
		||||
            } catch (WebColorException $e) {
 | 
			
		||||
                $this->clientError($e->getMessage());
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $id = $design->insert();
 | 
			
		||||
 | 
			
		||||
            if (empty($id)) {
 | 
			
		||||
                common_log_db_error($id, 'INSERT', __FILE__);
 | 
			
		||||
                $this->clientError(_('Unable to save your design settings.'));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $original              = clone($this->user);
 | 
			
		||||
            $this->user->design_id = $id;
 | 
			
		||||
            $result                = $this->user->update($original);
 | 
			
		||||
 | 
			
		||||
            if (empty($result)) {
 | 
			
		||||
                common_log_db_error($original, 'UPDATE', __FILE__);
 | 
			
		||||
                $this->clientError(_('Unable to save your design settings.'));
 | 
			
		||||
                $this->user->query('ROLLBACK');
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $this->user->query('COMMIT');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $profile = $this->user->getProfile();
 | 
			
		||||
 | 
			
		||||
        if (empty($profile)) {
 | 
			
		||||
            $this->clientError(_('User has no profile.'));
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $twitter_user = $this->twitterUserArray($profile, true);
 | 
			
		||||
 | 
			
		||||
        if ($this->format == 'xml') {
 | 
			
		||||
            $this->initDocument('xml');
 | 
			
		||||
            $this->showTwitterXmlUser($twitter_user);
 | 
			
		||||
            $this->endDocument('xml');
 | 
			
		||||
        } elseif ($this->format == 'json') {
 | 
			
		||||
            $this->initDocument('json');
 | 
			
		||||
            $this->showJsonObjects($twitter_user);
 | 
			
		||||
            $this->endDocument('json');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the user's design colors based on the request parameters
 | 
			
		||||
     *
 | 
			
		||||
     * @param Design $design the user's Design
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function setColors($design)
 | 
			
		||||
    {
 | 
			
		||||
        $bgcolor = empty($this->profile_background_color) ?
 | 
			
		||||
            null : new WebColor($this->profile_background_color);
 | 
			
		||||
        $tcolor  = empty($this->profile_text_color) ?
 | 
			
		||||
            null : new WebColor($this->profile_text_color);
 | 
			
		||||
        $sbcolor = empty($this->profile_sidebar_fill_color) ?
 | 
			
		||||
            null : new WebColor($this->profile_sidebar_fill_color);
 | 
			
		||||
        $lcolor  = empty($this->profile_link_color) ?
 | 
			
		||||
            null : new WebColor($this->profile_link_color);
 | 
			
		||||
        $ccolor  = empty($this->profile_content_color) ?
 | 
			
		||||
            null : new WebColor($this->profile_content_color);
 | 
			
		||||
 | 
			
		||||
        if (!empty($bgcolor)) {
 | 
			
		||||
            $design->backgroundcolor = $bgcolor->intValue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!empty($ccolor)) {
 | 
			
		||||
            $design->contentcolor = $ccolor->intValue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!empty($sbcolor)) {
 | 
			
		||||
            $design->sidebarcolor = $sbcolor->intValue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!empty($tcolor)) {
 | 
			
		||||
            $design->textcolor = $tcolor->intValue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!empty($lcolor)) {
 | 
			
		||||
            $design->linkcolor = $lcolor->intValue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -135,7 +135,7 @@ class ApiAccountUpdateProfileImageAction extends ApiAuthAction
 | 
			
		||||
 | 
			
		||||
        common_broadcast_profile($profile);
 | 
			
		||||
 | 
			
		||||
        $twitter_user = $this->twitterUserArray($this->user->getProfile(), true);
 | 
			
		||||
        $twitter_user = $this->twitterUserArray($profile, true);
 | 
			
		||||
 | 
			
		||||
        if ($this->format == 'xml') {
 | 
			
		||||
            $this->initDocument('xml');
 | 
			
		||||
 
 | 
			
		||||
@@ -104,7 +104,7 @@ class NoticesearchAction extends SearchAction
 | 
			
		||||
    {
 | 
			
		||||
        $notice        = new Notice();
 | 
			
		||||
 | 
			
		||||
        $search_engine = $notice->getSearchEngine('identica_notices');
 | 
			
		||||
        $search_engine = $notice->getSearchEngine('notice');
 | 
			
		||||
        $search_engine->set_sort_mode('chron');
 | 
			
		||||
        // Ask for an extra to see if there's more.
 | 
			
		||||
        $search_engine->limit((($page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
 | 
			
		||||
 
 | 
			
		||||
@@ -62,7 +62,7 @@ class NoticesearchrssAction extends Rss10Action
 | 
			
		||||
 | 
			
		||||
        $notice = new Notice();
 | 
			
		||||
 | 
			
		||||
        $search_engine = $notice->getSearchEngine('identica_notices');
 | 
			
		||||
        $search_engine = $notice->getSearchEngine('notice');
 | 
			
		||||
        $search_engine->set_sort_mode('chron');
 | 
			
		||||
 | 
			
		||||
        if (!$limit) $limit = 20;
 | 
			
		||||
 
 | 
			
		||||
@@ -58,19 +58,6 @@ class PasswordsettingsAction extends AccountSettingsAction
 | 
			
		||||
        return _('Change password');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function prepare($args){
 | 
			
		||||
        parent::prepare($args);
 | 
			
		||||
 | 
			
		||||
        $user = common_current_user();
 | 
			
		||||
 | 
			
		||||
        Event::handle('CanUserChangeField', array($user->nickname, 'password'));
 | 
			
		||||
 | 
			
		||||
        if(! $fields['password']){
 | 
			
		||||
            //user is not allowed to change his password
 | 
			
		||||
            $this->clientError(_('You are not allowed to change your password'));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Instructions for use
 | 
			
		||||
     *
 | 
			
		||||
@@ -182,8 +169,8 @@ class PasswordsettingsAction extends AccountSettingsAction
 | 
			
		||||
            $oldpassword = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $errormsg = false;
 | 
			
		||||
        if(! Event::handle('ChangePassword', array($user->nickname, $oldpassword, $newpassword, &$errormsg))){
 | 
			
		||||
        $success = false;
 | 
			
		||||
        if(! Event::handle('StartChangePassword', array($user->nickname, $oldpassword, $newpassword))){
 | 
			
		||||
            //no handler changed the password, so change the password internally
 | 
			
		||||
            $original = clone($user);
 | 
			
		||||
 | 
			
		||||
@@ -199,11 +186,9 @@ class PasswordsettingsAction extends AccountSettingsAction
 | 
			
		||||
                $this->serverError(_('Can\'t save new password.'));
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            Event::handle('EndChangePassword', array($nickname));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if($errormsg === false)
 | 
			
		||||
        $this->showForm(_('Password saved.'), true);
 | 
			
		||||
        else
 | 
			
		||||
            $this->showForm($errormsg);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,7 @@ class PeoplesearchAction extends SearchAction
 | 
			
		||||
    function showResults($q, $page)
 | 
			
		||||
    {
 | 
			
		||||
        $profile = new Profile();
 | 
			
		||||
        $search_engine = $profile->getSearchEngine('identica_people');
 | 
			
		||||
        $search_engine = $profile->getSearchEngine('profile');
 | 
			
		||||
        $search_engine->set_sort_mode('chron');
 | 
			
		||||
        // Ask for an extra to see if there's more.
 | 
			
		||||
        $search_engine->limit((($page-1)*PROFILES_PER_PAGE), PROFILES_PER_PAGE + 1);
 | 
			
		||||
 
 | 
			
		||||
@@ -161,7 +161,7 @@ class TwitapisearchatomAction extends ApiAction
 | 
			
		||||
        // lcase it for comparison
 | 
			
		||||
        $q = strtolower($this->query);
 | 
			
		||||
 | 
			
		||||
        $search_engine = $notice->getSearchEngine('identica_notices');
 | 
			
		||||
        $search_engine = $notice->getSearchEngine('notice');
 | 
			
		||||
        $search_engine->set_sort_mode('chron');
 | 
			
		||||
        $search_engine->limit(($this->page - 1) * $this->rpp,
 | 
			
		||||
            $this->rpp + 1, true);
 | 
			
		||||
 
 | 
			
		||||
@@ -121,7 +121,7 @@ class TwitapisearchjsonAction extends ApiAction
 | 
			
		||||
        // lcase it for comparison
 | 
			
		||||
        $q = strtolower($this->query);
 | 
			
		||||
 | 
			
		||||
        $search_engine = $notice->getSearchEngine('identica_notices');
 | 
			
		||||
        $search_engine = $notice->getSearchEngine('notice');
 | 
			
		||||
        $search_engine->set_sort_mode('chron');
 | 
			
		||||
        $search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1, true);
 | 
			
		||||
        if (false === $search_engine->query($q)) {
 | 
			
		||||
 
 | 
			
		||||
@@ -184,14 +184,7 @@ class Memcached_DataObject extends DB_DataObject
 | 
			
		||||
        require_once INSTALLDIR.'/lib/search_engines.php';
 | 
			
		||||
        static $search_engine;
 | 
			
		||||
        if (!isset($search_engine)) {
 | 
			
		||||
                $connected = false;
 | 
			
		||||
                if (common_config('sphinx', 'enabled')) {
 | 
			
		||||
                    $search_engine = new SphinxSearch($this, $table);
 | 
			
		||||
                    $connected = $search_engine->is_connected();
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // unable to connect to sphinx' search daemon
 | 
			
		||||
                if (!$connected) {
 | 
			
		||||
            if (Event::handle('GetSearchEngine', array($this, $table, &$search_engine))) {
 | 
			
		||||
                if ('mysql' === common_config('db', 'type')) {
 | 
			
		||||
                    $type = common_config('search', 'type');
 | 
			
		||||
                    if ($type == 'like') {
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,7 @@ class Status_network extends DB_DataObject
 | 
			
		||||
        $config['db']['ini_'.$dbname] = INSTALLDIR.'/classes/status_network.ini';
 | 
			
		||||
        $config['db']['table_status_network'] = $dbname;
 | 
			
		||||
 | 
			
		||||
        if (class_exists('Memcache')) {
 | 
			
		||||
            self::$cache = new Memcache();
 | 
			
		||||
 | 
			
		||||
            if (is_array($servers)) {
 | 
			
		||||
@@ -66,6 +67,7 @@ class Status_network extends DB_DataObject
 | 
			
		||||
            } else {
 | 
			
		||||
                self::$cache->addServer($servers);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self::$base = $dbname;
 | 
			
		||||
    }
 | 
			
		||||
@@ -76,6 +78,10 @@ class Status_network extends DB_DataObject
 | 
			
		||||
 | 
			
		||||
    static function memGet($k, $v)
 | 
			
		||||
    {
 | 
			
		||||
        if (!self::$cache) {
 | 
			
		||||
            return self::staticGet($k, $v);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $ck = self::cacheKey($k, $v);
 | 
			
		||||
 | 
			
		||||
        $sn = self::$cache->get($ck);
 | 
			
		||||
@@ -92,12 +98,14 @@ class Status_network extends DB_DataObject
 | 
			
		||||
 | 
			
		||||
    function decache()
 | 
			
		||||
    {
 | 
			
		||||
        if (self::$cache) {
 | 
			
		||||
            $keys = array('nickname', 'hostname', 'pathname');
 | 
			
		||||
            foreach ($keys as $k) {
 | 
			
		||||
                $ck = self::cacheKey($k, $this->$k);
 | 
			
		||||
                self::$cache->delete($ck);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function update($orig=null)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -104,35 +104,29 @@ class AccountSettingsNav extends Widget
 | 
			
		||||
        if (Event::handle('StartAccountSettingsNav', array(&$this->action))) {
 | 
			
		||||
            $user = common_current_user();
 | 
			
		||||
 | 
			
		||||
            $menu = array();
 | 
			
		||||
            $menu['profilesettings'] =
 | 
			
		||||
                    array(_('Profile'),
 | 
			
		||||
                          _('Change your profile settings'));
 | 
			
		||||
            if(Event::handle('CanUserChangeField', array($user->nickname, 'avatar'))){
 | 
			
		||||
                $menu['avatarsettings'] =
 | 
			
		||||
                        array(_('Avatar'),
 | 
			
		||||
                              _('Upload an avatar'));
 | 
			
		||||
            if(Event::handle('StartAccountSettingsProfileMenuItem', array($this, &$menu))){
 | 
			
		||||
                $this->showMenuItem('profilesettings',_('Profile'),_('Change your profile settings'));
 | 
			
		||||
                Event::handle('EndAccountSettingsProfileMenuItem', array($this, &$menu));
 | 
			
		||||
            }
 | 
			
		||||
            if(Event::handle('CanUserChangeField', array($user->nickname, 'password'))){
 | 
			
		||||
                $menu['passwordsettings'] =
 | 
			
		||||
                        array(_('Password'),
 | 
			
		||||
                              _('Change your password'));
 | 
			
		||||
            if(Event::handle('StartAccountSettingsAvatarMenuItem', array($this, &$menu))){
 | 
			
		||||
                $this->showMenuItem('avatarsettings',_('Avatar'),_('Upload an avatar'));
 | 
			
		||||
                Event::handle('EndAccountSettingsAvatarMenuItem', array($this, &$menu));
 | 
			
		||||
            }
 | 
			
		||||
            $menu['emailsettings'] =
 | 
			
		||||
                    array(_('Email'),
 | 
			
		||||
                          _('Change email handling'));
 | 
			
		||||
            $menu['userdesignsettings'] =
 | 
			
		||||
                    array(_('Design'),
 | 
			
		||||
                          _('Design your profile'));
 | 
			
		||||
            $menu['othersettings'] =
 | 
			
		||||
                    array(_('Other'),
 | 
			
		||||
                          _('Other options'));
 | 
			
		||||
 | 
			
		||||
            foreach ($menu as $menuaction => $menudesc) {
 | 
			
		||||
                $this->action->menuItem(common_local_url($menuaction),
 | 
			
		||||
                                        $menudesc[0],
 | 
			
		||||
                                        $menudesc[1],
 | 
			
		||||
                                        $action_name === $menuaction);
 | 
			
		||||
            if(Event::handle('StartAccountSettingsPasswordMenuItem', array($this, &$menu))){
 | 
			
		||||
                $this->showMenuItem('passwordsettings',_('Password'),_('Change your password'));
 | 
			
		||||
                Event::handle('EndAccountSettingsPasswordMenuItem', array($this, &$menu));
 | 
			
		||||
            }
 | 
			
		||||
            if(Event::handle('StartAccountSettingsEmailMenuItem', array($this, &$menu))){
 | 
			
		||||
                $this->showMenuItem('emailsettings',_('Email'),_('Change email handling'));
 | 
			
		||||
                Event::handle('EndAccountSettingsEmailMenuItem', array($this, &$menu));
 | 
			
		||||
            }
 | 
			
		||||
            if(Event::handle('StartAccountSettingsDesignMenuItem', array($this, &$menu))){
 | 
			
		||||
                $this->showMenuItem('userdesignsettings',_('Design'),_('Design your profile'));
 | 
			
		||||
                Event::handle('EndAccountSettingsDesignMenuItem', array($this, &$menu));
 | 
			
		||||
            }
 | 
			
		||||
            if(Event::handle('StartAccountSettingsOtherMenuItem', array($this, &$menu))){
 | 
			
		||||
                $this->showMenuItem('othersettings',_('Other'),_('Other options'));
 | 
			
		||||
                Event::handle('EndAccountSettingsOtherMenuItem', array($this, &$menu));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Event::handle('EndAccountSettingsNav', array(&$this->action));
 | 
			
		||||
@@ -140,4 +134,13 @@ class AccountSettingsNav extends Widget
 | 
			
		||||
 | 
			
		||||
        $this->action->elementEnd('ul');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function showMenuItem($menuaction, $desc1, $desc2)
 | 
			
		||||
    {
 | 
			
		||||
        $action_name = $this->action->trimmed('action');
 | 
			
		||||
        $this->action->menuItem(common_local_url($menuaction),
 | 
			
		||||
            $desc1,
 | 
			
		||||
            $desc2,
 | 
			
		||||
            $action_name === $menuaction);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								lib/api.php
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								lib/api.php
									
									
									
									
									
								
							@@ -176,9 +176,14 @@ class ApiAction extends Action
 | 
			
		||||
        $twitter_user['utc_offset'] = $t->format('Z');
 | 
			
		||||
        $twitter_user['time_zone'] = $timezone;
 | 
			
		||||
 | 
			
		||||
        // To be supported some day, perhaps
 | 
			
		||||
        $twitter_user['profile_background_image_url'] = '';
 | 
			
		||||
        $twitter_user['profile_background_tile'] = false;
 | 
			
		||||
        $twitter_user['profile_background_image_url']
 | 
			
		||||
            = empty($design->backgroundimage)
 | 
			
		||||
            ? '' : ($design->disposition & BACKGROUND_ON)
 | 
			
		||||
            ? Design::url($design->backgroundimage) : '';
 | 
			
		||||
 | 
			
		||||
        $twitter_user['profile_background_tile']
 | 
			
		||||
            = empty($design->disposition)
 | 
			
		||||
            ? '' : ($design->disposition & BACKGROUND_TILE) ? 'true' : 'false';
 | 
			
		||||
 | 
			
		||||
        $twitter_user['statuses_count'] = $profile->noticeCount();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -125,10 +125,6 @@ $default =
 | 
			
		||||
              'public' => array()), # JIDs of users who want to receive the public stream
 | 
			
		||||
        'invite' =>
 | 
			
		||||
        array('enabled' => true),
 | 
			
		||||
        'sphinx' =>
 | 
			
		||||
        array('enabled' => false,
 | 
			
		||||
              'server' => 'localhost',
 | 
			
		||||
              'port' => 3312),
 | 
			
		||||
        'tag' =>
 | 
			
		||||
        array('dropoff' => 864000.0),
 | 
			
		||||
        'popular' =>
 | 
			
		||||
 
 | 
			
		||||
@@ -428,9 +428,21 @@ class Router
 | 
			
		||||
            $m->connect('api/account/verify_credentials.:format',
 | 
			
		||||
                        array('action' => 'ApiAccountVerifyCredentials'));
 | 
			
		||||
 | 
			
		||||
            $m->connect('api/account/update_profile.:format',
 | 
			
		||||
                        array('action' => 'ApiAccountUpdateProfile'));
 | 
			
		||||
 | 
			
		||||
            $m->connect('api/account/update_profile_image.:format',
 | 
			
		||||
                        array('action' => 'ApiAccountUpdateProfileImage'));
 | 
			
		||||
 | 
			
		||||
            $m->connect('api/account/update_profile_background_image.:format',
 | 
			
		||||
                        array('action' => 'ApiAccountUpdateProfileBackgroundImage'));
 | 
			
		||||
 | 
			
		||||
            $m->connect('api/account/update_profile_colors.:format',
 | 
			
		||||
                        array('action' => 'ApiAccountUpdateProfileColors'));
 | 
			
		||||
 | 
			
		||||
            $m->connect('api/account/update_delivery_device.:format',
 | 
			
		||||
                        array('action' => 'ApiAccountUpdateDeliveryDevice'));
 | 
			
		||||
 | 
			
		||||
            // special case where verify_credentials is called w/out a format
 | 
			
		||||
 | 
			
		||||
            $m->connect('api/account/verify_credentials',
 | 
			
		||||
 
 | 
			
		||||
@@ -46,70 +46,11 @@ class SearchEngine
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SphinxSearch extends SearchEngine
 | 
			
		||||
{
 | 
			
		||||
    private $sphinx;
 | 
			
		||||
    private $connected;
 | 
			
		||||
 | 
			
		||||
    function __construct($target, $table)
 | 
			
		||||
    {
 | 
			
		||||
        $fp = @fsockopen(common_config('sphinx', 'server'), common_config('sphinx', 'port'));
 | 
			
		||||
        if (!$fp) {
 | 
			
		||||
            $this->connected = false;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        fclose($fp);
 | 
			
		||||
        parent::__construct($target, $table);
 | 
			
		||||
        $this->sphinx = new SphinxClient;
 | 
			
		||||
        $this->sphinx->setServer(common_config('sphinx', 'server'), common_config('sphinx', 'port'));
 | 
			
		||||
        $this->connected = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function is_connected()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->connected;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function limit($offset, $count, $rss = false)
 | 
			
		||||
    {
 | 
			
		||||
        //FIXME without LARGEST_POSSIBLE, the most recent results aren't returned
 | 
			
		||||
        //      this probably has a large impact on performance
 | 
			
		||||
        $LARGEST_POSSIBLE = 1e6;
 | 
			
		||||
 | 
			
		||||
        if ($rss) {
 | 
			
		||||
            $this->sphinx->setLimits($offset, $count, $count, $LARGEST_POSSIBLE);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            // return at most 50 pages of results
 | 
			
		||||
            $this->sphinx->setLimits($offset, $count, 50 * ($count - 1), $LARGEST_POSSIBLE);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->target->limit(0, $count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function query($q)
 | 
			
		||||
    {
 | 
			
		||||
        $result = $this->sphinx->query($q, $this->table);
 | 
			
		||||
        if (!isset($result['matches'])) return false;
 | 
			
		||||
        $id_set = join(', ', array_keys($result['matches']));
 | 
			
		||||
        $this->target->whereAdd("id in ($id_set)");
 | 
			
		||||
        return true;
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
    function set_sort_mode($mode)
 | 
			
		||||
    {
 | 
			
		||||
        if ('chron' === $mode) {
 | 
			
		||||
            $this->sphinx->SetSortMode(SPH_SORT_ATTR_DESC, 'created_ts');
 | 
			
		||||
            return $this->target->orderBy('created desc');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class MySQLSearch extends SearchEngine
 | 
			
		||||
{
 | 
			
		||||
    function query($q)
 | 
			
		||||
    {
 | 
			
		||||
        if ('identica_people' === $this->table) {
 | 
			
		||||
        if ('profile' === $this->table) {
 | 
			
		||||
            $this->target->whereAdd('MATCH(nickname, fullname, location, bio, homepage) ' .
 | 
			
		||||
                                    'AGAINST (\''.addslashes($q).'\' IN BOOLEAN MODE)');
 | 
			
		||||
            if (strtolower($q) != $q) {
 | 
			
		||||
@@ -117,7 +58,7 @@ class MySQLSearch extends SearchEngine
 | 
			
		||||
                                        'AGAINST (\''.addslashes(strtolower($q)).'\' IN BOOLEAN MODE)', 'OR');
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if ('identica_notices' === $this->table) {
 | 
			
		||||
        } else if ('notice' === $this->table) {
 | 
			
		||||
 | 
			
		||||
            // Don't show imported notices
 | 
			
		||||
            $this->target->whereAdd('notice.is_local != ' . Notice::GATEWAY);
 | 
			
		||||
@@ -143,13 +84,13 @@ class MySQLLikeSearch extends SearchEngine
 | 
			
		||||
{
 | 
			
		||||
    function query($q)
 | 
			
		||||
    {
 | 
			
		||||
        if ('identica_people' === $this->table) {
 | 
			
		||||
        if ('profile' === $this->table) {
 | 
			
		||||
            $qry = sprintf('(nickname LIKE "%%%1$s%%" OR '.
 | 
			
		||||
                           ' fullname LIKE "%%%1$s%%" OR '.
 | 
			
		||||
                           ' location LIKE "%%%1$s%%" OR '.
 | 
			
		||||
                           ' bio      LIKE "%%%1$s%%" OR '.
 | 
			
		||||
                           ' homepage LIKE "%%%1$s%%")', addslashes($q));
 | 
			
		||||
        } else if ('identica_notices' === $this->table) {
 | 
			
		||||
        } else if ('notice' === $this->table) {
 | 
			
		||||
            $qry = sprintf('content LIKE "%%%1$s%%"', addslashes($q));
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new ServerException('Unknown table: ' . $this->table);
 | 
			
		||||
@@ -165,9 +106,9 @@ class PGSearch extends SearchEngine
 | 
			
		||||
{
 | 
			
		||||
    function query($q)
 | 
			
		||||
    {
 | 
			
		||||
        if ('identica_people' === $this->table) {
 | 
			
		||||
        if ('profile' === $this->table) {
 | 
			
		||||
            return $this->target->whereAdd('textsearch @@ plainto_tsquery(\''.addslashes($q).'\')');
 | 
			
		||||
        } else if ('identica_notices' === $this->table) {
 | 
			
		||||
        } else if ('notice' === $this->table) {
 | 
			
		||||
 | 
			
		||||
            // XXX: We need to filter out gateway notices (notice.is_local = -2) --Zach
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										172
									
								
								plugins/Auth/AuthPlugin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								plugins/Auth/AuthPlugin.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,172 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet, the distributed open-source microblogging tool
 | 
			
		||||
 *
 | 
			
		||||
 * Superclass for plugins that do authentication and/or authorization
 | 
			
		||||
 *
 | 
			
		||||
 * 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>
 | 
			
		||||
 * @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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Superclass for plugins that do authentication
 | 
			
		||||
 *
 | 
			
		||||
 * @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/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
abstract class AuthPlugin extends Plugin
 | 
			
		||||
{
 | 
			
		||||
    //is this plugin authoritative for authentication?
 | 
			
		||||
    public $authn_authoritative = false;
 | 
			
		||||
    
 | 
			
		||||
    //should accounts be automatically created after a successful login attempt?
 | 
			
		||||
    public $autoregistration = false;
 | 
			
		||||
 | 
			
		||||
    //can the user change their email address
 | 
			
		||||
    public $email_changeable=true;
 | 
			
		||||
 | 
			
		||||
    //can the user change their email address
 | 
			
		||||
    public $password_changeable=true;
 | 
			
		||||
 | 
			
		||||
    //------------Auth plugin should implement some (or all) of these methods------------\\
 | 
			
		||||
    /**
 | 
			
		||||
    * Check if a nickname/password combination is valid
 | 
			
		||||
    * @param nickname
 | 
			
		||||
    * @param password
 | 
			
		||||
    * @return boolean true if the credentials are valid, false if they are invalid.
 | 
			
		||||
    */
 | 
			
		||||
    function checkPassword($nickname, $password)
 | 
			
		||||
    {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    * Automatically register a user when they attempt to login with valid credentials.
 | 
			
		||||
    * User::register($data) is a very useful method for this implementation
 | 
			
		||||
    * @param nickname
 | 
			
		||||
    * @return boolean true if the user was created, false if autoregistration is not allowed, null if this plugin is not responsible for this nickname
 | 
			
		||||
    */
 | 
			
		||||
    function autoRegister($nickname)
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    * Change a user's password
 | 
			
		||||
    * The old password has been verified to be valid by this plugin before this call is made
 | 
			
		||||
    * @param nickname
 | 
			
		||||
    * @param oldpassword
 | 
			
		||||
    * @param newpassword
 | 
			
		||||
    * @return boolean true if the password was changed, false if password changing failed for some reason, null if this plugin is not responsible for this nickname
 | 
			
		||||
    */
 | 
			
		||||
    function changePassword($nickname,$oldpassword,$newpassword)
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
    * Can a user change this field in his own profile?
 | 
			
		||||
    * @param nickname
 | 
			
		||||
    * @param field
 | 
			
		||||
    * @return boolean true if the field can be changed, false if not allowed to change it, null if this plugin is not responsible for this nickname
 | 
			
		||||
    */
 | 
			
		||||
    function canUserChangeField($nickname, $field)
 | 
			
		||||
    {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //------------Below are the methods that connect StatusNet to the implementing Auth plugin------------\\
 | 
			
		||||
    function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    function StartCheckPassword($nickname, $password, &$authenticatedUser){
 | 
			
		||||
        if($this->password_changeable){
 | 
			
		||||
            $authenticated = $this->checkPassword($nickname, $password);
 | 
			
		||||
            if($authenticated){
 | 
			
		||||
                $authenticatedUser = User::staticGet('nickname', $nickname);
 | 
			
		||||
                if(!$authenticatedUser && $this->autoregistration){
 | 
			
		||||
                    if($this->autoregister($nickname)){
 | 
			
		||||
                        $authenticatedUser = User::staticGet('nickname', $nickname);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
            }else{
 | 
			
		||||
                if($this->authn_authoritative){
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            //we're not authoritative, so let other handlers try
 | 
			
		||||
        }else{
 | 
			
		||||
            if($this->authn_authoritative){
 | 
			
		||||
                //since we're authoritative, no other plugin could do this
 | 
			
		||||
                throw new Exception(_('Password changing is not allowed'));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onStartChangePassword($nickname,$oldpassword,$newpassword)
 | 
			
		||||
    {
 | 
			
		||||
        if($this->password_changeable){
 | 
			
		||||
            $authenticated = $this->checkPassword($nickname, $oldpassword);
 | 
			
		||||
            if($authenticated){
 | 
			
		||||
                $result = $this->changePassword($nickname,$oldpassword,$newpassword);
 | 
			
		||||
                if($result){
 | 
			
		||||
                    //stop handling of other handlers, because what was requested was done
 | 
			
		||||
                    return false;
 | 
			
		||||
                }else{
 | 
			
		||||
                    throw new Exception(_('Password changing failed'));
 | 
			
		||||
                }
 | 
			
		||||
            }else{
 | 
			
		||||
                if($this->authn_authoritative){
 | 
			
		||||
                    //since we're authoritative, no other plugin could do this
 | 
			
		||||
                    throw new Exception(_('Password changing failed'));
 | 
			
		||||
                }else{
 | 
			
		||||
                    //let another handler try
 | 
			
		||||
                    return null;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }else{
 | 
			
		||||
            if($this->authn_authoritative){
 | 
			
		||||
                //since we're authoritative, no other plugin could do this
 | 
			
		||||
                throw new Exception(_('Password changing is not allowed'));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onStartAccountSettingsPasswordMenuItem($widget)
 | 
			
		||||
    {
 | 
			
		||||
        if($this->authn_authoritative && !$this->password_changeable){
 | 
			
		||||
            //since we're authoritative, no other plugin could change passwords, so do render the menu item
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										119
									
								
								plugins/GeoURLPlugin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								plugins/GeoURLPlugin.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * StatusNet, the distributed open-source microblogging tool
 | 
			
		||||
 *
 | 
			
		||||
 * Plugin to add ICBM metadata to HTML pages and report data to GeoURL.org
 | 
			
		||||
 *
 | 
			
		||||
 * 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  Action
 | 
			
		||||
 * @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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Plugin to add ICBM metadata to HTML pages and report data to GeoURL.org
 | 
			
		||||
 *
 | 
			
		||||
 * Adds metadata to notice and profile pages that geourl.org and others
 | 
			
		||||
 * understand. Also, pings geourl.org when a new notice is saved or
 | 
			
		||||
 * a profile is changed.
 | 
			
		||||
 *
 | 
			
		||||
 * @category Plugin
 | 
			
		||||
 * @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/
 | 
			
		||||
 *
 | 
			
		||||
 * @seeAlso  Location
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class GeoURLPlugin extends Plugin
 | 
			
		||||
{
 | 
			
		||||
    public $ping = 'http://geourl.org/ping/';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add extra <meta> headers for certain pages that geourl.org understands
 | 
			
		||||
     *
 | 
			
		||||
     * @param Action $action page being shown
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean event handler flag
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function onEndShowHeadElements($action)
 | 
			
		||||
    {
 | 
			
		||||
        $name = $action->trimmed('action');
 | 
			
		||||
 | 
			
		||||
        $location = null;
 | 
			
		||||
 | 
			
		||||
        if ($name == 'showstream') {
 | 
			
		||||
            $profile = $action->profile;
 | 
			
		||||
            if (!empty($profile) && !empty($profile->lat) && !empty($profile->lon)) {
 | 
			
		||||
                $location = $profile->lat . ', ' . $profile->lon;
 | 
			
		||||
            }
 | 
			
		||||
        } else if ($name == 'shownotice') {
 | 
			
		||||
            $notice = $action->profile;
 | 
			
		||||
            if (!empty($notice) && !empty($notice->lat) && !empty($notice->lon)) {
 | 
			
		||||
                $location = $notice->lat . ', ' . $notice->lon;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!empty($location)) {
 | 
			
		||||
            $action->element('meta', array('name' => 'ICBM',
 | 
			
		||||
                                           'content' => $location));
 | 
			
		||||
            $action->element('meta', array('name' => 'DC.title',
 | 
			
		||||
                                           'content' => $action->title()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Report local notices to GeoURL.org when they're created
 | 
			
		||||
     *
 | 
			
		||||
     * @param Notice &$notice queued notice
 | 
			
		||||
     *
 | 
			
		||||
     * @return boolean event handler flag
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    function onHandleQueuedNotice(&$notice)
 | 
			
		||||
    {
 | 
			
		||||
        if ($notice->is_local == 1) {
 | 
			
		||||
 | 
			
		||||
            $request = HTTPClient::start();
 | 
			
		||||
 | 
			
		||||
            $url = common_local_url('shownotice',
 | 
			
		||||
                                    array('notice' => $notice->id));
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                $request->post($this->ping,
 | 
			
		||||
                               null,
 | 
			
		||||
                               array('p' => $url));
 | 
			
		||||
            } catch (HTTP_Request2_Exception $e) {
 | 
			
		||||
                common_log(LOG_WARNING,
 | 
			
		||||
                           "GeoURL.org ping failed for '$url' ($this->ping)");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -31,38 +31,53 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
require_once INSTALLDIR.'/plugins/Ldap/ldap.php';
 | 
			
		||||
require_once INSTALLDIR.'/plugins/Auth/AuthPlugin.php';
 | 
			
		||||
require_once 'Net/LDAP2.php';
 | 
			
		||||
 | 
			
		||||
class LdapPlugin extends Plugin
 | 
			
		||||
class LdapPlugin extends AuthPlugin
 | 
			
		||||
{
 | 
			
		||||
    private $config = array();
 | 
			
		||||
    public $host=null;
 | 
			
		||||
    public $port=null;
 | 
			
		||||
    public $version=null;
 | 
			
		||||
    public $starttls=null;
 | 
			
		||||
    public $binddn=null;
 | 
			
		||||
    public $bindpw=null;
 | 
			
		||||
    public $basedn=null;
 | 
			
		||||
    public $options=null;
 | 
			
		||||
    public $filter=null;
 | 
			
		||||
    public $scope=null;
 | 
			
		||||
    public $attributes=array();
 | 
			
		||||
 | 
			
		||||
    function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    function onCheckPassword($nickname, $password, &$authenticated)
 | 
			
		||||
    //---interface implementation---//
 | 
			
		||||
 | 
			
		||||
    function checkPassword($nickname, $password)
 | 
			
		||||
    {
 | 
			
		||||
        if(ldap_check_password($nickname, $password)){
 | 
			
		||||
            $authenticated = true;
 | 
			
		||||
            //stop handling of other events, because we have an answer
 | 
			
		||||
        $ldap = $this->ldap_get_connection();
 | 
			
		||||
        if(!$ldap){
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if(common_config('ldap','authoritative')){
 | 
			
		||||
            //a false return stops handler processing
 | 
			
		||||
        $entry = $this->ldap_get_user($nickname);
 | 
			
		||||
        if(!$entry){
 | 
			
		||||
            return false;
 | 
			
		||||
        }else{
 | 
			
		||||
            $config = $this->ldap_get_config();
 | 
			
		||||
            $config['binddn']=$entry->dn();
 | 
			
		||||
            $config['bindpw']=$password;
 | 
			
		||||
            if($this->ldap_get_connection($config)){
 | 
			
		||||
                return true;
 | 
			
		||||
            }else{
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    function onAutoRegister($nickname)
 | 
			
		||||
    {
 | 
			
		||||
        $user = User::staticGet('nickname', $nickname);
 | 
			
		||||
        if (! is_null($user) && $user !== false) {
 | 
			
		||||
            common_log(LOG_WARNING, "An attempt was made to autoregister an existing user with nickname: $nickname");
 | 
			
		||||
            return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function autoRegister($nickname)
 | 
			
		||||
    {
 | 
			
		||||
        $attributes=array();
 | 
			
		||||
        $config_attributes = array('nickname','email','fullname','homepage','location');
 | 
			
		||||
        foreach($config_attributes as $config_attribute){
 | 
			
		||||
@@ -71,7 +86,7 @@ class LdapPlugin extends Plugin
 | 
			
		||||
                array_push($attributes,$value);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $entry = ldap_get_user($nickname,$attributes);
 | 
			
		||||
        $entry = $this->ldap_get_user($nickname,$attributes);
 | 
			
		||||
        if($entry){
 | 
			
		||||
            $registration_data = array();
 | 
			
		||||
            foreach($config_attributes as $config_attribute){
 | 
			
		||||
@@ -89,21 +104,22 @@ class LdapPlugin extends Plugin
 | 
			
		||||
            //set the database saved password to a random string.
 | 
			
		||||
            $registration_data['password']=common_good_rand(16);
 | 
			
		||||
            $user = User::register($registration_data);
 | 
			
		||||
            //prevent other handlers from running, as we have registered the user
 | 
			
		||||
            return false;
 | 
			
		||||
            return true;
 | 
			
		||||
        }else{
 | 
			
		||||
            //user isn't in ldap, so we cannot register him
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onChangePassword($nickname,$oldpassword,$newpassword,&$errormsg)
 | 
			
		||||
    function changePassword($nickname,$oldpassword,$newpassword)
 | 
			
		||||
    {
 | 
			
		||||
        //TODO implement this
 | 
			
		||||
        $errormsg = _('Sorry, changing LDAP passwords is not supported at this time');
 | 
			
		||||
        throw new Exception(_('Sorry, changing LDAP passwords is not supported at this time'));
 | 
			
		||||
 | 
			
		||||
        //return false, indicating that the event has been handled
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onCanUserChangeField($nickname, $field)
 | 
			
		||||
    function canUserChangeField($nickname, $field)
 | 
			
		||||
    {
 | 
			
		||||
        switch($field)
 | 
			
		||||
        {
 | 
			
		||||
@@ -113,4 +129,67 @@ class LdapPlugin extends Plugin
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    //---utility functions---//
 | 
			
		||||
    function ldap_get_config(){
 | 
			
		||||
        $config = array();
 | 
			
		||||
        $keys = array('host','port','version','starttls','binddn','bindpw','basedn','options','filter','scope');
 | 
			
		||||
        foreach($keys as $key){
 | 
			
		||||
            $value = $this->$key;
 | 
			
		||||
            if($value!==null){
 | 
			
		||||
                $config[$key]=$value;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return $config;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    function ldap_get_connection($config = null){
 | 
			
		||||
        if($config == null){
 | 
			
		||||
            $config = $this->ldap_get_config();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        //cannot use Net_LDAP2::connect() as StatusNet uses
 | 
			
		||||
        //PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
 | 
			
		||||
        //PEAR handling can be overridden on instance objects, so we do that.
 | 
			
		||||
        $ldap = new Net_LDAP2($config);
 | 
			
		||||
        $ldap->setErrorHandling(PEAR_ERROR_RETURN);
 | 
			
		||||
        $err=$ldap->bind();
 | 
			
		||||
        if (Net_LDAP2::isError($err)) {
 | 
			
		||||
            common_log(LOG_WARNING, 'Could not connect to LDAP server: '.$err->getMessage());
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return $ldap;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    /**
 | 
			
		||||
     * get an LDAP entry for a user with a given username
 | 
			
		||||
     * 
 | 
			
		||||
     * @param string $username
 | 
			
		||||
     * $param array $attributes LDAP attributes to retrieve
 | 
			
		||||
     * @return string DN
 | 
			
		||||
     */
 | 
			
		||||
    function ldap_get_user($username,$attributes=array()){
 | 
			
		||||
        $ldap = $this->ldap_get_connection();
 | 
			
		||||
        $filter = Net_LDAP2_Filter::create(common_config('ldap','nickname_attribute'), 'equals',  $username);
 | 
			
		||||
        $options = array(
 | 
			
		||||
            'scope' => 'sub',
 | 
			
		||||
            'attributes' => $attributes
 | 
			
		||||
        );
 | 
			
		||||
        $search = $ldap->search(null,$filter,$options);
 | 
			
		||||
        
 | 
			
		||||
        if (PEAR::isError($search)) {
 | 
			
		||||
            common_log(LOG_WARNING, 'Error while getting DN for user: '.$search->getMessage());
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if($search->count()==0){
 | 
			
		||||
            return false;
 | 
			
		||||
        }else if($search->count()==1){
 | 
			
		||||
            $entry = $search->shiftEntry();
 | 
			
		||||
            return $entry;
 | 
			
		||||
        }else{
 | 
			
		||||
            common_log(LOG_WARNING, 'Found ' . $search->count() . ' ldap user with the username: ' . $username);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,22 +2,49 @@ The LDAP plugin allows for StatusNet to handle authentication, authorization, an
 | 
			
		||||
 | 
			
		||||
Installation
 | 
			
		||||
============
 | 
			
		||||
Add configuration entries to config.php. These entries are:
 | 
			
		||||
add "addPlugin('ldap', array('setting'=>'value', 'setting2'=>'value2', ...);" to the bottom of your config.php
 | 
			
		||||
 | 
			
		||||
The following are documented at http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
$config['ldap']['binddn']
 | 
			
		||||
$config['ldap']['bindpw']
 | 
			
		||||
$config['ldap']['basedn']
 | 
			
		||||
$config['ldap']['host']
 | 
			
		||||
Settings
 | 
			
		||||
========
 | 
			
		||||
authn_authoritative (false): Set to true if LDAP's responses are authoritative (meaning if LDAP fails, do check the any other plugins or the internal password database).
 | 
			
		||||
autoregistration (false): Set to true if users should be automatically created when they attempt to login.
 | 
			
		||||
email_changeable (true): Are users allowed to change their email address? (true or false)
 | 
			
		||||
password_changeable (true): Are users allowed to change their passwords? (true or false)
 | 
			
		||||
 | 
			
		||||
$config['ldap']['nickname_attribute'] Set this to the name of the ldap attribute that holds the username. For example, on Microsoft's Active Directory, this should be set to 'sAMAccountName'
 | 
			
		||||
$config['ldap']['nickname_email'] Set this to the name of the ldap attribute that holds the user's email address. For example, on Microsoft's Active Directory, this should be set to 'mail'
 | 
			
		||||
$config['ldap']['nickname_fullname'] Set this to the name of the ldap attribute that holds the user's full name. For example, on Microsoft's Active Directory, this should be set to 'displayName'
 | 
			
		||||
$config['ldap']['nickname_homepage'] Set this to the name of the ldap attribute that holds the the url of the user's home page.
 | 
			
		||||
$config['ldap']['nickname_location'] Set this to the name of the ldap attribute that holds the user's location.
 | 
			
		||||
host*: LDAP server name to connect to. You can provide several hosts in an array in which case the hosts are tried from left to right.. See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
port: Port on the server. See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
version: LDAP version. See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
starttls: TLS is started after connecting. See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
binddn: The distinguished name to bind as (username). See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
bindpw: Password for the binddn. See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
basedn*: LDAP base name (root directory). See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
options: See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
filter: Default search filter. See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
scope: Default search scope. See http://pear.php.net/manual/en/package.networking.net-ldap2.connecting.php
 | 
			
		||||
 | 
			
		||||
$config['ldap']['authoritative'] Set to true if LDAP's responses are authoritative (meaning if LDAP fails, do check the any other plugins or the internal password database)
 | 
			
		||||
$config['ldap']['autoregister'] Set to true if users should be automatically created when they attempt to login
 | 
			
		||||
attributes: an array with the key being the StatusNet user attribute name, and the value the LDAP attribute name
 | 
			
		||||
    nickname*
 | 
			
		||||
    email
 | 
			
		||||
    fullname
 | 
			
		||||
    homepage
 | 
			
		||||
    location
 | 
			
		||||
    
 | 
			
		||||
Finally, add "addPlugin('ldap');" to the bottom of your config.php
 | 
			
		||||
* required
 | 
			
		||||
default values are in (parenthesis)
 | 
			
		||||
 | 
			
		||||
Example
 | 
			
		||||
=======
 | 
			
		||||
Here's an example of an LDAP plugin configuration that connects to Microsoft Active Directory.
 | 
			
		||||
 | 
			
		||||
addPlugin('ldap', array(
 | 
			
		||||
    'authn_authoritative'=>true,
 | 
			
		||||
    'autoregistration'=>true,
 | 
			
		||||
    'binddn'=>'username',
 | 
			
		||||
    'bindpw'=>'password',
 | 
			
		||||
    'basedn'=>'OU=Users,OU=StatusNet,OU=US,DC=americas,DC=global,DC=loc',
 | 
			
		||||
    'host'=>array('server1', 'server2'),
 | 
			
		||||
    'attributes'=>array(
 | 
			
		||||
        'nickname'=>'sAMAccountName',
 | 
			
		||||
        'email'=>'mail',
 | 
			
		||||
        'fullname'=>'displayName')
 | 
			
		||||
));
 | 
			
		||||
 
 | 
			
		||||
@@ -1,108 +0,0 @@
 | 
			
		||||
<?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 'Net/LDAP2.php';
 | 
			
		||||
 | 
			
		||||
function ldap_get_config(){
 | 
			
		||||
    static $config = null;
 | 
			
		||||
    if($config == null){
 | 
			
		||||
        $config = array();
 | 
			
		||||
        $keys = array('host','port','version','starttls','binddn','bindpw','basedn','options','scope');
 | 
			
		||||
        foreach($keys as $key){
 | 
			
		||||
            $value = common_config('ldap', $key);
 | 
			
		||||
            if($value!==false){
 | 
			
		||||
                $config[$key]=$value;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return $config;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ldap_get_connection($config = null){
 | 
			
		||||
    if($config == null){
 | 
			
		||||
        $config = ldap_get_config();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    //cannot use Net_LDAP2::connect() as StatusNet uses
 | 
			
		||||
    //PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
 | 
			
		||||
    //PEAR handling can be overridden on instance objects, so we do that.
 | 
			
		||||
    $ldap = new Net_LDAP2($config);
 | 
			
		||||
    $ldap->setErrorHandling(PEAR_ERROR_RETURN);
 | 
			
		||||
    $err=$ldap->bind();
 | 
			
		||||
    if (Net_LDAP2::isError($err)) {
 | 
			
		||||
        common_log(LOG_WARNING, 'Could not connect to LDAP server: '.$err->getMessage());
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return $ldap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ldap_check_password($username, $password){
 | 
			
		||||
    $ldap = ldap_get_connection();
 | 
			
		||||
    if(!$ldap){
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    $entry = ldap_get_user($username);
 | 
			
		||||
    if(!$entry){
 | 
			
		||||
        return false;
 | 
			
		||||
    }else{
 | 
			
		||||
        $config = ldap_get_config();
 | 
			
		||||
        $config['binddn']=$entry->dn();
 | 
			
		||||
        $config['bindpw']=$password;
 | 
			
		||||
        if(ldap_get_connection($config)){
 | 
			
		||||
            return true;
 | 
			
		||||
        }else{
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * get an LDAP entry for a user with a given username
 | 
			
		||||
 * 
 | 
			
		||||
 * @param string $username
 | 
			
		||||
 * $param array $attributes LDAP attributes to retrieve
 | 
			
		||||
 * @return string DN
 | 
			
		||||
 */
 | 
			
		||||
function ldap_get_user($username,$attributes=array()){
 | 
			
		||||
    $ldap = ldap_get_connection();
 | 
			
		||||
    $filter = Net_LDAP2_Filter::create(common_config('ldap','nickname_attribute'), 'equals',  $username);
 | 
			
		||||
    $options = array(
 | 
			
		||||
        'scope' => 'sub',
 | 
			
		||||
        'attributes' => $attributes
 | 
			
		||||
    );
 | 
			
		||||
    $search = $ldap->search(null,$filter,$options);
 | 
			
		||||
    
 | 
			
		||||
    if (PEAR::isError($search)) {
 | 
			
		||||
        common_log(LOG_WARNING, 'Error while getting DN for user: '.$search->getMessage());
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if($search->count()==0){
 | 
			
		||||
        return false;
 | 
			
		||||
    }else if($search->count()==1){
 | 
			
		||||
        $entry = $search->shiftEntry();
 | 
			
		||||
        return $entry;
 | 
			
		||||
    }else{
 | 
			
		||||
        common_log(LOG_WARNING, 'Found ' . $search->count() . ' ldap user with the username: ' . $username);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										45
									
								
								plugins/SphinxSearch/README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								plugins/SphinxSearch/README
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
You can get a significant boost in performance using Sphinx Search
 | 
			
		||||
instead of your database server to search for users and notices.
 | 
			
		||||
<http://sphinxsearch.com/>.
 | 
			
		||||
 | 
			
		||||
Configuration
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
In StatusNet's configuration, you can adjust the following settings
 | 
			
		||||
under 'sphinx':
 | 
			
		||||
 | 
			
		||||
enabled: Set to true to enable. Default false.
 | 
			
		||||
server: a string with the hostname of the sphinx server.
 | 
			
		||||
port: an integer with the port number of the sphinx server.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Requirements
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
To use a Sphinx server to search users and notices, you also need
 | 
			
		||||
to install, compile and enable the sphinx pecl extension for php on the
 | 
			
		||||
client side, which itself depends on the sphinx development files.
 | 
			
		||||
"pecl install sphinx" should take care of that. Add "extension=sphinx.so"
 | 
			
		||||
to your php.ini and reload apache to enable it.
 | 
			
		||||
 | 
			
		||||
You can update your MySQL or Postgresql databases to drop their fulltext
 | 
			
		||||
search indexes, since they're now provided by sphinx.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
You will also need a Sphinx server to serve the search queries.
 | 
			
		||||
 | 
			
		||||
On the sphinx server side, a script reads the main database and build
 | 
			
		||||
the keyword index. A cron job reads the database and keeps the sphinx
 | 
			
		||||
indexes up to date. scripts/sphinx-cron.sh should be called by cron
 | 
			
		||||
every 5 minutes, for example. scripts/sphinx.sh is an init.d script
 | 
			
		||||
to start and stop the sphinx search daemon.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Server configuration
 | 
			
		||||
--------------------
 | 
			
		||||
scripts/gen_config.php can generate a sphinx.conf file listing MySQL
 | 
			
		||||
data sources for your databases. You may need to tweak paths afterwards.
 | 
			
		||||
 | 
			
		||||
  $ plugins/SphinxSearch/scripts/gen_config.php > sphinx.conf
 | 
			
		||||
 | 
			
		||||
If you wish, you can build a full config yourself based on sphinx.conf.sample
 | 
			
		||||
							
								
								
									
										100
									
								
								plugins/SphinxSearch/SphinxSearchPlugin.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								plugins/SphinxSearch/SphinxSearchPlugin.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
<?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 2009 Control Yourself, Inc.
 | 
			
		||||
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 | 
			
		||||
 * @link      http://laconi.ca/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
if (!defined('STATUSNET')) {
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Set defaults if not already set in the config array...
 | 
			
		||||
global $config;
 | 
			
		||||
$sphinxDefaults =
 | 
			
		||||
    array('enabled' => true,
 | 
			
		||||
          'server' => 'localhost',
 | 
			
		||||
          'port' => 3312);
 | 
			
		||||
foreach($sphinxDefaults as $key => $val) {
 | 
			
		||||
    if (!isset($config['sphinx'][$key])) {
 | 
			
		||||
        $config['sphinx'][$key] = $val;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Plugin for Sphinx search backend.
 | 
			
		||||
 *
 | 
			
		||||
 * @category Plugin
 | 
			
		||||
 * @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://laconi.ca/
 | 
			
		||||
 * @link     http://twitter.com/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
class SphinxSearchPlugin extends Plugin
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Automatically load any classes used
 | 
			
		||||
     *
 | 
			
		||||
     * @param string $cls the class
 | 
			
		||||
     * @return boolean hook return
 | 
			
		||||
     */
 | 
			
		||||
    function onAutoload($cls)
 | 
			
		||||
    {
 | 
			
		||||
        switch ($cls) {
 | 
			
		||||
        case 'SphinxSearch':
 | 
			
		||||
            include_once INSTALLDIR . '/plugins/SphinxSearch/' .
 | 
			
		||||
              strtolower($cls) . '.php';
 | 
			
		||||
            return false;
 | 
			
		||||
        default:
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create sphinx search engine object for the given table type.
 | 
			
		||||
     *
 | 
			
		||||
     * @param Memcached_DataObject $target
 | 
			
		||||
     * @param string $table
 | 
			
		||||
     * @param out &$search_engine SearchEngine object on output if successful
 | 
			
		||||
     * @ return boolean hook return
 | 
			
		||||
     */
 | 
			
		||||
    function onGetSearchEngine(Memcached_DataObject $target, $table, &$search_engine)
 | 
			
		||||
    {
 | 
			
		||||
        if (common_config('sphinx', 'enabled')) {
 | 
			
		||||
            if (!class_exists('SphinxClient')) {
 | 
			
		||||
                throw new ServerException('Sphinx PHP extension must be installed.');
 | 
			
		||||
            }
 | 
			
		||||
            $engine = new SphinxSearch($target, $table);
 | 
			
		||||
            if ($engine->is_connected()) {
 | 
			
		||||
                $search_engine = $engine;
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Sphinx disabled or disconnected
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								plugins/SphinxSearch/scripts/gen_config.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										126
									
								
								plugins/SphinxSearch/scripts/gen_config.php
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
#!/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__) . '/../../..'));
 | 
			
		||||
 | 
			
		||||
$longoptions = array('base=', 'network');
 | 
			
		||||
 | 
			
		||||
$helptext = <<<END_OF_TRIM_HELP
 | 
			
		||||
Generates sphinx.conf file based on StatusNet configuration.
 | 
			
		||||
    --base               Base dir to Sphinx install
 | 
			
		||||
                         (default /usr/local)
 | 
			
		||||
    --network            Use status_network global config table
 | 
			
		||||
                         (non-functional at present)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
END_OF_TRIM_HELP;
 | 
			
		||||
 | 
			
		||||
require_once INSTALLDIR . '/scripts/commandline.inc';
 | 
			
		||||
require dirname(__FILE__) . '/sphinx-utils.php';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
$timestamp = date('r');
 | 
			
		||||
print <<<END
 | 
			
		||||
#
 | 
			
		||||
# Sphinx configuration for StatusNet
 | 
			
		||||
# Generated {$timestamp}
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
END;
 | 
			
		||||
 | 
			
		||||
sphinx_iterate_sites('sphinx_site_template');
 | 
			
		||||
 | 
			
		||||
print <<<END
 | 
			
		||||
 | 
			
		||||
indexer
 | 
			
		||||
{
 | 
			
		||||
    mem_limit               = 300M
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
searchd
 | 
			
		||||
{
 | 
			
		||||
    port                    = 3312
 | 
			
		||||
    log                     = {$base}/log/searchd.log
 | 
			
		||||
    query_log               = {$base}/log/query.log
 | 
			
		||||
    read_timeout            = 5
 | 
			
		||||
    max_children            = 30
 | 
			
		||||
    pid_file                = {$base}/log/searchd.pid
 | 
			
		||||
    max_matches             = 1000
 | 
			
		||||
    seamless_rotate         = 1
 | 
			
		||||
    preopen_indexes         = 0
 | 
			
		||||
    unlink_old              = 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
END;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Build config entries for a single site
 | 
			
		||||
 * @fixme we only seem to have master DB currently available...
 | 
			
		||||
 */
 | 
			
		||||
function sphinx_site_template($sn)
 | 
			
		||||
{
 | 
			
		||||
    return
 | 
			
		||||
        sphinx_template($sn,
 | 
			
		||||
            'profile',
 | 
			
		||||
            'SELECT id, UNIX_TIMESTAMP(created) as created_ts, nickname, fullname, location, bio, homepage FROM profile',
 | 
			
		||||
            'SELECT * FROM profile where id = $id') .
 | 
			
		||||
        sphinx_template($sn,
 | 
			
		||||
            'notice',
 | 
			
		||||
            'SELECT id, UNIX_TIMESTAMP(created) as created_ts, content FROM notice',
 | 
			
		||||
            'SELECT * FROM notice where notice.id = $id AND notice.is_local != -2');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sphinx_template($sn, $table, $query, $query_info)
 | 
			
		||||
{
 | 
			
		||||
    $base = sphinx_base();
 | 
			
		||||
    $dbtype = common_config('db', 'type');
 | 
			
		||||
 | 
			
		||||
    print <<<END
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# {$sn->sitename}
 | 
			
		||||
#
 | 
			
		||||
source {$sn->dbname}_src_{$table}
 | 
			
		||||
{
 | 
			
		||||
    type                    = {$dbtype}
 | 
			
		||||
    sql_host                = {$sn->dbhost}
 | 
			
		||||
    sql_user                = {$sn->dbuser}
 | 
			
		||||
    sql_pass                = {$sn->dbpass}
 | 
			
		||||
    sql_db                  = {$sn->dbname}
 | 
			
		||||
    sql_query_pre           = SET NAMES utf8;
 | 
			
		||||
    sql_query               = {$query}
 | 
			
		||||
    sql_query_info          = {$query_info}
 | 
			
		||||
    sql_attr_timestamp      = created_ts
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
index {$sn->dbname}_{$table}
 | 
			
		||||
{
 | 
			
		||||
    source                  = {$sn->dbname}_src_{$table}
 | 
			
		||||
    path                    = {$base}/data/{$sn->dbname}_{$table}
 | 
			
		||||
    docinfo                 = extern
 | 
			
		||||
    charset_type            = utf-8
 | 
			
		||||
    min_word_len            = 3
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
END;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								plugins/SphinxSearch/scripts/index_update.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										61
									
								
								plugins/SphinxSearch/scripts/index_update.php
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
#!/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__) . '/../../..'));
 | 
			
		||||
 | 
			
		||||
$longoptions = array('base=', 'network');
 | 
			
		||||
 | 
			
		||||
$helptext = <<<END_OF_TRIM_HELP
 | 
			
		||||
Runs Sphinx search indexer.
 | 
			
		||||
    --rotate             Have Sphinx run index update in background and
 | 
			
		||||
                         rotate updated indexes into place as they finish.
 | 
			
		||||
    --base               Base dir to Sphinx install
 | 
			
		||||
                         (default /usr/local)
 | 
			
		||||
    --network            Use status_network global config table for site list
 | 
			
		||||
                         (non-functional at present)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
END_OF_TRIM_HELP;
 | 
			
		||||
 | 
			
		||||
require_once INSTALLDIR . '/scripts/commandline.inc';
 | 
			
		||||
require dirname(__FILE__) . '/sphinx-utils.php';
 | 
			
		||||
 | 
			
		||||
sphinx_iterate_sites('sphinx_index_update');
 | 
			
		||||
 | 
			
		||||
function sphinx_index_update($sn)
 | 
			
		||||
{
 | 
			
		||||
    $base = sphinx_base();
 | 
			
		||||
    
 | 
			
		||||
    $baseIndexes = array('notice', 'profile');
 | 
			
		||||
    $params = array();
 | 
			
		||||
    
 | 
			
		||||
    if (have_option('rotate')) {
 | 
			
		||||
        $params[] = '--rotate';
 | 
			
		||||
    }
 | 
			
		||||
    foreach ($baseIndexes as $index) {
 | 
			
		||||
        $params[] = "{$sn->dbname}_{$index}";
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    $params = implode(' ', $params);
 | 
			
		||||
    $cmd = "$base/bin/indexer --config $base/etc/sphinx.conf $params";
 | 
			
		||||
    
 | 
			
		||||
    print "$cmd\n";
 | 
			
		||||
    system($cmd);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								plugins/SphinxSearch/scripts/sphinx-utils.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								plugins/SphinxSearch/scripts/sphinx-utils.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
<?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/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
function sphinx_use_network()
 | 
			
		||||
{
 | 
			
		||||
    return have_option('network');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sphinx_base()
 | 
			
		||||
{
 | 
			
		||||
    if (have_option('base')) {
 | 
			
		||||
        return get_option_value('base');
 | 
			
		||||
    } else {
 | 
			
		||||
        return "/usr/local/sphinx";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sphinx_iterate_sites($callback)
 | 
			
		||||
{
 | 
			
		||||
    if (sphinx_use_network()) {
 | 
			
		||||
        // @fixme this should use, like, some kind of config
 | 
			
		||||
        Status_network::setupDB('localhost', 'statusnet', 'statuspass', 'statusnet');
 | 
			
		||||
        $sn = new Status_network();
 | 
			
		||||
        if (!$sn->find()) {
 | 
			
		||||
            die("Confused... no sites in status_network table or lookup failed.\n");
 | 
			
		||||
        }
 | 
			
		||||
        while ($sn->fetch()) {
 | 
			
		||||
            $callback($sn);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if (preg_match('!^(mysqli?|pgsql)://(.*?):(.*?)@(.*?)/(.*?)$!',
 | 
			
		||||
                common_config('db', 'database'), $matches)) {
 | 
			
		||||
            list(/*all*/, $dbtype, $dbuser, $dbpass, $dbhost, $dbname) = $matches;
 | 
			
		||||
            $sn = (object)array(
 | 
			
		||||
                'sitename' => common_config('site', 'name'),
 | 
			
		||||
                'dbhost' => $dbhost,
 | 
			
		||||
                'dbuser' => $dbuser,
 | 
			
		||||
                'dbpass' => $dbpass,
 | 
			
		||||
                'dbname' => $dbname);
 | 
			
		||||
            $callback($sn);
 | 
			
		||||
        } else {
 | 
			
		||||
            print "Unrecognized database configuration string in config.php\n";
 | 
			
		||||
            exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										96
									
								
								plugins/SphinxSearch/sphinxsearch.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								plugins/SphinxSearch/sphinxsearch.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
			
		||||
<?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 SphinxSearch extends SearchEngine
 | 
			
		||||
{
 | 
			
		||||
    private $sphinx;
 | 
			
		||||
    private $connected;
 | 
			
		||||
 | 
			
		||||
    function __construct($target, $table)
 | 
			
		||||
    {
 | 
			
		||||
        $fp = @fsockopen(common_config('sphinx', 'server'), common_config('sphinx', 'port'));
 | 
			
		||||
        if (!$fp) {
 | 
			
		||||
            $this->connected = false;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        fclose($fp);
 | 
			
		||||
        parent::__construct($target, $table);
 | 
			
		||||
        $this->sphinx = new SphinxClient;
 | 
			
		||||
        $this->sphinx->setServer(common_config('sphinx', 'server'), common_config('sphinx', 'port'));
 | 
			
		||||
        $this->connected = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function is_connected()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->connected;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function limit($offset, $count, $rss = false)
 | 
			
		||||
    {
 | 
			
		||||
        //FIXME without LARGEST_POSSIBLE, the most recent results aren't returned
 | 
			
		||||
        //      this probably has a large impact on performance
 | 
			
		||||
        $LARGEST_POSSIBLE = 1e6;
 | 
			
		||||
 | 
			
		||||
        if ($rss) {
 | 
			
		||||
            $this->sphinx->setLimits($offset, $count, $count, $LARGEST_POSSIBLE);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            // return at most 50 pages of results
 | 
			
		||||
            $this->sphinx->setLimits($offset, $count, 50 * ($count - 1), $LARGEST_POSSIBLE);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->target->limit(0, $count);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function query($q)
 | 
			
		||||
    {
 | 
			
		||||
        $result = $this->sphinx->query($q, $this->remote_table());
 | 
			
		||||
        if (!isset($result['matches'])) return false;
 | 
			
		||||
        $id_set = join(', ', array_keys($result['matches']));
 | 
			
		||||
        $this->target->whereAdd("id in ($id_set)");
 | 
			
		||||
        return true;
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
    function set_sort_mode($mode)
 | 
			
		||||
    {
 | 
			
		||||
        if ('chron' === $mode) {
 | 
			
		||||
            $this->sphinx->SetSortMode(SPH_SORT_ATTR_DESC, 'created_ts');
 | 
			
		||||
            return $this->target->orderBy('created desc');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function remote_table()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->dbname() . '_' . $this->table;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function dbname()
 | 
			
		||||
    {
 | 
			
		||||
        // @fixme there should be a less dreadful way to do this.
 | 
			
		||||
        // DB objects won't give database back until they connect, it's confusing
 | 
			
		||||
        if (preg_match('!^.*?://.*?:.*?@.*?/(.*?)$!', common_config('db', 'database'), $matches)) {
 | 
			
		||||
            return $matches[1];
 | 
			
		||||
        }
 | 
			
		||||
        throw new ServerException("Sphinx search could not identify database name");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
# StatusNet - a 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/>.
 | 
			
		||||
 | 
			
		||||
# This program tries to start the daemons for StatusNet.
 | 
			
		||||
# Note that the 'maildaemon' needs to run as a mail filter.
 | 
			
		||||
 | 
			
		||||
/usr/local/bin/indexer --config /usr/local/etc/sphinx.conf --all --rotate
 | 
			
		||||
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
#!/bin/sh
 | 
			
		||||
 | 
			
		||||
# StatusNet - a 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/>.
 | 
			
		||||
 | 
			
		||||
# This program tries to start the daemons for StatusNet.
 | 
			
		||||
# Note that the 'maildaemon' needs to run as a mail filter.
 | 
			
		||||
 | 
			
		||||
/usr/local/bin/indexer --config /usr/local/etc/sphinx.conf --all
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user