diff --git a/actions/groupqueue.php b/actions/groupqueue.php new file mode 100644 index 0000000000..aa745f7384 --- /dev/null +++ b/actions/groupqueue.php @@ -0,0 +1,529 @@ +. + * + * @category Group + * @package StatusNet + * @author Evan Prodromou + * @copyright 2008-2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once(INSTALLDIR.'/lib/profilelist.php'); +require_once INSTALLDIR.'/lib/publicgroupnav.php'; + +/** + * List of group members + * + * @category Group + * @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 GroupqueueAction extends GroupDesignAction +{ + var $page = null; + + function isReadOnly($args) + { + return true; + } + + // fixme most of this belongs in a base class, sounds common to most group actions? + 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('groupqueue', $args), 301); + return false; + } + + if (!$nickname) { + // TRANS: Client error displayed when trying to view group members without providing a group nickname. + $this->clientError(_('No nickname.'), 404); + return false; + } + + $local = Local_group::staticGet('nickname', $nickname); + + if (!$local) { + // TRANS: Client error displayed when trying to view group members for a non-existing group. + $this->clientError(_('No such group.'), 404); + return false; + } + + $this->group = User_group::staticGet('id', $local->group_id); + + if (!$this->group) { + // TRANS: Client error displayed when trying to view group members for an object that is not a group. + $this->clientError(_('No such group.'), 404); + return false; + } + + return true; + } + + function title() + { + if ($this->page == 1) { + // TRANS: Title of the page showing pending group members still awaiting approval to join the group. + // TRANS: %s is the name of the group. + return sprintf(_('%s group members awaiting approval'), + $this->group->nickname); + } else { + // TRANS: Title of the page showing pending group members still awaiting approval to join the group. + // TRANS: %1$s is the name of the group, %2$d is the page number of the members list. + return sprintf(_('%1$s group members awaiting approval, page %2$d'), + $this->group->nickname, + $this->page); + } + } + + function handle($args) + { + parent::handle($args); + $this->showPage(); + } + + function showPageNotice() + { + $this->element('p', 'instructions', + // TRANS: Page notice for group members page. + _('A list of users awaiting approval to join this group.')); + } + + function showObjectNav() + { + $nav = new GroupNav($this, $this->group); + $nav->show(); + } + + function showContent() + { + $offset = ($this->page-1) * PROFILES_PER_PAGE; + $limit = PROFILES_PER_PAGE + 1; + + $cnt = 0; + + $members = $this->group->getRequests($offset, $limit); + + if ($members) { + // @fixme change! + $member_list = new GroupMemberList($members, $this->group, $this); + $cnt = $member_list->show(); + } + + $members->free(); + + $this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE, + $this->page, 'groupmembers', + array('nickname' => $this->group->nickname)); + } +} + +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, $action) + { + parent::__construct($profile, $action); + + $this->group = $group; + } + + function showFullName() + { + parent::showFullName(); + if ($this->profile->isAdmin($this->group)) { + $this->out->text(' '); // for separating the classes. + // TRANS: Indicator in group members list that this user is a group administrator. + $this->out->element('span', 'role', _('Admin')); + } + } + + function showActions() + { + $this->startActions(); + if (Event::handle('StartProfileListItemActionElements', array($this))) { + $this->showSubscribeButton(); + $this->showMakeAdminForm(); + $this->showGroupBlockForm(); + Event::handle('EndProfileListItemActionElements', array($this)); + } + $this->endActions(); + } + + function showMakeAdminForm() + { + $user = common_current_user(); + + if (!empty($user) && + $user->id != $this->profile->id && + ($user->isAdmin($this->group) || $user->hasRight(Right::MAKEGROUPADMIN)) && + !$this->profile->isAdmin($this->group)) { + $this->out->elementStart('li', 'entity_make_admin'); + $maf = new MakeAdminForm($this->out, $this->profile, $this->group, + $this->returnToArgs()); + $maf->show(); + $this->out->elementEnd('li'); + } + + } + + function showGroupBlockForm() + { + $user = common_current_user(); + + if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group)) { + $this->out->elementStart('li', 'entity_block'); + $bf = new GroupBlockForm($this->out, $this->profile, $this->group, + $this->returnToArgs()); + $bf->show(); + $this->out->elementEnd('li'); + } + } + + function linkAttributes() + { + $aAttrs = parent::linkAttributes(); + + if (common_config('nofollow', 'members')) { + $aAttrs['rel'] .= ' nofollow'; + } + + return $aAttrs; + } + + function homepageAttributes() + { + $aAttrs = parent::linkAttributes(); + + if (common_config('nofollow', 'members')) { + $aAttrs['rel'] = 'nofollow'; + } + + return $aAttrs; + } + + /** + * Fetch necessary return-to arguments for the profile forms + * to return to this list when they're done. + * + * @return array + */ + protected function returnToArgs() + { + $args = array('action' => 'groupmembers', + 'nickname' => $this->group->nickname); + $page = $this->out->arg('page'); + if ($page) { + $args['param-page'] = $page; + } + return $args; + } +} + +/** + * Form for blocking a user from a group + * + * @category Form + * @package StatusNet + * @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://status.net/ + * + * @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() + { + // TRANS: Form legend for form to block user from a group. + $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', + // TRANS: Button text for the form that will block a user from a group. + _m('BUTTON','Block'), + 'submit', + null, + // TRANS: Submit button title. + _m('TOOLTIP', 'Block this user')); + } +} + +/** + * Form for making a user an admin for a group + * + * @category Form + * @package StatusNet + * @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://status.net/ + */ +class MakeAdminForm 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 'makeadmin-' . $this->profile->id; + } + + /** + * class of the form + * + * @return string class of the form + */ + function formClass() + { + return 'form_make_admin'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + function action() + { + return common_local_url('makeadmin', array('nickname' => $this->group->nickname)); + } + + /** + * Legend of the Form + * + * @return void + */ + function formLegend() + { + // TRANS: Form legend for form to make a user a group admin. + $this->out->element('legend', null, _('Make user an admin of the group')); + } + + /** + * Data elements of the form + * + * @return void + */ + function formData() + { + $this->out->hidden('profileid-' . $this->profile->id, + $this->profile->id, + 'profileid'); + $this->out->hidden('groupid-' . $this->group->id, + $this->group->id, + 'groupid'); + 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', + // TRANS: Button text for the form that will make a user administrator. + _m('BUTTON','Make Admin'), + 'submit', + null, + // TRANS: Submit button title. + _m('TOOLTIP','Make this user an admin')); + } +} diff --git a/classes/User_group.php b/classes/User_group.php index 11efe8d3af..c044594f1f 100644 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -153,6 +153,36 @@ class User_group extends Memcached_DataObject return $members; } + /** + * Get pending members, who have not yet been approved. + * + * @param int $offset + * @param int $limit + * @return Profile + */ + function getRequests($offset=0, $limit=null) + { + $qry = + 'SELECT profile.* ' . + 'FROM profile JOIN group_join_queue '. + 'ON profile.id = group_join_queue.profile_id ' . + 'WHERE group_join_queue.group_id = %d ' . + 'ORDER BY group_join_queue.created DESC '; + + if ($limit != null) { + if (common_config('db','type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } + } + + $members = new Profile(); + + $members->query(sprintf($qry, $this->id)); + return $members; + } + function getMemberCount() { // XXX: WORM cache this diff --git a/lib/router.php b/lib/router.php index d6f5a37b06..fcc915b107 100644 --- a/lib/router.php +++ b/lib/router.php @@ -393,6 +393,10 @@ class Router array('action' => 'makeadmin'), array('nickname' => Nickname::DISPLAY_FMT)); + $m->connect('group/:nickname/members/pending', + array('action' => 'groupqueue'), + array('nickname' => Nickname::DISPLAY_FMT)); + $m->connect('group/:id/id', array('action' => 'groupbyid'), array('id' => '[0-9]+'));