From 7160e11395168723f6692b140f35a943267731cd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 24 Dec 2009 15:13:30 -0800 Subject: [PATCH 01/20] add setconfig.php script to set configuration options --- scripts/setconfig.php | 98 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 scripts/setconfig.php diff --git a/scripts/setconfig.php b/scripts/setconfig.php new file mode 100644 index 0000000000..b102f99b1f --- /dev/null +++ b/scripts/setconfig.php @@ -0,0 +1,98 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); + +$shortoptions = 'd'; +$longoptions = array('delete'); + +$helptext = << +With three args, set the setting to the value. +With two args, just show the setting. +With -d, delete the setting. + + [section] section to use (required) + [setting] setting to use (required) + value to set (optional) + + -d --delete delete the setting (no value) + +END_OF_SETCONFIG_HELP; + +require_once INSTALLDIR.'/scripts/commandline.inc'; + +if (count($args) < 2 || count($args) > 3) { + show_help(); + exit(1); +} + +$section = $args[0]; +$setting = $args[1]; + +if (count($args) == 3) { + $value = $args[2]; +} else { + $value = null; +} + +try { + + if (have_option('d', 'delete')) { // Delete + if (count($args) != 2) { + show_help(); + exit(1); + } + + if (have_option('v', 'verbose')) { + print "Deleting setting $section/$setting..."; + } + + $setting = Config::pkeyGet(array('section' => $section, + 'setting' => $setting)); + + if (empty($setting)) { + print "Not found.\n"; + } else { + $result = $setting->delete(); + if ($result) { + print "DONE.\n"; + } else { + print "ERROR.\n"; + } + } + } else if (count($args) == 2) { // show + if (have_option('v', 'verbose')) { + print "$section/$setting = "; + } + $value = common_config($section, $setting); + print "$value\n"; + } else { // set + if (have_option('v', 'verbose')) { + print "Setting $section/$setting..."; + } + Config::save($section, $setting, $value); + print "DONE.\n"; + } + +} catch (Exception $e) { + print $e->getMessage() . "\n"; + exit(1); +} From 7f9b07d8c9840944ea7ebf437f45e44584bcb5ee Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 24 Dec 2009 15:25:59 -0600 Subject: [PATCH 02/20] Move ssl settings from site admin panel to paths admin panel --- actions/pathsadminpanel.php | 34 ++++++++++++++++++++++++++++++++-- actions/siteadminpanel.php | 31 +------------------------------ 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/actions/pathsadminpanel.php b/actions/pathsadminpanel.php index f1a2b1b8a6..c6daa17345 100644 --- a/actions/pathsadminpanel.php +++ b/actions/pathsadminpanel.php @@ -92,7 +92,7 @@ class PathsadminpanelAction extends AdminPanelAction function saveSettings() { static $settings = array( - 'site' => array('path', 'locale_path'), + 'site' => array('path', 'locale_path', 'ssl', 'sslserver'), 'theme' => array('server', 'dir', 'path'), 'avatar' => array('server', 'dir', 'path'), 'background' => array('server', 'dir', 'path') @@ -160,6 +160,14 @@ class PathsadminpanelAction extends AdminPanelAction $this->clientError(sprintf(_("Locales directory not readable: %s"), $values['site']['locale_path'])); } + // Validate SSL setup + + if (in_array($values['site']['ssl'], array('sometimes', 'always'))) { + if (empty($values['site']['sslserver'])) { + $this->clientError(_("You must set an SSL server when enabling SSL.")); + } + } + } } @@ -283,6 +291,29 @@ class PathsAdminPanelForm extends AdminForm $this->out->elementEnd('ul'); $this->out->elementEnd('fieldset'); + + $this->out->elementStart('fieldset', array('id' => 'settings_admin_ssl')); + $this->out->element('legend', null, _('SSL')); + $this->out->elementStart('ul', 'form_data'); + $this->li(); + $ssl = array('never' => _('Never'), + 'sometimes' => _('Sometimes'), + 'always' => _('Always')); + + common_debug("site ssl = " . $this->value('site', 'ssl')); + + $this->out->dropdown('site-ssl', _('Use SSL'), + $ssl, _('When to use SSL'), + false, $this->value('ssl', 'site')); + $this->unli(); + + $this->li(); + $this->input('sslserver', _('SSL Server'), + _('Server to direct SSL requests to'), 'site'); + $this->unli(); + $this->out->elementEnd('ul'); + $this->out->elementEnd('fieldset'); + } /** @@ -297,7 +328,6 @@ class PathsAdminPanelForm extends AdminForm 'save', _('Save paths')); } - /** * Utility to simplify some of the duplicated code around * params and settings. Overriding the input() in the base class diff --git a/actions/siteadminpanel.php b/actions/siteadminpanel.php index b963336e60..f260a44760 100644 --- a/actions/siteadminpanel.php +++ b/actions/siteadminpanel.php @@ -92,8 +92,7 @@ class SiteadminpanelAction extends AdminPanelAction { static $settings = array('site' => array('name', 'broughtby', 'broughtbyurl', 'email', 'timezone', 'language', - 'ssl', 'sslserver', 'site', - 'textlimit', 'dupelimit'), + 'site', 'textlimit', 'dupelimit'), 'snapshot' => array('run', 'reporturl', 'frequency')); static $booleans = array('site' => array('private', 'inviteonly', 'closed', 'fancy')); @@ -192,14 +191,6 @@ class SiteadminpanelAction extends AdminPanelAction $this->clientError(_("Snapshot frequency must be a number.")); } - // Validate SSL setup - - if (in_array($values['site']['ssl'], array('sometimes', 'always'))) { - if (empty($values['site']['sslserver'])) { - $this->clientError(_("You must set an SSL server when enabling SSL.")); - } - } - if (mb_strlen($values['site']['sslserver']) > 255) { $this->clientError(_("Invalid SSL server. The maximum length is 255 characters.")); } @@ -376,26 +367,6 @@ class SiteAdminPanelForm extends AdminForm $this->out->elementEnd('ul'); $this->out->elementEnd('fieldset'); - $this->out->elementStart('fieldset', array('id' => 'settings_admin_ssl')); - $this->out->element('legend', null, _('SSL')); - $this->out->elementStart('ul', 'form_data'); - $this->li(); - $ssl = array('never' => _('Never'), - 'sometimes' => _('Sometimes'), - 'always' => _('Always')); - - $this->out->dropdown('ssl', _('Use SSL'), - $ssl, _('When to use SSL'), - false, $this->value('ssl', 'site')); - $this->unli(); - - $this->li(); - $this->input('sslserver', _('SSL Server'), - _('Server to direct SSL requests to')); - $this->unli(); - $this->out->elementEnd('ul'); - $this->out->elementEnd('fieldset'); - $this->out->elementStart('fieldset', array('id' => 'settings_admin_limits')); $this->out->element('legend', null, _('Limits')); $this->out->elementStart('ul', 'form_data'); From 1a462b04d7594159e90b514538ddbe3f7effd7f8 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 24 Dec 2009 16:50:28 -0600 Subject: [PATCH 03/20] Paths admin panel should not insist on an ssl server being specified, ever. --- actions/pathsadminpanel.php | 7 ++----- actions/siteadminpanel.php | 4 ---- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/actions/pathsadminpanel.php b/actions/pathsadminpanel.php index c6daa17345..d39c7c449a 100644 --- a/actions/pathsadminpanel.php +++ b/actions/pathsadminpanel.php @@ -162,12 +162,9 @@ class PathsadminpanelAction extends AdminPanelAction // Validate SSL setup - if (in_array($values['site']['ssl'], array('sometimes', 'always'))) { - if (empty($values['site']['sslserver'])) { - $this->clientError(_("You must set an SSL server when enabling SSL.")); - } + if (mb_strlen($values['site']['sslserver']) > 255) { + $this->clientError(_("Invalid SSL server. The maximum length is 255 characters.")); } - } } diff --git a/actions/siteadminpanel.php b/actions/siteadminpanel.php index f260a44760..5e29f4c191 100644 --- a/actions/siteadminpanel.php +++ b/actions/siteadminpanel.php @@ -191,10 +191,6 @@ class SiteadminpanelAction extends AdminPanelAction $this->clientError(_("Snapshot frequency must be a number.")); } - if (mb_strlen($values['site']['sslserver']) > 255) { - $this->clientError(_("Invalid SSL server. The maximum length is 255 characters.")); - } - // Validate text limit if (!Validate::number($values['site']['textlimit'], array('min' => 140))) { From 5d6b6bfd3494a7829c8fdccfdf85278811db83c8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 27 Dec 2009 11:04:53 -0800 Subject: [PATCH 04/20] admin page checks for right to review flags --- plugins/UserFlag/UserFlagPlugin.php | 12 +++++++- plugins/UserFlag/adminprofileflag.php | 43 +++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/plugins/UserFlag/UserFlagPlugin.php b/plugins/UserFlag/UserFlagPlugin.php index 75dcca4fcb..b4f9bd783e 100644 --- a/plugins/UserFlag/UserFlagPlugin.php +++ b/plugins/UserFlag/UserFlagPlugin.php @@ -43,6 +43,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { class UserFlagPlugin extends Plugin { + const REVIEWFLAGS = 'UserFlagPlugin::reviewflags'; + function onCheckSchema() { $schema = Schema::get(); @@ -138,7 +140,7 @@ class UserFlagPlugin extends Plugin function onEndShowStatusNetStyles($action) { - $action->cssLink(common_path('plugins/UserFlag/userflag.css'), + $action->cssLink(common_path('plugins/UserFlag/userflag.css'), null, 'screen, projection, tv'); return true; } @@ -148,4 +150,12 @@ class UserFlagPlugin extends Plugin $action->inlineScript('if ($(".form_entity_flag").length > 0) { SN.U.FormXHR($(".form_entity_flag")); }'); return true; } + + function onUserRightsCheck($user, $right, &$result) { + if ($right == self::REVIEWFLAGS) { + $result = $user->hasRole('moderator'); + return false; // done processing! + } + return true; // unchanged! + } } diff --git a/plugins/UserFlag/adminprofileflag.php b/plugins/UserFlag/adminprofileflag.php index 20b8086377..5d6acf0863 100644 --- a/plugins/UserFlag/adminprofileflag.php +++ b/plugins/UserFlag/adminprofileflag.php @@ -43,6 +43,8 @@ if (!defined('STATUSNET')) { class AdminprofileflagAction extends Action { + var $page = null; + /** * Take arguments for running * @@ -55,6 +57,47 @@ class AdminprofileflagAction extends Action { parent::prepare($args); + $user = common_current_user(); + + // User must be logged in. + + if (!common_logged_in()) { + $this->clientError(_('Not logged in.')); + return; + } + + $user = common_current_user(); + + // ...because they're logged in + + assert(!empty($user)); + + // It must be a "real" login, not saved cookie login + + if (!common_is_real_login()) { + // Cookie theft is too easy; we require automatic + // logins to re-authenticate before admining the site + common_set_returnto($this->selfUrl()); + if (Event::handle('RedirectToLogin', array($this, $user))) { + common_redirect(common_local_url('login'), 303); + } + } + + // User must have the right to review flags + + if (!$user->hasRight(UserFlagPlugin::REVIEWFLAGS)) { + $this->clientError(_('You cannot review profile flags.')); + return false; + } + + $page = $this->int('page'); + + if (empty($page)) { + $this->page = 1; + } else { + $this->page = $page; + } + return true; } From 4b7835caa570a27f372935fdda799dd065ae8ea4 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 27 Dec 2009 11:47:54 -0800 Subject: [PATCH 05/20] pagination works for flagged profiles --- plugins/UserFlag/adminprofileflag.php | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/plugins/UserFlag/adminprofileflag.php b/plugins/UserFlag/adminprofileflag.php index 5d6acf0863..b0888a31d7 100644 --- a/plugins/UserFlag/adminprofileflag.php +++ b/plugins/UserFlag/adminprofileflag.php @@ -43,7 +43,8 @@ if (!defined('STATUSNET')) { class AdminprofileflagAction extends Action { - var $page = null; + var $page = null; + var $profiles = null; /** * Take arguments for running @@ -90,14 +91,14 @@ class AdminprofileflagAction extends Action return false; } - $page = $this->int('page'); + $this->page = $this->trimmed('page'); - if (empty($page)) { + if (empty($this->page)) { $this->page = 1; - } else { - $this->page = $page; } + $this->profiles = $this->getProfiles(); + return true; } @@ -128,11 +129,12 @@ class AdminprofileflagAction extends Action function showContent() { - $profile = $this->getProfiles(); + $pl = new FlaggedProfileList($this->profiles, $this); - $pl = new FlaggedProfileList($profile, $this); + $cnt = $pl->show(); - $pl->show(); + $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE, + $this->page, 'adminprofileflag'); } function getProfiles() @@ -146,7 +148,12 @@ class AdminprofileflagAction extends Action $ufp->whereAdd('cleared is NULL'); $ufp->groupBy('profile_id'); - $ufp->orderBy('flag_count DESC'); + $ufp->orderBy('flag_count DESC, profile_id DESC'); + + $offset = ($this->page-1) * PROFILES_PER_PAGE; + $limit = PROFILES_PER_PAGE + 1; + + $ufp->limit($offset, $limit); $profiles = array(); From 75fbec2fa336ac9b749fa273ac5a44c2fb211623 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 07:58:33 -0800 Subject: [PATCH 06/20] Add tools to clear flags Added a form to clear all flags for a profile, when showed on adminprofileflags list. Add an action to handle the form, and a right for the action. --- plugins/UserFlag/clearflag.php | 129 +++++++++++++++++++++++++++++ plugins/UserFlag/clearflagform.php | 92 ++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 plugins/UserFlag/clearflag.php create mode 100644 plugins/UserFlag/clearflagform.php diff --git a/plugins/UserFlag/clearflag.php b/plugins/UserFlag/clearflag.php new file mode 100644 index 0000000000..58151d33ce --- /dev/null +++ b/plugins/UserFlag/clearflag.php @@ -0,0 +1,129 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2009, StatusNet, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Action to clear flags for a profile + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ + +class ClearflagAction extends ProfileFormAction +{ + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + + function prepare($args) + { + if (!parent::prepare($args)) { + return false; + } + + $user = common_current_user(); + + assert(!empty($user)); // checked above + assert(!empty($this->profile)); // checked above + + return true; + } + + /** + * Handle request + * + * Overriding the base Action's handle() here to deal check + * for Ajax and return an HXR response if necessary + * + * @param array $args $_REQUEST args; handled in prepare() + * + * @return void + */ + + function handle($args) + { + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $this->handlePost(); + if (!$this->boolean('ajax')) { + $this->returnToArgs(); + } + } + } + + /** + * Handle POST + * + * @return void + */ + + function handlePost() + { + $ufp = new User_flag_profile(); + + $result = $ufp->query('UPDATE user_flag_profile ' . + 'SET cleared = now() ' . + 'WHERE cleared is null ' . + 'AND profile_id = ' . $this->profile->id); + + if ($result == false) { + throw new ServerException(sprintf(_("Couldn't clear flags for profile '%s'."), + $this->profile->nickname)); + } + + $ufp->free(); + + if ($this->boolean('ajax')) { + $this->ajaxResults(); + } + } + + function ajaxResults() { + header('Content-Type: text/xml;charset=utf-8'); + $this->xw->startDocument('1.0', 'UTF-8'); + $this->elementStart('html'); + $this->elementStart('head'); + $this->element('title', null, _('Flags cleared')); + $this->elementEnd('head'); + $this->elementStart('body'); + $this->element('p', 'cleared', _('Cleared')); + $this->elementEnd('body'); + $this->elementEnd('html'); + } +} + diff --git a/plugins/UserFlag/clearflagform.php b/plugins/UserFlag/clearflagform.php new file mode 100644 index 0000000000..5ad6055d33 --- /dev/null +++ b/plugins/UserFlag/clearflagform.php @@ -0,0 +1,92 @@ +. + * + * @category Form + * @package StatusNet + * @author Evan Prodromou + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/form.php'; + +/** + * Form for clearing profile flags + * + * @category Form + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class ClearFlagForm extends ProfileActionForm +{ + /** + * class of the form + * Action this form provides + * + * @return string class of the form + */ + + function formClass() + { + return 'form_entity_clearflag'; + } + + /** + * Action this form provides + * + * @return string Name of the action, lowercased. + */ + + function target() + { + return 'clearflag'; + } + + /** + * Title of the form + * + * @return string Title of the form, internationalized + */ + + function title() + { + return _('Clear'); + } + + /** + * Description of the form + * + * @return string description of the form, internationalized + */ + + function description() + { + return _('Clear all flags'); + } +} From 2c2a82fda0b78422802a9d0b23afc765c2f5f52b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 08:19:22 -0800 Subject: [PATCH 07/20] add stuff for clearing flags to UserFlagPlugin --- plugins/UserFlag/UserFlagPlugin.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/plugins/UserFlag/UserFlagPlugin.php b/plugins/UserFlag/UserFlagPlugin.php index b4f9bd783e..78979ace23 100644 --- a/plugins/UserFlag/UserFlagPlugin.php +++ b/plugins/UserFlag/UserFlagPlugin.php @@ -44,6 +44,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { class UserFlagPlugin extends Plugin { const REVIEWFLAGS = 'UserFlagPlugin::reviewflags'; + const CLEARFLAGS = 'UserFlagPlugin::clearflags'; function onCheckSchema() { @@ -72,6 +73,7 @@ class UserFlagPlugin extends Plugin function onRouterInitialized($m) { $m->connect('main/flag/profile', array('action' => 'flagprofile')); + $m->connect('main/flag/clear', array('action' => 'clearflag')); $m->connect('admin/profile/flag', array('action' => 'adminprofileflag')); return true; } @@ -82,9 +84,11 @@ class UserFlagPlugin extends Plugin { case 'FlagprofileAction': case 'AdminprofileflagAction': + case 'ClearflagAction': require_once(INSTALLDIR.'/plugins/UserFlag/' . strtolower(mb_substr($cls, 0, -6)) . '.php'); return false; case 'FlagProfileForm': + case 'ClearFlagForm': require_once(INSTALLDIR.'/plugins/UserFlag/' . strtolower($cls . '.php')); return false; case 'User_flag_profile': @@ -152,10 +156,13 @@ class UserFlagPlugin extends Plugin } function onUserRightsCheck($user, $right, &$result) { - if ($right == self::REVIEWFLAGS) { + switch ($right) { + case self::REVIEWFLAGS: + case self::CLEARFLAGS: $result = $user->hasRole('moderator'); return false; // done processing! } + return true; // unchanged! } } From 85b8b35f53258a95989a8679455e0b2fd72bc5f5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 08:19:56 -0800 Subject: [PATCH 08/20] clear flags and show flaggers in adminflagprofile --- plugins/UserFlag/adminprofileflag.php | 67 +++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/plugins/UserFlag/adminprofileflag.php b/plugins/UserFlag/adminprofileflag.php index b0888a31d7..ab1a86ac4e 100644 --- a/plugins/UserFlag/adminprofileflag.php +++ b/plugins/UserFlag/adminprofileflag.php @@ -182,6 +182,8 @@ class FlaggedProfileList extends ProfileList { class FlaggedProfileListItem extends ProfileListItem { + const MAX_FLAGGERS = 5; + var $user = null; var $r2args = null; @@ -252,5 +254,70 @@ class FlaggedProfileListItem extends ProfileListItem function showClearButton() { + if ($this->user->hasRight(UserFlagPlugin::CLEARFLAGS)) { + $this->out->elementStart('li', 'entity_clear'); + $cf = new ClearFlagForm($this->out, $this->profile, $this->r2args); + $cf->show(); + $this->out->elementEnd('li'); + } + } + + function endProfile() + { + $this->showFlaggersList(); + parent::endProfile(); + } + + function showFlaggersList() + { + $flaggers = array(); + + $ufp = new User_flag_profile(); + + $ufp->selectAdd(); + $ufp->selectAdd('user_id'); + $ufp->profile_id = $this->profile->id; + $ufp->orderBy('created'); + + if ($ufp->find()) { // XXX: this should always happen + while ($ufp->fetch()) { + $user = User::staticGet('id', $ufp->user_id); + if (!empty($user)) { // XXX: this would also be unusual + $flaggers[] = clone($user); + } + } + } + + $cnt = count($flaggers); + $others = 0; + + if ($cnt > self::MAX_FLAGGERS) { + $flaggers = array_slice($flaggers, 0, self::MAX_FLAGGERS); + $others = $cnt - self::MAX_FLAGGERS; + } + + $lnks = array(); + + foreach ($flaggers as $flagger) { + + $url = common_local_url('showstream', + array('nickname' => $flagger->nickname)); + + $lnks[] = XMLStringer::estring('a', array('href' => $url, + 'class' => 'flagger'), + $flagger->nickname); + } + + if ($cnt > 0) { + $text = _('Flagged by '); + $text .= implode(', ', $lnks); + if ($others > 0) { + $text .= sprintf(_(' and %d others'), $others); + } + + $this->out->elementStart('p', array('class' => 'flaggers')); + $this->out->raw($text); + $this->out->elementEnd('p'); + } } } From ea23111a5611a3634faf3828f3f5c67867a460e3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 08:37:30 -0800 Subject: [PATCH 09/20] PHPCS-clean UserFlagPlugin --- plugins/UserFlag/UserFlagPlugin.php | 100 +++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 15 deletions(-) diff --git a/plugins/UserFlag/UserFlagPlugin.php b/plugins/UserFlag/UserFlagPlugin.php index 78979ace23..21af506a99 100644 --- a/plugins/UserFlag/UserFlagPlugin.php +++ b/plugins/UserFlag/UserFlagPlugin.php @@ -27,7 +27,7 @@ * @link http://status.net/ */ -if (!defined('STATUSNET') && !defined('LACONICA')) { +if (!defined('STATUSNET')) { exit(1); } @@ -46,6 +46,15 @@ class UserFlagPlugin extends Plugin const REVIEWFLAGS = 'UserFlagPlugin::reviewflags'; const CLEARFLAGS = 'UserFlagPlugin::clearflags'; + /** + * Hook for ensuring our tables are created + * + * Ensures that the user_flag_profile table exists + * and has the right columns. + * + * @return boolean hook return + */ + function onCheckSchema() { $schema = Schema::get(); @@ -65,40 +74,61 @@ class UserFlagPlugin extends Plugin return true; } - function onInitializePlugin() - { - // XXX: do something here? - return true; - } + /** + * Add our actions to the URL router + * + * @param Net_URL_Mapper $m URL mapper for this hit + * + * @return boolean hook return + */ - function onRouterInitialized($m) { + function onRouterInitialized($m) + { $m->connect('main/flag/profile', array('action' => 'flagprofile')); $m->connect('main/flag/clear', array('action' => 'clearflag')); $m->connect('admin/profile/flag', array('action' => 'adminprofileflag')); return true; } - function onAutoload($cls) + /** + * Auto-load our classes if called + * + * @param string $cls Class to load + * + * @return boolean hook return + */ + + function onAutoload($cls) { switch ($cls) { case 'FlagprofileAction': case 'AdminprofileflagAction': case 'ClearflagAction': - require_once(INSTALLDIR.'/plugins/UserFlag/' . strtolower(mb_substr($cls, 0, -6)) . '.php'); + include_once INSTALLDIR.'/plugins/UserFlag/' . + strtolower(mb_substr($cls, 0, -6)) . '.php'; return false; case 'FlagProfileForm': case 'ClearFlagForm': - require_once(INSTALLDIR.'/plugins/UserFlag/' . strtolower($cls . '.php')); + include_once INSTALLDIR.'/plugins/UserFlag/' . strtolower($cls . '.php'); return false; case 'User_flag_profile': - require_once(INSTALLDIR.'/plugins/UserFlag/'.$cls.'.php'); + include_once INSTALLDIR.'/plugins/UserFlag/'.$cls.'.php'; return false; default: return true; } } + /** + * Add a 'flag' button to profile page + * + * @param Action &$action The action being called + * @param Profile $profile Profile being shown + * + * @return boolean hook result + */ + function onEndProfilePageActionsElements(&$action, $profile) { $user = common_current_user(); @@ -111,8 +141,8 @@ class UserFlagPlugin extends Plugin $action->element('p', 'flagged', _('Flagged')); } else { $form = new FlagProfileForm($action, $profile, - array('action' => 'showstream', - 'nickname' => $profile->nickname)); + array('action' => 'showstream', + 'nickname' => $profile->nickname)); $form->show(); } @@ -122,6 +152,14 @@ class UserFlagPlugin extends Plugin return true; } + /** + * Add a 'flag' button to profiles in a list + * + * @param ProfileListItem $item item being shown + * + * @return boolean hook result + */ + function onEndProfileListItemActionElements($item) { $user = common_current_user(); @@ -142,6 +180,14 @@ class UserFlagPlugin extends Plugin return true; } + /** + * Add our plugin's CSS to page output + * + * @param Action $action action being shown + * + * @return boolean hook result + */ + function onEndShowStatusNetStyles($action) { $action->cssLink(common_path('plugins/UserFlag/userflag.css'), @@ -149,13 +195,37 @@ class UserFlagPlugin extends Plugin return true; } + /** + * Initialize any flagging buttons on the page + * + * @param Action $action action being shown + * + * @return boolean hook result + */ + function onEndShowScripts($action) { - $action->inlineScript('if ($(".form_entity_flag").length > 0) { SN.U.FormXHR($(".form_entity_flag")); }'); + $action->inlineScript('if ($(".form_entity_flag").length > 0) { '. + 'SN.U.FormXHR($(".form_entity_flag")); '. + '}'); return true; } - function onUserRightsCheck($user, $right, &$result) { + /** + * Check whether a user has one of our defined rights + * + * We define extra rights; this function checks to see if a + * user has one of them. + * + * @param User $user User being checked + * @param string $right Right we're checking + * @param boolean &$result out, result of the check + * + * @return boolean hook result + */ + + function onUserRightsCheck($user, $right, &$result) + { switch ($right) { case self::REVIEWFLAGS: case self::CLEARFLAGS: From c8fd5403e5bfc3b9110042eb1573904625f607e1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 08:45:21 -0800 Subject: [PATCH 10/20] PHPCS-clean adminprofileflags.php --- plugins/UserFlag/adminprofileflag.php | 99 +++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 6 deletions(-) diff --git a/plugins/UserFlag/adminprofileflag.php b/plugins/UserFlag/adminprofileflag.php index ab1a86ac4e..17374927b3 100644 --- a/plugins/UserFlag/adminprofileflag.php +++ b/plugins/UserFlag/adminprofileflag.php @@ -117,7 +117,14 @@ class AdminprofileflagAction extends Action $this->showPage(); } - function title() { + /** + * Title of this page + * + * @return string Title of the page + */ + + function title() + { return _('Flagged profiles'); } @@ -137,6 +144,12 @@ class AdminprofileflagAction extends Action $this->page, 'adminprofileflag'); } + /** + * Retrieve this action's profiles + * + * @return Profile $profile Profile query results + */ + function getProfiles() { $ufp = new User_flag_profile(); @@ -151,7 +164,7 @@ class AdminprofileflagAction extends Action $ufp->orderBy('flag_count DESC, profile_id DESC'); $offset = ($this->page-1) * PROFILES_PER_PAGE; - $limit = PROFILES_PER_PAGE + 1; + $limit = PROFILES_PER_PAGE + 1; $ufp->limit($offset, $limit); @@ -172,7 +185,27 @@ class AdminprofileflagAction extends Action } } -class FlaggedProfileList extends ProfileList { +/** + * Specialization of ProfileList to show flagging information + * + * Most of the hard part is done in FlaggedProfileListItem. + * + * @category Widget + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ + +class FlaggedProfileList extends ProfileList +{ + /** + * Factory method for creating new list items + * + * @param Profile $profile Profile to create an item for + * + * @return ProfileListItem newly-created item + */ function newListItem($profile) { @@ -180,13 +213,29 @@ class FlaggedProfileList extends ProfileList { } } +/** + * Specialization of ProfileListItem to show flagging information + * + * @category Widget + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ + class FlaggedProfileListItem extends ProfileListItem { const MAX_FLAGGERS = 5; - var $user = null; + var $user = null; var $r2args = null; + /** + * Overload parent's action list with our own moderation-oriented buttons + * + * @return void + */ + function showActions() { $this->user = common_current_user(); @@ -211,6 +260,12 @@ class FlaggedProfileListItem extends ProfileListItem $this->endActions(); } + /** + * Show a button to sandbox the profile + * + * @return void + */ + function showSandboxButton() { if ($this->user->hasRight(Right::SANDBOXUSER)) { @@ -226,6 +281,12 @@ class FlaggedProfileListItem extends ProfileListItem } } + /** + * Show a button to silence the profile + * + * @return void + */ + function showSilenceButton() { if ($this->user->hasRight(Right::SILENCEUSER)) { @@ -241,6 +302,12 @@ class FlaggedProfileListItem extends ProfileListItem } } + /** + * Show a button to delete user and profile + * + * @return void + */ + function showDeleteButton() { @@ -252,6 +319,12 @@ class FlaggedProfileListItem extends ProfileListItem } } + /** + * Show a button to clear flags + * + * @return void + */ + function showClearButton() { if ($this->user->hasRight(UserFlagPlugin::CLEARFLAGS)) { @@ -262,12 +335,24 @@ class FlaggedProfileListItem extends ProfileListItem } } + /** + * Overload parent function to add flaggers list + * + * @return void + */ + function endProfile() { $this->showFlaggersList(); parent::endProfile(); } + /** + * Show a list of people who've flagged this profile + * + * @return void + */ + function showFlaggersList() { $flaggers = array(); @@ -288,12 +373,12 @@ class FlaggedProfileListItem extends ProfileListItem } } - $cnt = count($flaggers); + $cnt = count($flaggers); $others = 0; if ($cnt > self::MAX_FLAGGERS) { $flaggers = array_slice($flaggers, 0, self::MAX_FLAGGERS); - $others = $cnt - self::MAX_FLAGGERS; + $others = $cnt - self::MAX_FLAGGERS; } $lnks = array(); @@ -310,7 +395,9 @@ class FlaggedProfileListItem extends ProfileListItem if ($cnt > 0) { $text = _('Flagged by '); + $text .= implode(', ', $lnks); + if ($others > 0) { $text .= sprintf(_(' and %d others'), $others); } From df98ddff0c6daa6a94c71be11b7db683f6181482 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 09:06:38 -0800 Subject: [PATCH 11/20] phpcs-clean clearflag.php --- plugins/UserFlag/clearflag.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/plugins/UserFlag/clearflag.php b/plugins/UserFlag/clearflag.php index 58151d33ce..bd6732e2da 100644 --- a/plugins/UserFlag/clearflag.php +++ b/plugins/UserFlag/clearflag.php @@ -89,6 +89,8 @@ class ClearflagAction extends ProfileFormAction /** * Handle POST * + * Executes the actions; deletes all flags + * * @return void */ @@ -102,8 +104,9 @@ class ClearflagAction extends ProfileFormAction 'AND profile_id = ' . $this->profile->id); if ($result == false) { - throw new ServerException(sprintf(_("Couldn't clear flags for profile '%s'."), - $this->profile->nickname)); + $msg = sprintf(_("Couldn't clear flags for profile '%s'."), + $this->profile->nickname); + throw new ServerException($msg); } $ufp->free(); @@ -113,7 +116,14 @@ class ClearflagAction extends ProfileFormAction } } - function ajaxResults() { + /** + * Return results in ajax form + * + * @return void + */ + + function ajaxResults() + { header('Content-Type: text/xml;charset=utf-8'); $this->xw->startDocument('1.0', 'UTF-8'); $this->elementStart('html'); @@ -126,4 +136,3 @@ class ClearflagAction extends ProfileFormAction $this->elementEnd('html'); } } - From 4a5bac43c33ef0006b85eb39eda10de55985d52d Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 09:08:28 -0800 Subject: [PATCH 12/20] phpcs-clean flagprofile.php --- plugins/UserFlag/flagprofile.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/plugins/UserFlag/flagprofile.php b/plugins/UserFlag/flagprofile.php index 9bce7865b8..55753f4e85 100644 --- a/plugins/UserFlag/flagprofile.php +++ b/plugins/UserFlag/flagprofile.php @@ -63,8 +63,7 @@ class FlagprofileAction extends ProfileFormAction assert(!empty($this->profile)); // checked above if (User_flag_profile::exists($this->profile->id, - $user->id)) - { + $user->id)) { $this->clientError(_('Flag already exists.')); return false; } @@ -72,7 +71,6 @@ class FlagprofileAction extends ProfileFormAction return true; } - /** * Handle request * @@ -114,8 +112,9 @@ class FlagprofileAction extends ProfileFormAction $ufp->created = common_sql_now(); if (!$ufp->insert()) { - throw new ServerException(sprintf(_("Couldn't flag profile '%s' for review."), - $this->profile->nickname)); + $msg = sprintf(_("Couldn't flag profile '%s' for review."), + $this->profile->nickname); + throw new ServerException($msg); } $ufp->free(); @@ -125,7 +124,14 @@ class FlagprofileAction extends ProfileFormAction } } - function ajaxResults() { + /** + * Return results as AJAX message + * + * @return void + */ + + function ajaxResults() + { header('Content-Type: text/xml;charset=utf-8'); $this->xw->startDocument('1.0', 'UTF-8'); $this->elementStart('html'); From a80fa178726da3ff6d06272bd06f35afbfe2f757 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 09:15:07 -0800 Subject: [PATCH 13/20] phpcs-clean User_flag_profile as best as possible --- plugins/UserFlag/User_flag_profile.php | 59 ++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/plugins/UserFlag/User_flag_profile.php b/plugins/UserFlag/User_flag_profile.php index 30bd4ae68d..b8f3f3fe16 100644 --- a/plugins/UserFlag/User_flag_profile.php +++ b/plugins/UserFlag/User_flag_profile.php @@ -1,5 +1,15 @@ + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * * StatusNet - the distributed open-source microblogging tool * Copyright (C) 2009, StatusNet, Inc. * @@ -23,6 +33,18 @@ if (!defined('STATUSNET')) { require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; +/** + * Data class for profile flags + * + * A class representing a user flagging another profile for review. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ + class User_flag_profile extends Memcached_DataObject { ###START_AUTOCODE @@ -40,7 +62,14 @@ class User_flag_profile extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - function table() { + /** + * return table definition for DB_DataObject + * + * @return array array of column definitions + */ + + function table() + { return array( 'profile_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, 'user_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, @@ -49,15 +78,39 @@ class User_flag_profile extends Memcached_DataObject ); } - function keys() { + /** + * return key definitions for DB_DataObject + * + * @return array key definitions + */ + + function keys() + { return array('profile_id' => 'N', 'user_id' => 'N'); } + /** + * Get a single object with multiple keys + * + * @param array $kv Map of key-value pairs + * + * @return User_flag_profile found object or null + */ + function &pkeyGet($kv) { return Memcached_DataObject::pkeyGet('User_flag_profile', $kv); } + /** + * Check if a flag exists for given profile and user + * + * @param integer $profile_id Profile to check for + * @param integer $user_id User to check for + * + * @return boolean true if exists, else false + */ + static function exists($profile_id, $user_id) { $ufp = User_flag_profile::pkeyGet(array('profile_id' => $profile_id, From c07f22104094d26f7f6266c2b59f7999030fda1a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 10:42:31 -0800 Subject: [PATCH 14/20] check if other user exists before unsub --- classes/User.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/classes/User.php b/classes/User.php index 484dc8c82b..6708d95b6a 100644 --- a/classes/User.php +++ b/classes/User.php @@ -625,7 +625,11 @@ class User extends Memcached_DataObject // Cancel their subscription, if it exists - subs_unsubscribe_to($other->getUser(),$this->getProfile()); + $otherUser = User::staticGet('id', $other->id); + + if (!empty($otherUser)) { + subs_unsubscribe_to($otherUser, $this->getProfile()); + } $block->query('COMMIT'); From c5de3262312f814bc44e596d9031c2df22420e27 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 10:42:55 -0800 Subject: [PATCH 15/20] events for blocking a user --- EVENTS.txt | 7 +++++++ actions/apiblockcreate.php | 13 ++++++++++--- actions/block.php | 8 ++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/EVENTS.txt b/EVENTS.txt index 96250f64c7..42aecfaf90 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -640,3 +640,10 @@ EndLog: After writing to the logs - $msg - $filename +StartBlockProfile: when we're about to block +- $user: the person doing the block +- $profile: the person getting blocked, can be remote + +EndBlockProfile: when a block has succeeded +- $user: the person doing the block +- $profile: the person blocked, can be remote diff --git a/actions/apiblockcreate.php b/actions/apiblockcreate.php index e79dec32d0..c26485f591 100644 --- a/actions/apiblockcreate.php +++ b/actions/apiblockcreate.php @@ -109,9 +109,16 @@ class ApiBlockCreateAction extends ApiAuthAction return; } - if ($this->user->hasBlocked($this->other) - || $this->user->block($this->other) - ) { + if (!$this->user->hasBlocked($this->other)) { + if (Event::handle('StartBlockProfile', array($this->user, $this->other))) { + $result = $this->user->block($this->other); + if ($result) { + Event::handle('EndBlockProfile', array($this->user, $this->other)); + } + } + } + + if ($this->user->hasBlocked($this->other)) { $this->initDocument($this->format); $this->showProfile($this->other, $this->format); $this->endDocument($this->format); diff --git a/actions/block.php b/actions/block.php index 71a34e0879..5fae45dffc 100644 --- a/actions/block.php +++ b/actions/block.php @@ -156,7 +156,12 @@ class BlockAction extends ProfileFormAction { $cur = common_current_user(); - $result = $cur->block($this->profile); + if (Event::handle('StartBlockProfile', array($cur, $this->profile))) { + $result = $cur->block($this->profile); + if ($result) { + Event::handle('EndBlockProfile', array($cur, $this->profile)); + } + } if (!$result) { $this->serverError(_('Failed to save block information.')); @@ -164,4 +169,3 @@ class BlockAction extends ProfileFormAction } } } - From 2ae04bb6d598c74763aca79ab52172934158be46 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 10:50:12 -0800 Subject: [PATCH 16/20] add events for unblocking a profile --- EVENTS.txt | 8 ++++++++ actions/apiblockdestroy.php | 13 ++++++++++--- actions/unblock.php | 13 +++++++++++-- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/EVENTS.txt b/EVENTS.txt index 42aecfaf90..64e345b692 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -647,3 +647,11 @@ StartBlockProfile: when we're about to block EndBlockProfile: when a block has succeeded - $user: the person doing the block - $profile: the person blocked, can be remote + +StartUnblockProfile: when we're about to unblock +- $user: the person doing the unblock +- $profile: the person getting unblocked, can be remote + +EndUnblockProfile: when an unblock has succeeded +- $user: the person doing the unblock +- $profile: the person unblocked, can be remote diff --git a/actions/apiblockdestroy.php b/actions/apiblockdestroy.php index 328f18ab0d..666f308f4c 100644 --- a/actions/apiblockdestroy.php +++ b/actions/apiblockdestroy.php @@ -97,9 +97,16 @@ class ApiBlockDestroyAction extends ApiAuthAction return; } - if (!$this->user->hasBlocked($this->other) - || $this->user->unblock($this->other) - ) { + if ($this->user->hasBlocked($this->other)) { + if (Event::handle('StartUnblockProfile', array($this->user, $this->other))) { + $result = $this->user->unblock($this->other); + if ($result) { + Event::handle('EndUnblockProfile', array($this->user, $this->other)); + } + } + } + + if (!$this->user->hasBlocked($this->other)) { $this->initDocument($this->format); $this->showProfile($this->other, $this->format); $this->endDocument($this->format); diff --git a/actions/unblock.php b/actions/unblock.php index c60458cd3c..0f63e1dae0 100644 --- a/actions/unblock.php +++ b/actions/unblock.php @@ -71,8 +71,17 @@ class UnblockAction extends ProfileFormAction function handlePost() { - $cur = common_current_user(); - $result = $cur->unblock($this->profile); + $cur = common_current_user(); + + $result = false; + + if (Event::handle('StartUnblockProfile', array($cur, $this->profile))) { + $result = $cur->unblock($this->profile); + if ($result) { + Event::handle('EndUnblockProfile', array($cur, $this->profile)); + } + } + if (!$result) { $this->serverError(_('Error removing the block.')); return; From 6d3e6b42849ad14b15cb4c41c4f8baac45e58df0 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 10:58:49 -0800 Subject: [PATCH 17/20] move flag creation to a method of data object --- plugins/UserFlag/User_flag_profile.php | 19 +++++++++++++++++++ plugins/UserFlag/flagprofile.php | 14 ++------------ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/plugins/UserFlag/User_flag_profile.php b/plugins/UserFlag/User_flag_profile.php index b8f3f3fe16..6582594524 100644 --- a/plugins/UserFlag/User_flag_profile.php +++ b/plugins/UserFlag/User_flag_profile.php @@ -118,4 +118,23 @@ class User_flag_profile extends Memcached_DataObject return !empty($ufp); } + + static function create($user_id, $profile_id) + { + $ufp = new User_flag_profile(); + + $ufp->profile_id = $profile_id; + $ufp->user_id = $user_id; + $ufp->created = common_sql_now(); + + if (!$ufp->insert()) { + $msg = sprintf(_("Couldn't flag profile '%d' for review."), + $profile_id); + throw new ServerException($msg); + } + + $ufp->free(); + + return true; + } } diff --git a/plugins/UserFlag/flagprofile.php b/plugins/UserFlag/flagprofile.php index 55753f4e85..2d0f0abb90 100644 --- a/plugins/UserFlag/flagprofile.php +++ b/plugins/UserFlag/flagprofile.php @@ -105,19 +105,9 @@ class FlagprofileAction extends ProfileFormAction assert(!empty($user)); assert(!empty($this->profile)); - $ufp = new User_flag_profile(); + // throws an exception on error - $ufp->profile_id = $this->profile->id; - $ufp->user_id = $user->id; - $ufp->created = common_sql_now(); - - if (!$ufp->insert()) { - $msg = sprintf(_("Couldn't flag profile '%s' for review."), - $this->profile->nickname); - throw new ServerException($msg); - } - - $ufp->free(); + User_flag_profile::create($user->id, $this->profile->id); if ($this->boolean('ajax')) { $this->ajaxResults(); From d9efeb6ac3810ef2ed7da6a274c3fc5ef1cfd5d7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 11:02:44 -0800 Subject: [PATCH 18/20] optionally flag a profile for review when blocked --- plugins/UserFlag/UserFlagPlugin.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/plugins/UserFlag/UserFlagPlugin.php b/plugins/UserFlag/UserFlagPlugin.php index 21af506a99..0fca5f9cf9 100644 --- a/plugins/UserFlag/UserFlagPlugin.php +++ b/plugins/UserFlag/UserFlagPlugin.php @@ -46,6 +46,8 @@ class UserFlagPlugin extends Plugin const REVIEWFLAGS = 'UserFlagPlugin::reviewflags'; const CLEARFLAGS = 'UserFlagPlugin::clearflags'; + public $flagOnBlock = true; + /** * Hook for ensuring our tables are created * @@ -235,4 +237,23 @@ class UserFlagPlugin extends Plugin return true; // unchanged! } + + /** + * Optionally flag profile when a block happens + * + * We optionally add a flag when a profile has been blocked + * + * @param User $user User doing the block + * @param Profile $profile Profile being blocked + * + * @return boolean hook result + */ + + function onEndBlockProfile($user, $profile) + { + if ($this->flagOnBlock) { + User_flag_profile::create($user->id, $profile->id); + } + return true; + } } From 749b8b5b8ca4d1c39d350879aadddbdb9d8b71d5 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Mon, 28 Dec 2009 12:27:28 -0800 Subject: [PATCH 19/20] Drop the Google Client API-based AJAX geolocation lookup shim -- it fails to ask for user permission, causing us quite a bit of difficulty. --- js/geometa.js | 123 ++------------------------------------------------ 1 file changed, 5 insertions(+), 118 deletions(-) diff --git a/js/geometa.js b/js/geometa.js index 21deb18852..87e3c99a16 100644 --- a/js/geometa.js +++ b/js/geometa.js @@ -1,4 +1,4 @@ -// A shim to implement the W3C Geolocation API Specification using Gears or the Ajax API +// A shim to implement the W3C Geolocation API Specification using Gears if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) (function(){ // -- BEGIN GEARS_INIT @@ -96,122 +96,9 @@ var GearsGeoLocation = (function() { }; }); -var AjaxGeoLocation = (function() { - // -- PRIVATE - var loading = false; - var loadGoogleLoader = function() { - if (!hasGoogleLoader() && !loading) { - loading = true; - var s = document.createElement('script'); - s.src = (document.location.protocol == "https:"?"https://":"http://") + 'www.google.com/jsapi?callback=_google_loader_apiLoaded'; - s.type = "text/javascript"; - document.getElementsByTagName('body')[0].appendChild(s); - } - }; - - var queue = []; - var addLocationQueue = function(callback) { - queue.push(callback); - } - - var runLocationQueue = function() { - if (hasGoogleLoader()) { - while (queue.length > 0) { - var call = queue.pop(); - call(); - } - } - } - - window['_google_loader_apiLoaded'] = function() { - runLocationQueue(); - } - - var hasGoogleLoader = function() { - return (window['google'] && google['loader']); - } - - var checkGoogleLoader = function(callback) { - if (hasGoogleLoader()) return true; - - addLocationQueue(callback); - - loadGoogleLoader(); - - return false; - }; - - loadGoogleLoader(); // start to load as soon as possible just in case - - // -- PUBLIC - return { - shim: true, - - type: "ClientLocation", - - lastPosition: null, - - getCurrentPosition: function(successCallback, errorCallback, options) { - var self = this; - if (!checkGoogleLoader(function() { - self.getCurrentPosition(successCallback, errorCallback, options); - })) return; - - if (google.loader.ClientLocation) { - var cl = google.loader.ClientLocation; - - var position = { - coords: { - latitude: cl.latitude, - longitude: cl.longitude, - altitude: null, - accuracy: 43000, // same as Gears accuracy over wifi? - altitudeAccuracy: null, - heading: null, - speed: null, - }, - // extra info that is outside of the bounds of the core API - address: { - city: cl.address.city, - country: cl.address.country, - country_code: cl.address.country_code, - region: cl.address.region - }, - timestamp: new Date() - }; - - successCallback(position); - - this.lastPosition = position; - } else if (errorCallback === "function") { - errorCallback({ code: 3, message: "Using the Google ClientLocation API and it is not able to calculate a location."}); - } - }, - - watchPosition: function(successCallback, errorCallback, options) { - this.getCurrentPosition(successCallback, errorCallback, options); - - var self = this; - var watchId = setInterval(function() { - self.getCurrentPosition(successCallback, errorCallback, options); - }, 10000); - - return watchId; - }, - - clearWatch: function(watchId) { - clearInterval(watchId); - }, - - getPermission: function(siteName, imageUrl, extraMessage) { - // for now just say yes :) - return true; - } - - }; -}); - -// If you have Gears installed use that, else use Ajax ClientLocation -navigator.geolocation = (window.google && google.gears) ? GearsGeoLocation() : AjaxGeoLocation(); +// If you have Gears installed use that +if (window.google && google.gears) { + navigator.geolocation = GearsGeoLocation(); +} })(); From dd0aaac70ec092edd38b53285ac74a4ad36e7c1e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 28 Dec 2009 12:42:22 -0800 Subject: [PATCH 20/20] First version of blacklist plugin First version of blacklist plugin. Replaces custom code in identi.ca's config.php, which was getting scary and long. Also correctly handles changed nicknames or URLs in profile settings and using 'forbidden' URLs in notice text. --- plugins/Blacklist/BlacklistPlugin.php | 203 ++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 plugins/Blacklist/BlacklistPlugin.php diff --git a/plugins/Blacklist/BlacklistPlugin.php b/plugins/Blacklist/BlacklistPlugin.php new file mode 100644 index 0000000000..655b0926b7 --- /dev/null +++ b/plugins/Blacklist/BlacklistPlugin.php @@ -0,0 +1,203 @@ +. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @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 prevent use of nicknames or URLs on a blacklist + * + * @category Plugin + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class BlacklistPlugin extends Plugin +{ + public $nicknames = array(); + public $urls = array(); + + /** + * Hook registration to prevent blacklisted homepages or nicknames + * + * Throws an exception if there's a blacklisted homepage or nickname. + * + * @param Action $action Action being called (usually register) + * + * @return boolean hook value + */ + + function onStartRegistrationTry($action) + { + $homepage = strtolower($action->trimmed('homepage')); + + if (!empty($homepage)) { + if (!$this->_checkUrl($homepage)) { + $msg = sprintf(_m("You may not register with homepage '%s'"), + $homepage); + throw new ClientException($msg); + } + } + + $nickname = strtolower($action->trimmed('nickname')); + + if (!empty($nickname)) { + if (!$this->_checkNickname($nickname)) { + $msg = sprintf(_m("You may not register with nickname '%s'"), + $nickname); + throw new ClientException($msg); + } + } + + return true; + } + + /** + * Hook profile update to prevent blacklisted homepages or nicknames + * + * Throws an exception if there's a blacklisted homepage or nickname. + * + * @param Action $action Action being called (usually register) + * + * @return boolean hook value + */ + + function onStartProfileSaveForm($action) + { + $homepage = strtolower($action->trimmed('homepage')); + + if (!empty($homepage)) { + if (!$this->_checkUrl($homepage)) { + $msg = sprintf(_m("You may not use homepage '%s'"), + $homepage); + throw new ClientException($msg); + } + } + + $nickname = strtolower($action->trimmed('nickname')); + + if (!empty($nickname)) { + if (!$this->_checkNickname($nickname)) { + $msg = sprintf(_m("You may not use nickname '%s'"), + $nickname); + throw new ClientException($msg); + } + } + + return true; + } + + /** + * Hook notice save to prevent blacklisted urls + * + * Throws an exception if there's a blacklisted url in the content. + * + * @param Notice &$notice Notice being saved + * + * @return boolean hook value + */ + + function onStartNoticeSave(&$notice) + { + common_replace_urls_callback($notice->content, + array($this, 'checkNoticeUrl')); + return true; + } + + /** + * Helper callback for notice save + * + * Throws an exception if there's a blacklisted url in the content. + * + * @param string $url URL in the notice content + * + * @return boolean hook value + */ + + function checkNoticeUrl($url) + { + // It comes in special'd, so we unspecial it + // before comparing against patterns + + $url = htmlspecialchars_decode($url); + + if (!$this->_checkUrl($url)) { + $msg = sprintf(_m("You may not use url '%s' in notices"), + $url); + throw new ClientException($msg); + } + + return $url; + } + + /** + * Helper for checking URLs + * + * Checks an URL against our patterns for a match. + * + * @param string $url URL to check + * + * @return boolean true means it's OK, false means it's bad + */ + + private function _checkUrl($url) + { + foreach ($this->urls as $pattern) { + if (preg_match("/$pattern/", $url)) { + return false; + } + } + + return true; + } + + /** + * Helper for checking nicknames + * + * Checks a nickname against our patterns for a match. + * + * @param string $nickname nickname to check + * + * @return boolean true means it's OK, false means it's bad + */ + + private function _checkNickname($nickname) + { + foreach ($this->nicknames as $pattern) { + if (preg_match("/$pattern/", $nickname)) { + return false; + } + } + + return true; + } +}