From 754b610ac4e4478cd36e5826f6bbfcad0531b7aa Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 12:04:45 -0700 Subject: added group_block table to database --- db/laconica.sql | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/db/laconica.sql b/db/laconica.sql index a11e31692..3ffe1ed81 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -482,3 +482,13 @@ create table file_to_post ( unique(file_id, post_id) ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; + +create table group_block ( + group_id integer not null comment 'group profile is blocked from' references user_group (id), + blocked integer not null comment 'profile that is blocked' references profile (id), + blocker integer not null comment 'user making the block' references user (id), + modified timestamp comment 'date of blocking', + + constraint primary key (group_id, blocked) + +) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; -- cgit v1.2.3-54-g00ecf From 85b74d846dda8781c7e713b403c1229124480d12 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 12:06:22 -0700 Subject: create DB_DataObject classes for group block --- classes/Group_block.php | 23 +++++++++++++++++++++++ classes/laconica.ini | 11 +++++++++++ 2 files changed, 34 insertions(+) create mode 100755 classes/Group_block.php mode change 100644 => 100755 classes/laconica.ini diff --git a/classes/Group_block.php b/classes/Group_block.php new file mode 100755 index 000000000..437046a9c --- /dev/null +++ b/classes/Group_block.php @@ -0,0 +1,23 @@ + Date: Sun, 14 Jun 2009 12:07:12 -0700 Subject: fix perms on Group_block classes --- classes/Group_block.php | 0 classes/laconica.ini | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 classes/Group_block.php mode change 100755 => 100644 classes/laconica.ini diff --git a/classes/Group_block.php b/classes/Group_block.php old mode 100755 new mode 100644 diff --git a/classes/laconica.ini b/classes/laconica.ini old mode 100755 new mode 100644 -- cgit v1.2.3-54-g00ecf From b6dee88e5d0a0ed58391ccb8868f4afbf631342a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 15:08:00 -0700 Subject: add UI for blocking a user from a group --- actions/groupmembers.php | 170 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 2 deletions(-) diff --git a/actions/groupmembers.php b/actions/groupmembers.php index 53fee3129..079dad9e9 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -139,14 +139,180 @@ class GroupmembersAction extends Action } } -class GroupMemberList extends ProfileList { +class GroupMemberList extends ProfileList +{ + var $group = null; + + function __construct($profile, $group, $action) + { + parent::__construct($profile, $action); + + $this->group = $group; + } + + function newListItem($profile) + { + return new GroupMemberListItem($profile, $this->group, $this->action); + } +} +class GroupMemberListItem extends ProfileListItem +{ var $group = null; - function __construct($profile, $group=null, $action=null) + function __construct($profile, $group, $action) { parent::__construct($profile, $action); $this->group = $group; } + + function showActions() + { + $this->startActions(); + $this->showSubscribeButton(); + $this->showGroupBlockForm(); + $this->endActions(); + } + + function showGroupBlockForm() + { + $user = common_current_user(); + + if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group)) { + $bf = new GroupBlockForm($this->out, $this->profile, + array('action' => 'groupmembers', + 'nickname' => $this->group->nickname)); + $bf->show(); + } + + } +} + +/** + * Form for blocking a user from a group + * + * @category Form + * @package Laconica + * @author Evan Prodromou + * @author Sarven Capadisli + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see BlockForm + */ + +class GroupBlockForm extends Form +{ + /** + * Profile of user to block + */ + + var $profile = null; + + /** + * Group to block the user from + */ + + var $group = null; + + /** + * Return-to args + */ + + var $args = null; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param Profile $profile profile of user to block + * @param User_group $group group to block user from + * @param array $args return-to args + */ + + function __construct($out=null, $profile=null, $group=null, $args=null) + { + parent::__construct($out); + + $this->profile = $profile; + $this->group = $group; + $this->args = $args; + } + + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + // This should be unique for the page. + return 'block-' . $this->profile->id; + } + + /** + * class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_group_block'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('groupblock'); + } + + /** + * Legend of the Form + * + * @return void + */ + function formLegend() + { + $this->out->element('legend', null, _('Block user from group')); + } + + /** + * Data elements of the form + * + * @return void + */ + + function formData() + { + $this->out->hidden('blockto-' . $this->profile->id, + $this->profile->id, + 'blockto'); + $this->out->hidden('blockgroup-' . $this->group->id, + $this->group->id, + 'blockgroup'); + if ($this->args) { + foreach ($this->args as $k => $v) { + $this->out->hidden('returnto-' . $k, $v); + } + } + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Block'), 'submit', null, _('Block this user')); + } } -- cgit v1.2.3-54-g00ecf From d3a0c524cce9be65b8e45280168cf3584a60f81c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 15:40:42 -0700 Subject: Make group block work --- actions/groupblock.php | 215 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 actions/groupblock.php diff --git a/actions/groupblock.php b/actions/groupblock.php new file mode 100644 index 000000000..93662da79 --- /dev/null +++ b/actions/groupblock.php @@ -0,0 +1,215 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + * + * Laconica - a distributed open-source microblogging tool + * Copyright (C) 2008, Controlez-Vous, 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('LACONICA')) { + exit(1); +} + +/** + * Block a user from a group + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + */ + +class GroupblockAction extends Action +{ + var $profile = null; + var $group = null; + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + + function prepare($args) + { + parent::prepare($args); + if (!common_logged_in()) { + $this->clientError(_('Not logged in.')); + return false; + } + $token = $this->trimmed('token'); + if (empty($token) || $token != common_session_token()) { + $this->clientError(_('There was a problem with your session token. Try again, please.')); + return; + } + $id = $this->trimmed('blockto'); + if (empty($id)) { + $this->clientError(_('No profile specified.')); + return false; + } + $this->profile = Profile::staticGet('id', $id); + if (empty($this->profile)) { + $this->clientError(_('No profile with that ID.')); + return false; + } + $group_id = $this->trimmed('blockgroup'); + if (empty($group_id)) { + $this->clientError(_('No group specified.')); + return false; + } + $this->group = User_group::staticGet('id', $group_id); + if (empty($this->group)) { + $this->clientError(_('No such group.')); + return false; + } + $user = common_current_user(); + if (!$user->isAdmin($this->group)) { + $this->clientError(_('Only an admin can block group members.'), 401); + return false; + } + if (Group_block::isBlocked($this->group, $this->profile)) { + $this->clientError(_('User is already blocked from group.')); + return false; + } + // XXX: could have proactive blocks, but we don't have UI for it. + if (!$this->profile->isMember($this->group)) { + $this->clientError(_('User is not a member of group.')); + return false; + } + return true; + } + + /** + * Handle request + * + * Shows a page with list of favorite notices + * + * @param array $args $_REQUEST args; handled in prepare() + * + * @return void + */ + function handle($args) + { + parent::handle($args); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + if ($this->arg('no')) { + common_redirect(common_local_url('groupmembers', + array('nickname' => $this->group->nickname)), + 303); + } elseif ($this->arg('yes')) { + $this->blockProfile(); + } elseif ($this->arg('blockto')) { + $this->showPage(); + } + } + } + + function showContent() { + $this->areYouSureForm(); + } + + function title() { + return _('Block user from group'); + } + + function showNoticeForm() { + // nop + } + + /** + * Confirm with user. + * + * Shows a confirmation form. + * + * @return void + */ + + function areYouSureForm() + { + $id = $this->profile->id; + $this->element('p', null, + sprintf(_('Are you sure you want to block user "%s" from the group "%s"? '. + 'They will be removed from the group, unable to post, and '. + 'unable to subscribe to the group in the future.'), + $this->profile->getBestName(), + $this->group->getBestName())); + $this->elementStart('form', array('id' => 'block-' . $id, + 'method' => 'post', + 'class' => 'block', + 'action' => common_local_url('groupblock'))); + $this->hidden('token', common_session_token()); + $this->hidden('blockto-' . $this->profile->id, + $this->profile->id, + 'blockto'); + $this->hidden('blockgroup-' . $this->group->id, + $this->group->id, + 'blockgroup'); + foreach ($this->args as $k => $v) { + if (substr($k, 0, 9) == 'returnto-') { + $this->hidden($k, $v); + } + } + $this->submit('no', _('No')); + $this->submit('yes', _('Yes')); + $this->elementEnd('form'); + } + + /** + * Actually block a user. + * + * @return void + */ + + function blockProfile() + { + $block = Group_block::blockProfile($this->group, $this->profile, + common_current_user()); + + if (empty($block)) { + $this->serverError(_("Database error blocking user from group.")); + return false; + } + + // Now, gotta figure where we go back to + foreach ($this->args as $k => $v) { + if ($k == 'returnto-action') { + $action = $v; + } elseif (substr($k, 0, 9) == 'returnto-') { + $args[substr($k, 9)] = $v; + } + } + + if ($action) { + common_redirect(common_local_url($action, $args), 303); + } else { + common_redirect(common_local_url('groupmembers', + array('nickname' => $this->group->nickname)), + 303); + } + } +} + -- cgit v1.2.3-54-g00ecf From 1c87532912b63effc047da2913e55a6551d8f629 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 15:47:39 -0700 Subject: The rest of the things necessary to make group block work Link to the group block form. Hide join button if the current user is blocked. --- actions/groupmembers.php | 2 +- actions/joingroup.php | 5 ++++ actions/showgroup.php | 2 +- classes/Group_block.php | 76 ++++++++++++++++++++++++++++++++++++++++++++++-- classes/User_group.php | 5 ++++ lib/grouplist.php | 2 +- lib/router.php | 8 ++--- 7 files changed, 91 insertions(+), 9 deletions(-) diff --git a/actions/groupmembers.php b/actions/groupmembers.php index 079dad9e9..150b60a54 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -180,7 +180,7 @@ class GroupMemberListItem extends ProfileListItem $user = common_current_user(); if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group)) { - $bf = new GroupBlockForm($this->out, $this->profile, + $bf = new GroupBlockForm($this->out, $this->profile, $this->group, array('action' => 'groupmembers', 'nickname' => $this->group->nickname)); $bf->show(); diff --git a/actions/joingroup.php b/actions/joingroup.php index a5d82ddc7..0e4f96eaf 100644 --- a/actions/joingroup.php +++ b/actions/joingroup.php @@ -96,6 +96,11 @@ class JoingroupAction extends Action return false; } + if (Group_block::isBlocked($this->group, $cur->getProfile())) { + $this->clientError(_('You have been blocked from that group by the admin.'), 403); + return false; + } + return true; } diff --git a/actions/showgroup.php b/actions/showgroup.php index 3ce45adc6..537f09278 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -283,7 +283,7 @@ class ShowgroupAction extends Action if ($cur->isMember($this->group)) { $lf = new LeaveForm($this, $this->group); $lf->show(); - } else { + } else if (!Group_block::isBlocked($this->group, $cur->getProfile())) { $jf = new JoinForm($this, $this->group); $jf->show(); } diff --git a/classes/Group_block.php b/classes/Group_block.php index 437046a9c..d945fd57a 100644 --- a/classes/Group_block.php +++ b/classes/Group_block.php @@ -1,10 +1,29 @@ . */ -require_once 'classes/Memcached_DataObject'; -class Group_block extends Memcached_DataObject +if (!defined('LACONICA')) { exit(1); } + +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; + +class Group_block extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -20,4 +39,57 @@ class Group_block extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + function &pkeyGet($kv) + { + return Memcached_DataObject::pkeyGet('Group_block', $kv); + } + + static function isBlocked($group, $profile) + { + $block = Group_block::pkeyGet(array('group_id' => $group->id, + 'blocked' => $profile->id)); + return !empty($block); + } + + static function blockProfile($group, $profile, $blocker) + { + // Insert the block + + $block = new Group_block(); + + $block->query('BEGIN'); + + $block->group_id = $group->id; + $block->blocked = $profile->id; + $block->blocker = $blocker->id; + + $result = $block->insert(); + + if (!$result) { + common_log_db_error($block, 'INSERT', __FILE__); + return null; + } + + // Delete membership if any + + $member = new Group_member(); + + $member->group_id = $group->id; + $member->profile_id = $profile->id; + + if ($member->find(true)) { + $result = $member->delete(); + if (!$result) { + common_log_db_error($member, 'DELETE', __FILE__); + return null; + } + } + + // Commit, since both have been done + + $block->query('COMMIT'); + + return $block; + } } diff --git a/classes/User_group.php b/classes/User_group.php index a135015ba..1be34b60b 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -137,4 +137,9 @@ class User_group extends Memcached_DataObject common_debug(common_log_objstring($this)); return $this->update($orig); } + + function getBestName() + { + return ($this->fullname) ? $this->fullname : $this->nickname; + } } diff --git a/lib/grouplist.php b/lib/grouplist.php index 1b8547499..1ded5160b 100644 --- a/lib/grouplist.php +++ b/lib/grouplist.php @@ -166,7 +166,7 @@ class GroupList extends Widget if ($user->isMember($this->group)) { $lf = new LeaveForm($this->out, $this->group); $lf->show(); - } else { + } else if (!Group_block::isBlocked($this->group, $user->getProfile())) { $jf = new JoinForm($this->out, $this->group); $jf->show(); } diff --git a/lib/router.php b/lib/router.php index 456d1793e..469d9a171 100644 --- a/lib/router.php +++ b/lib/router.php @@ -101,7 +101,7 @@ class Router $main = array('login', 'logout', 'register', 'subscribe', 'unsubscribe', 'confirmaddress', 'recoverpassword', 'invite', 'favor', 'disfavor', 'sup', - 'block', 'subedit'); + 'block', 'subedit', 'groupblock'); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); @@ -164,10 +164,10 @@ class Router array('action' => 'newnotice'), array('replyto' => '[A-Za-z0-9_-]+')); - $m->connect('notice/:notice/file', - array('action' => 'file'), + $m->connect('notice/:notice/file', + array('action' => 'file'), array('notice' => '[0-9]+')); - + $m->connect('notice/:notice', array('action' => 'shownotice'), array('notice' => '[0-9]+')); -- cgit v1.2.3-54-g00ecf From 203a5aba67c3bd9e2848d90b1778240b387aeda3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 15:54:22 -0700 Subject: Some UI improvements for blocking and unblocking Add unblock to the router table, so unblocking will work at all. Block form and unblock form return to subscribers list, not subscriptions list, by default. showstream action sends its parameters to block and unblock forms to better return to the right page. --- actions/block.php | 2 +- actions/showstream.php | 8 ++++++-- actions/unblock.php | 2 +- lib/router.php | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/actions/block.php b/actions/block.php index 34f991dc6..0efee5932 100644 --- a/actions/block.php +++ b/actions/block.php @@ -180,7 +180,7 @@ class BlockAction extends Action if ($action) { common_redirect(common_local_url($action, $args), 303); } else { - common_redirect(common_local_url('subscriptions', + common_redirect(common_local_url('subscribers', array('nickname' => $cur->nickname)), 303); } diff --git a/actions/showstream.php b/actions/showstream.php index c1a2c337a..641228bc7 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -308,10 +308,14 @@ class ShowstreamAction extends ProfileAction $blocked = $cur->hasBlocked($this->profile); $this->elementStart('li', 'entity_block'); if ($blocked) { - $ubf = new UnblockForm($this, $this->profile); + $ubf = new UnblockForm($this, $this->profile, + array('action' => 'showstream', + 'nickname' => $this->profile->nickname)); $ubf->show(); } else { - $bf = new BlockForm($this, $this->profile); + $bf = new BlockForm($this, $this->profile, + array('action' => 'showstream', + 'nickname' => $this->profile->nickname)); $bf->show(); } $this->elementEnd('li'); diff --git a/actions/unblock.php b/actions/unblock.php index 8573b2a87..6e671c9dd 100644 --- a/actions/unblock.php +++ b/actions/unblock.php @@ -118,7 +118,7 @@ class UnblockAction extends Action if ($action) { common_redirect(common_local_url($action, $args), 303); } else { - common_redirect(common_local_url('subscriptions', + common_redirect(common_local_url('subscribers', array('nickname' => $cur->nickname)), 303); } diff --git a/lib/router.php b/lib/router.php index 12590b790..748966567 100644 --- a/lib/router.php +++ b/lib/router.php @@ -101,7 +101,7 @@ class Router $main = array('login', 'logout', 'register', 'subscribe', 'unsubscribe', 'confirmaddress', 'recoverpassword', 'invite', 'favor', 'disfavor', 'sup', - 'block', 'subedit'); + 'block', 'unblock', 'subedit'); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); -- cgit v1.2.3-54-g00ecf From f8da15bf41b07a46b1fbe5323e2b8136d42c5b31 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 14 Jun 2009 16:17:44 -0700 Subject: Allow users to be unblocked from a group List users who are blocked from joining a group. Add a form to let them be unblocked. Add an action that removes the block. Includes changes to group and groupblock classes. --- actions/blockedfromgroup.php | 313 +++++++++++++++++++++++++++++++++++++++++++ actions/groupunblock.php | 149 ++++++++++++++++++++ classes/Group_block.php | 20 +++ classes/User_group.php | 23 ++++ lib/groupnav.php | 6 + lib/router.php | 7 +- 6 files changed, 517 insertions(+), 1 deletion(-) create mode 100644 actions/blockedfromgroup.php create mode 100644 actions/groupunblock.php diff --git a/actions/blockedfromgroup.php b/actions/blockedfromgroup.php new file mode 100644 index 000000000..1b7b31784 --- /dev/null +++ b/actions/blockedfromgroup.php @@ -0,0 +1,313 @@ +. + * + * @category Group + * @package Laconica + * @author Evan Prodromou + * @copyright 2008-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('LACONICA')) { + exit(1); +} + +/** + * List of profiles blocked from this group + * + * @category Group + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class BlockedfromgroupAction extends Action +{ + var $page = null; + + function isReadOnly($args) + { + return true; + } + + function prepare($args) + { + parent::prepare($args); + $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; + + $nickname_arg = $this->arg('nickname'); + $nickname = common_canonical_nickname($nickname_arg); + + // Permanent redirect on non-canonical nickname + + if ($nickname_arg != $nickname) { + $args = array('nickname' => $nickname); + if ($this->page != 1) { + $args['page'] = $this->page; + } + common_redirect(common_local_url('blockedfromgroup', $args), 301); + return false; + } + + if (!$nickname) { + $this->clientError(_('No nickname'), 404); + return false; + } + + $this->group = User_group::staticGet('nickname', $nickname); + + if (!$this->group) { + $this->clientError(_('No such group'), 404); + return false; + } + + return true; + } + + function title() + { + if ($this->page == 1) { + return sprintf(_('%s blocked profiles'), + $this->group->nickname); + } else { + return sprintf(_('%s blocked profiles, page %d'), + $this->group->nickname, + $this->page); + } + } + + function handle($args) + { + parent::handle($args); + $this->showPage(); + } + + function showPageNotice() + { + $this->element('p', 'instructions', + _('A list of the users blocked from joining this group.')); + } + + function showLocalNav() + { + $nav = new GroupNav($this, $this->group); + $nav->show(); + } + + function showContent() + { + $offset = ($this->page-1) * PROFILES_PER_PAGE; + $limit = PROFILES_PER_PAGE + 1; + + $cnt = 0; + + $blocked = $this->group->getBlocked($offset, $limit); + + if ($blocked) { + $blocked_list = new GroupBlockList($blocked, $this->group, $this); + $cnt = $blocked_list->show(); + } + + $blocked->free(); + + $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE, + $this->page, 'blockedfromgroup', + array('nickname' => $this->group->nickname)); + } +} + +class GroupBlockList extends ProfileList +{ + var $group = null; + + function __construct($profile, $group, $action) + { + parent::__construct($profile, $action); + + $this->group = $group; + } + + function newListItem($profile) + { + return new GroupBlockListItem($profile, $this->group, $this->action); + } +} + +class GroupBlockListItem extends ProfileListItem +{ + var $group = null; + + function __construct($profile, $group, $action) + { + parent::__construct($profile, $action); + + $this->group = $group; + } + + function showActions() + { + $this->startActions(); + $this->showGroupUnblockForm(); + $this->endActions(); + } + + function showGroupUnblockForm() + { + $user = common_current_user(); + + if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group)) { + $bf = new GroupUnblockForm($this->out, $this->profile, $this->group, + array('action' => 'blockedfromgroup', + 'nickname' => $this->group->nickname)); + $bf->show(); + } + } +} + +/** + * Form for unblocking a user from a group + * + * @category Form + * @package Laconica + * @author Evan Prodromou + * @author Sarven Capadisli + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see UnblockForm + */ + +class GroupUnblockForm extends Form +{ + /** + * Profile of user to block + */ + + var $profile = null; + + /** + * Group to block the user from + */ + + var $group = null; + + /** + * Return-to args + */ + + var $args = null; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param Profile $profile profile of user to block + * @param User_group $group group to block user from + * @param array $args return-to args + */ + + function __construct($out=null, $profile=null, $group=null, $args=null) + { + parent::__construct($out); + + $this->profile = $profile; + $this->group = $group; + $this->args = $args; + } + + /** + * ID of the form + * + * @return int ID of the form + */ + + function id() + { + // This should be unique for the page. + return 'unblock-' . $this->profile->id; + } + + /** + * class of the form + * + * @return string class of the form + */ + + function formClass() + { + return 'form_group_unblock'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + + function action() + { + return common_local_url('groupunblock'); + } + + /** + * Legend of the Form + * + * @return void + */ + function formLegend() + { + $this->out->element('legend', null, _('Unblock user from group')); + } + + /** + * Data elements of the form + * + * @return void + */ + + function formData() + { + $this->out->hidden('unblockto-' . $this->profile->id, + $this->profile->id, + 'unblockto'); + $this->out->hidden('unblockgroup-' . $this->group->id, + $this->group->id, + 'unblockgroup'); + if ($this->args) { + foreach ($this->args as $k => $v) { + $this->out->hidden('returnto-' . $k, $v); + } + } + } + + /** + * Action elements + * + * @return void + */ + + function formActions() + { + $this->out->submit('submit', _('Unblock'), 'submit', null, _('Unblock this user')); + } +} diff --git a/actions/groupunblock.php b/actions/groupunblock.php new file mode 100644 index 000000000..a0bcb01f9 --- /dev/null +++ b/actions/groupunblock.php @@ -0,0 +1,149 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + * + * Laconica - a distributed open-source microblogging tool + * Copyright (C) 2008, Controlez-Vous, 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('LACONICA')) { + exit(1); +} + +/** + * Unlock a user from a group + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + */ + +class GroupunblockAction extends Action +{ + var $profile = null; + var $group = null; + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + + function prepare($args) + { + parent::prepare($args); + if (!common_logged_in()) { + $this->clientError(_('Not logged in.')); + return false; + } + $token = $this->trimmed('token'); + if (empty($token) || $token != common_session_token()) { + $this->clientError(_('There was a problem with your session token. Try again, please.')); + return; + } + $id = $this->trimmed('unblockto'); + if (empty($id)) { + $this->clientError(_('No profile specified.')); + return false; + } + $this->profile = Profile::staticGet('id', $id); + if (empty($this->profile)) { + $this->clientError(_('No profile with that ID.')); + return false; + } + $group_id = $this->trimmed('unblockgroup'); + if (empty($group_id)) { + $this->clientError(_('No group specified.')); + return false; + } + $this->group = User_group::staticGet('id', $group_id); + if (empty($this->group)) { + $this->clientError(_('No such group.')); + return false; + } + $user = common_current_user(); + if (!$user->isAdmin($this->group)) { + $this->clientError(_('Only an admin can unblock group members.'), 401); + return false; + } + if (!Group_block::isBlocked($this->group, $this->profile)) { + $this->clientError(_('User is not blocked from group.')); + return false; + } + return true; + } + + /** + * Handle request + * + * @param array $args $_REQUEST args; handled in prepare() + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $this->unblockProfile(); + } + } + + /** + * Unblock a user. + * + * @return void + */ + + function unblockProfile() + { + $result = Group_block::unblockProfile($this->group, $this->profile); + + if (!$result) { + $this->serverError(_('Error removing the block.')); + return; + } + + foreach ($this->args as $k => $v) { + if ($k == 'returnto-action') { + $action = $v; + } else if (substr($k, 0, 9) == 'returnto-') { + $args[substr($k, 9)] = $v; + } + } + + if ($action) { + common_redirect(common_local_url($action, $args), 303); + } else { + common_redirect(common_local_url('blockedfromgroup', + array('nickname' => $this->group->nickname)), + 303); + } + } +} + diff --git a/classes/Group_block.php b/classes/Group_block.php index d945fd57a..4c583d8e2 100644 --- a/classes/Group_block.php +++ b/classes/Group_block.php @@ -92,4 +92,24 @@ class Group_block extends Memcached_DataObject return $block; } + + static function unblockProfile($group, $profile) + { + $block = Group_block::pkeyGet(array('group_id' => $group->id, + 'blocked' => $profile->id)); + + if (empty($block)) { + return null; + } + + $result = $block->delete(); + + if (!$result) { + common_log_db_error($block, 'DELETE', __FILE__); + return null; + } + + return true; + } + } diff --git a/classes/User_group.php b/classes/User_group.php index 1be34b60b..9f9977755 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -125,6 +125,29 @@ class User_group extends Memcached_DataObject return $members; } + function getBlocked($offset=0, $limit=null) + { + $qry = + 'SELECT profile.* ' . + 'FROM profile JOIN group_block '. + 'ON profile.id = group_block.blocked ' . + 'WHERE group_block.group_id = %d ' . + 'ORDER BY group_block.modified DESC '; + + if ($limit != null) { + if (common_config('db','type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } + } + + $blocked = new Profile(); + + $blocked->query(sprintf($qry, $this->id)); + return $blocked; + } + function setOriginal($filename) { $imagefile = new ImageFile($this->id, Avatar::path($filename)); diff --git a/lib/groupnav.php b/lib/groupnav.php index 90bdc1014..194247982 100644 --- a/lib/groupnav.php +++ b/lib/groupnav.php @@ -95,6 +95,12 @@ class GroupNav extends Widget $cur = common_current_user(); if ($cur && $cur->isAdmin($this->group)) { + $this->out->menuItem(common_local_url('blockedfromgroup', array('nickname' => + $nickname)), + _('Blocked'), + sprintf(_('%s blocked users'), $nickname), + $action_name == 'blockedfromgroup', + 'nav_group_blocked'); $this->out->menuItem(common_local_url('editgroup', array('nickname' => $nickname)), _('Admin'), diff --git a/lib/router.php b/lib/router.php index 3d870e565..e10871bc0 100644 --- a/lib/router.php +++ b/lib/router.php @@ -101,7 +101,8 @@ class Router $main = array('login', 'logout', 'register', 'subscribe', 'unsubscribe', 'confirmaddress', 'recoverpassword', 'invite', 'favor', 'disfavor', 'sup', - 'block', 'unblock', 'subedit', 'groupblock'); + 'block', 'unblock', 'subedit', + 'groupblock', 'groupunblock'); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); @@ -228,6 +229,10 @@ class Router array('nickname' => '[a-zA-Z0-9]+')); } + $m->connect('group/:nickname/blocked', + array('action' => 'blockedfromgroup'), + array('nickname' => '[a-zA-Z0-9]+')); + $m->connect('group/:id/id', array('action' => 'groupbyid'), array('id' => '[0-9]+')); -- cgit v1.2.3-54-g00ecf