Merge branch '0.8.x' into userdesign

* 0.8.x: (32 commits)
  updates to Status_network
  makeadmin action
  make admins of groups
  show aliases when showing a group
  Link and distribute notices tagged for a group alias
  Code for adding and saving group aliases
  Styles for group block
  add correct li for css magic for block stuff
  typo in profileminilist class
  return count from show
  try to get the right class for profileminilist
  fix perms for classes/statusnet.ini
  fixup perms for classes
  Added Group_alias class
  add a table for group aliases
  Cross-browser notice_attach
  Allow users to be unblocked from a group
  Some UI improvements for blocking and unblocking
  The rest of the things necessary to make group block work
  Make group block work
  ...

Conflicts:
	db/laconica.sql
	lib/common.php
This commit is contained in:
Zach Copley 2009-06-15 11:50:08 -07:00
commit 92f095f589
46 changed files with 2091 additions and 238 deletions

8
README
View File

@ -1196,7 +1196,6 @@ reporturl: URL to post statistics to. Defaults to Laconica developers'
set 'run' to 'never' than to set this value to something set 'run' to 'never' than to set this value to something
nonsensical. nonsensical.
attachments attachments
----------- -----------
@ -1226,6 +1225,13 @@ user_quota: total size in bytes a user can store on this server. Each user
monthly_quota: total size permitted in the current month. This is the total monthly_quota: total size permitted in the current month. This is the total
size in bytes that a user can upload each month. size in bytes that a user can upload each month.
group
-----
Options for group functionality.
maxaliases: maximum number of aliases a group can have. Default 3. Set
to 0 or less to prevent aliases in a group.
Troubleshooting Troubleshooting
=============== ===============

View File

@ -180,7 +180,7 @@ class BlockAction extends Action
if ($action) { if ($action) {
common_redirect(common_local_url($action, $args), 303); common_redirect(common_local_url($action, $args), 303);
} else { } else {
common_redirect(common_local_url('subscriptions', common_redirect(common_local_url('subscribers',
array('nickname' => $cur->nickname)), array('nickname' => $cur->nickname)),
303); 303);
} }

View File

@ -0,0 +1,315 @@
<?php
/**
* Laconica, the distributed open-source microblogging tool
*
* List of group members
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Group
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @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 <evan@controlyourself.ca>
* @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)) {
$this->out->elementStart('li', 'entity_block');
$bf = new GroupUnblockForm($this->out, $this->profile, $this->group,
array('action' => 'blockedfromgroup',
'nickname' => $this->group->nickname));
$bf->show();
$this->out->elementEnd('li');
}
}
}
/**
* Form for unblocking a user from a group
*
* @category Form
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @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'));
}
}

View File

@ -171,6 +171,7 @@ class EditgroupAction extends Action
$homepage = $this->trimmed('homepage'); $homepage = $this->trimmed('homepage');
$description = $this->trimmed('description'); $description = $this->trimmed('description');
$location = $this->trimmed('location'); $location = $this->trimmed('location');
$aliasstring = $this->trimmed('aliases');
if (!Validate::string($nickname, array('min_length' => 1, if (!Validate::string($nickname, array('min_length' => 1,
'max_length' => 64, 'max_length' => 64,
@ -201,6 +202,39 @@ class EditgroupAction extends Action
return; return;
} }
if (!empty($aliasstring)) {
$aliases = array_map('common_canonical_nickname', array_unique(preg_split('/[\s,]+/', $aliasstring)));
} else {
$aliases = array();
}
if (count($aliases) > common_config('group', 'maxaliases')) {
$this->showForm(sprintf(_('Too many aliases! Maximum %d.'),
common_config('group', 'maxaliases')));
return;
}
foreach ($aliases as $alias) {
if (!Validate::string($alias, array('min_length' => 1,
'max_length' => 64,
'format' => NICKNAME_FMT))) {
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
return;
}
if ($this->nicknameExists($alias)) {
$this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'),
$alias));
return;
}
// XXX assumes alphanum nicknames
if (strcmp($alias, $nickname) == 0) {
$this->showForm(_('Alias can\'t be the same as nickname.'));
return;
}
}
$this->group->query('BEGIN');
$orig = clone($this->group); $orig = clone($this->group);
$this->group->nickname = $nickname; $this->group->nickname = $nickname;
@ -217,6 +251,14 @@ class EditgroupAction extends Action
$this->serverError(_('Could not update group.')); $this->serverError(_('Could not update group.'));
} }
$result = $this->group->setAliases($aliases);
if (!$result) {
$this->serverError(_('Could not create aliases.'));
}
$this->group->query('COMMIT');
if ($this->group->nickname != $orig->nickname) { if ($this->group->nickname != $orig->nickname) {
common_redirect(common_local_url('editgroup', common_redirect(common_local_url('editgroup',
array('nickname' => $nickname)), array('nickname' => $nickname)),
@ -229,9 +271,20 @@ class EditgroupAction extends Action
function nicknameExists($nickname) function nicknameExists($nickname)
{ {
$group = User_group::staticGet('nickname', $nickname); $group = User_group::staticGet('nickname', $nickname);
return (!is_null($group) &&
$group != false && if (!empty($group) &&
$group->id != $this->group->id); $group->id != $this->group->id) {
return true;
}
$alias = Group_alias::staticGet('alias', $nickname);
if (!empty($alias) &&
$alias->group_id != $this->group->id) {
return true;
}
return false;
} }
} }

215
actions/groupblock.php Normal file
View File

@ -0,0 +1,215 @@
<?php
/**
* Block a user from a group action class.
*
* PHP version 5
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @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 <http://www.gnu.org/licenses/>.
*/
if (!defined('LACONICA')) {
exit(1);
}
/**
* Block a user from a group
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @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);
}
}
}

View File

@ -127,7 +127,7 @@ class GroupmembersAction extends Action
$members = $this->group->getMembers($offset, $limit); $members = $this->group->getMembers($offset, $limit);
if ($members) { if ($members) {
$member_list = new ProfileList($members, null, $this); $member_list = new GroupMemberList($members, $this->group, $this);
$cnt = $member_list->show(); $cnt = $member_list->show();
} }
@ -138,3 +138,326 @@ class GroupmembersAction extends Action
array('nickname' => $this->group->nickname)); 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 showActions()
{
$this->startActions();
$this->showSubscribeButton();
$this->showMakeAdminForm();
$this->showGroupBlockForm();
$this->endActions();
}
function showMakeAdminForm()
{
$user = common_current_user();
if (!empty($user) && $user->id != $this->profile->id && $user->isAdmin($this->group) &&
!$this->profile->isAdmin($this->group)) {
$this->out->elementStart('li', 'entity_make_admin');
$maf = new MakeAdminForm($this->out, $this->profile, $this->group,
array('action' => 'groupmembers',
'nickname' => $this->group->nickname));
$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,
array('action' => 'groupmembers',
'nickname' => $this->group->nickname));
$bf->show();
$this->out->elementEnd('li');
}
}
}
/**
* Form for blocking a user from a group
*
* @category Form
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @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'));
}
}
/**
* Form for making a user an admin for a group
*
* @category Form
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://laconi.ca/
*/
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()
{
$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', _('Make Admin'), 'submit', null, _('Make this user an admin'));
}
}

149
actions/groupunblock.php Normal file
View File

@ -0,0 +1,149 @@
<?php
/**
* Block a user from a group action class.
*
* PHP version 5
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @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 <http://www.gnu.org/licenses/>.
*/
if (!defined('LACONICA')) {
exit(1);
}
/**
* Unlock a user from a group
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @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);
}
}
}

View File

@ -96,6 +96,11 @@ class JoingroupAction extends Action
return false; 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; return true;
} }

166
actions/makeadmin.php Normal file
View File

@ -0,0 +1,166 @@
<?php
/**
* Make another user an admin of a group
*
* PHP version 5
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @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 <http://www.gnu.org/licenses/>.
*/
if (!defined('LACONICA')) {
exit(1);
}
/**
* Make another user an admin of a group
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://laconi.ca/
*/
class MakeadminAction 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('profileid');
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('groupid');
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 make another user an admin.'), 401);
return false;
}
if ($this->profile->isAdmin($this->group)) {
$this->clientError(sprintf(_('%s is already an admin for group "%s".'),
$this->profile->getBestName(),
$this->group->getBestName()),
401);
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->makeAdmin();
}
}
/**
* Make user an admin
*
* @return void
*/
function makeAdmin()
{
$member = Group_member::pkeyGet(array('group_id' => $this->group->id,
'profile_id' => $this->profile->id));
if (empty($member)) {
$this->serverError(_('Can\'t get membership record for %s in group %s'),
$this->profile->getBestName(),
$this->group->getBestName());
}
$orig = clone($member);
$member->is_admin = 1;
$result = $member->update($orig);
if (!$result) {
common_log_db_error($member, 'UPDATE', __FILE__);
$this->serverError(_('Can\'t make %s an admin for group %s'),
$this->profile->getBestName(),
$this->group->getBestName());
}
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('groupmembers',
array('nickname' => $this->group->nickname)),
303);
}
}
}

View File

@ -123,6 +123,7 @@ class NewgroupAction extends Action
$homepage = $this->trimmed('homepage'); $homepage = $this->trimmed('homepage');
$description = $this->trimmed('description'); $description = $this->trimmed('description');
$location = $this->trimmed('location'); $location = $this->trimmed('location');
$aliasstring = $this->trimmed('aliases');
if (!Validate::string($nickname, array('min_length' => 1, if (!Validate::string($nickname, array('min_length' => 1,
'max_length' => 64, 'max_length' => 64,
@ -153,6 +154,37 @@ class NewgroupAction extends Action
return; return;
} }
if (!empty($aliasstring)) {
$aliases = array_map('common_canonical_nickname', array_unique(preg_split('/[\s,]+/', $aliasstring)));
} else {
$aliases = array();
}
if (count($aliases) > common_config('group', 'maxaliases')) {
$this->showForm(sprintf(_('Too many aliases! Maximum %d.'),
common_config('group', 'maxaliases')));
return;
}
foreach ($aliases as $alias) {
if (!Validate::string($alias, array('min_length' => 1,
'max_length' => 64,
'format' => NICKNAME_FMT))) {
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
return;
}
if ($this->nicknameExists($alias)) {
$this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'),
$alias));
return;
}
// XXX assumes alphanum nicknames
if (strcmp($alias, $nickname) == 0) {
$this->showForm(_('Alias can\'t be the same as nickname.'));
return;
}
}
$cur = common_current_user(); $cur = common_current_user();
// Checked in prepare() above // Checked in prepare() above
@ -177,6 +209,12 @@ class NewgroupAction extends Action
$this->serverError(_('Could not create group.')); $this->serverError(_('Could not create group.'));
} }
$result = $group->setAliases($aliases);
if (!$result) {
$this->serverError(_('Could not create aliases.'));
}
$member = new Group_member(); $member = new Group_member();
$member->group_id = $group->id; $member->group_id = $group->id;
@ -199,7 +237,18 @@ class NewgroupAction extends Action
function nicknameExists($nickname) function nicknameExists($nickname)
{ {
$group = User_group::staticGet('nickname', $nickname); $group = User_group::staticGet('nickname', $nickname);
return (!is_null($group) && $group != false);
if (!empty($group)) {
return true;
}
$alias = Group_alias::staticGet('alias', $nickname);
if (!empty($alias)) {
return true;
}
return false;
} }
} }

View File

@ -272,6 +272,17 @@ class ShowgroupAction extends Action
$this->elementEnd('dl'); $this->elementEnd('dl');
} }
if (common_config('group', 'maxaliases') > 0) {
$aliases = $this->group->getAliases();
if (!empty($aliases)) {
$this->elementStart('dl', 'entity_aliases');
$this->element('dt', null, _('Aliases'));
$this->element('dd', 'aliases', implode(' ', $aliases));
$this->elementEnd('dl');
}
}
$this->elementEnd('div'); $this->elementEnd('div');
$this->elementStart('div', 'entity_actions'); $this->elementStart('div', 'entity_actions');
@ -283,7 +294,7 @@ class ShowgroupAction extends Action
if ($cur->isMember($this->group)) { if ($cur->isMember($this->group)) {
$lf = new LeaveForm($this, $this->group); $lf = new LeaveForm($this, $this->group);
$lf->show(); $lf->show();
} else { } else if (!Group_block::isBlocked($this->group, $cur->getProfile())) {
$jf = new JoinForm($this, $this->group); $jf = new JoinForm($this, $this->group);
$jf->show(); $jf->show();
} }
@ -344,7 +355,7 @@ class ShowgroupAction extends Action
$this->element('h2', null, _('Members')); $this->element('h2', null, _('Members'));
$pml = new ProfileMiniList($member, null, $this); $pml = new ProfileMiniList($member, $this);
$cnt = $pml->show(); $cnt = $pml->show();
if ($cnt == 0) { if ($cnt == 0) {
$this->element('p', null, _('(None)')); $this->element('p', null, _('(None)'));

View File

@ -320,10 +320,14 @@ class ShowstreamAction extends ProfileAction
$blocked = $cur->hasBlocked($this->profile); $blocked = $cur->hasBlocked($this->profile);
$this->elementStart('li', 'entity_block'); $this->elementStart('li', 'entity_block');
if ($blocked) { if ($blocked) {
$ubf = new UnblockForm($this, $this->profile); $ubf = new UnblockForm($this, $this->profile,
array('action' => 'showstream',
'nickname' => $this->profile->nickname));
$ubf->show(); $ubf->show();
} else { } else {
$bf = new BlockForm($this, $this->profile); $bf = new BlockForm($this, $this->profile,
array('action' => 'showstream',
'nickname' => $this->profile->nickname));
$bf->show(); $bf->show();
} }
$this->elementEnd('li'); $this->elementEnd('li');

View File

@ -130,18 +130,34 @@ class SubscribersAction extends GalleryAction
} }
} }
class SubscribersList extends ProfileList class SubscribersList extends SubscriptionList
{ {
function showBlockForm() function newListItem($profile)
{ {
$bf = new BlockForm($this->out, $this->profile, return new SubscribersListItem($profile, $this->owner, $this->action);
array('action' => 'subscribers', }
'nickname' => $this->owner->nickname)); }
$bf->show();
} class SubscribersListItem extends SubscriptionListItem
{
function isReadOnly($args) function showActions()
{ {
return true; $this->startActions();
$this->showSubscribeButton();
// Relevant code!
$this->showBlockForm();
$this->endActions();
}
function showBlockForm()
{
$user = common_current_user();
if (!empty($user) && $this->owner->id == $user->id) {
$bf = new BlockForm($this->out, $this->profile,
array('action' => 'subscribers',
'nickname' => $this->owner->nickname));
$bf->show();
}
} }
} }

View File

@ -137,22 +137,46 @@ class SubscriptionsAction extends GalleryAction
} }
} }
class SubscriptionsList extends ProfileList // XXX SubscriptionsList and SubscriptionList are dangerously close
class SubscriptionsList extends SubscriptionList
{ {
function showOwnerControls($profile) function newListItem($profile)
{
return new SubscriptionsListItem($profile, $this->owner, $this->action);
}
}
class SubscriptionsListItem extends SubscriptionListItem
{
function showProfile()
{
$this->startProfile();
$this->showAvatar();
$this->showFullName();
$this->showLocation();
$this->showHomepage();
$this->showBio();
$this->showTags();
// Relevant portion!
$this->showOwnerControls();
$this->endProfile();
}
function showOwnerControls()
{ {
$sub = Subscription::pkeyGet(array('subscriber' => $this->owner->id, $sub = Subscription::pkeyGet(array('subscriber' => $this->owner->id,
'subscribed' => $profile->id)); 'subscribed' => $this->profile->id));
if (!$sub) { if (!$sub) {
return; return;
} }
$this->out->elementStart('form', array('id' => 'subedit-' . $profile->id, $this->out->elementStart('form', array('id' => 'subedit-' . $this->profile->id,
'method' => 'post', 'method' => 'post',
'class' => 'form_subscription_edit', 'class' => 'form_subscription_edit',
'action' => common_local_url('subedit'))); 'action' => common_local_url('subedit')));
$this->out->hidden('token', common_session_token()); $this->out->hidden('token', common_session_token());
$this->out->hidden('profile', $profile->id); $this->out->hidden('profile', $this->profile->id);
$this->out->checkbox('jabber', _('Jabber'), $sub->jabber); $this->out->checkbox('jabber', _('Jabber'), $sub->jabber);
$this->out->checkbox('sms', _('SMS'), $sub->sms); $this->out->checkbox('sms', _('SMS'), $sub->sms);
$this->out->submit('save', _('Save')); $this->out->submit('save', _('Save'));

View File

@ -118,7 +118,7 @@ class UnblockAction extends Action
if ($action) { if ($action) {
common_redirect(common_local_url($action, $args), 303); common_redirect(common_local_url($action, $args), 303);
} else { } else {
common_redirect(common_local_url('subscriptions', common_redirect(common_local_url('subscribers',
array('nickname' => $cur->nickname)), array('nickname' => $cur->nickname)),
303); 303);
} }

41
classes/Group_alias.php Normal file
View File

@ -0,0 +1,41 @@
<?php
/**
* Table Definition for group_alias
*
* Laconica - a distributed open-source microblogging tool
* Copyright (C) 2009, Control Yourself, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Group_alias extends Memcached_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
public $__table = 'group_alias'; // table name
public $alias; // varchar(64) primary_key not_null
public $group_id; // int(4) not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
/* Static get */
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Group_alias',$k,$v); }
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
}

115
classes/Group_block.php Normal file
View File

@ -0,0 +1,115 @@
<?php
/**
* Table Definition for group_block
*
* 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 <http://www.gnu.org/licenses/>.
*/
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 */
public $__table = 'group_block'; // table name
public $group_id; // int(4) primary_key not_null
public $blocked; // int(4) primary_key not_null
public $blocker; // int(4) not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
/* Static get */
function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('Group_block',$k,$v); }
/* 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;
}
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;
}
}

View File

@ -125,7 +125,12 @@ class Notice extends Memcached_DataObject
$profile = Profile::staticGet($profile_id); $profile = Profile::staticGet($profile_id);
$final = common_shorten_links($content); $final = common_shorten_links($content);
if (mb_strlen($final) > 140) {
common_log(LOG_INFO, 'Rejecting notice that is too long.');
return _('Problem saving notice. Too long.');
}
if (!$profile) { if (!$profile) {
common_log(LOG_ERR, 'Problem saving notice. Unknown user.'); common_log(LOG_ERR, 'Problem saving notice. Unknown user.');
@ -747,16 +752,16 @@ class Notice extends Memcached_DataObject
foreach (array_unique($match[1]) as $nickname) { foreach (array_unique($match[1]) as $nickname) {
/* XXX: remote groups. */ /* XXX: remote groups. */
$group = User_group::staticGet('nickname', $nickname); $group = User_group::getForNickname($nickname);
if (!$group) { if (empty($group)) {
continue; continue;
} }
// we automatically add a tag for every group name, too // we automatically add a tag for every group name, too
$tag = Notice_tag::pkeyGet(array('tag' => common_canonical_tag($nickname), $tag = Notice_tag::pkeyGet(array('tag' => common_canonical_tag($nickname),
'notice_id' => $this->id)); 'notice_id' => $this->id));
if (is_null($tag)) { if (is_null($tag)) {
$this->saveTag($nickname); $this->saveTag($nickname);

View File

@ -12,11 +12,13 @@ class Status_network extends DB_DataObject
public $nickname; // varchar(64) primary_key not_null public $nickname; // varchar(64) primary_key not_null
public $hostname; // varchar(255) unique_key public $hostname; // varchar(255) unique_key
public $pathname; // varchar(255) unique_key public $pathname; // varchar(255) unique_key
public $sitename; // varchar(255)
public $dbhost; // varchar(255) public $dbhost; // varchar(255)
public $dbuser; // varchar(255) public $dbuser; // varchar(255)
public $dbpass; // varchar(255) public $dbpass; // varchar(255)
public $dbname; // varchar(255) public $dbname; // varchar(255)
public $sitename; // varchar(255)
public $theme; // varchar(255)
public $logo; // varchar(255)
public $created; // datetime() not_null public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
@ -37,13 +39,19 @@ class Status_network extends DB_DataObject
return true; return true;
} }
static function setupSite($servername, $pathname) static function setupSite($servername, $pathname, $wildcard)
{ {
global $config; global $config;
$parts = explode('.', $servername); // XXX I18N, probably not crucial for hostnames
// XXX This probably needs a tune up
$sn = Status_network::staticGet('nickname', $parts[0]); if (0 == strncasecmp(strrev($wildcard), strrev($servername), strlen($wildcard))) {
$parts = explode('.', $servername);
$sn = Status_network::staticGet('nickname', strtolower($parts[0]));
} else {
$sn = Status_network::staticGet('hostname', strtolower($servername));
}
if (!empty($sn)) { if (!empty($sn)) {
$dbhost = (empty($sn->dbhost)) ? 'localhost' : $sn->dbhost; $dbhost = (empty($sn->dbhost)) ? 'localhost' : $sn->dbhost;
@ -52,7 +60,16 @@ class Status_network extends DB_DataObject
$dbname = (empty($sn->dbname)) ? $sn->nickname : $sn->dbname; $dbname = (empty($sn->dbname)) ? $sn->nickname : $sn->dbname;
$config['db']['database'] = "mysqli://$dbuser:$dbpass@$dbhost/$dbname"; $config['db']['database'] = "mysqli://$dbuser:$dbpass@$dbhost/$dbname";
$config['site']['name'] = $sn->sitename; $config['site']['name'] = $sn->sitename;
if (!empty($sn->theme)) {
$config['site']['theme'] = $sn->theme;
}
if (!empty($sn->logo)) {
$config['site']['logo'] = $sn->logo;
}
return true; return true;
} else { } else {
return false; return false;

View File

@ -125,6 +125,29 @@ class User_group extends Memcached_DataObject
return $members; 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) function setOriginal($filename)
{ {
$imagefile = new ImageFile($this->id, Avatar::path($filename)); $imagefile = new ImageFile($this->id, Avatar::path($filename));
@ -137,4 +160,83 @@ class User_group extends Memcached_DataObject
common_debug(common_log_objstring($this)); common_debug(common_log_objstring($this));
return $this->update($orig); return $this->update($orig);
} }
function getBestName()
{
return ($this->fullname) ? $this->fullname : $this->nickname;
}
function getAliases()
{
$aliases = array();
// XXX: cache this
$alias = new Group_alias();
$alias->group_id = $this->id;
if ($alias->find()) {
while ($alias->fetch()) {
$aliases[] = $alias->alias;
}
}
$alias->free();
return $aliases;
}
function setAliases($newaliases) {
$newaliases = array_unique($newaliases);
$oldaliases = $this->getAliases();
# Delete stuff that's old that not in new
$to_delete = array_diff($oldaliases, $newaliases);
# Insert stuff that's in new and not in old
$to_insert = array_diff($newaliases, $oldaliases);
$alias = new Group_alias();
$alias->group_id = $this->id;
foreach ($to_delete as $delalias) {
$alias->alias = $delalias;
$result = $alias->delete();
if (!$result) {
common_log_db_error($alias, 'DELETE', __FILE__);
return false;
}
}
foreach ($to_insert as $insalias) {
$alias->alias = $insalias;
$result = $alias->insert();
if (!$result) {
common_log_db_error($alias, 'INSERT', __FILE__);
return false;
}
}
return true;
}
static function getForNickname($nickname)
{
$nickname = common_canonical_nickname($nickname);
$group = User_group::staticGet('nickname', $nickname);
if (!empty($group)) {
return $group;
}
$alias = Group_alias::staticGet('alias', $nickname);
if (!empty($alias)) {
return User_group::staticGet('id', $alias->group_id);
}
return null;
}
} }

View File

@ -170,6 +170,24 @@ id = K
service = K service = K
uri = U uri = U
[group_alias]
alias = 130
group_id = 129
modified = 384
[group_alias__keys]
alias = K
[group_block]
group_id = 129
blocked = 129
blocker = 129
modified = 384
[group_block__keys]
group_id = K
blocked = K
[group_inbox] [group_inbox]
group_id = 129 group_id = 129
notice_id = 129 notice_id = 129

5
classes/statusnet.ini Executable file → Normal file
View File

@ -1,13 +1,14 @@
[status_network] [status_network]
nickname = 130 nickname = 130
hostname = 2 hostname = 2
pathname = 2 pathname = 2
sitename = 2
dbhost = 2 dbhost = 2
dbuser = 2 dbuser = 2
dbpass = 2 dbpass = 2
dbname = 2 dbname = 2
sitename = 2
theme = 2
logo = 2
created = 142 created = 142
modified = 384 modified = 384

View File

@ -431,49 +431,50 @@ create table group_inbox (
create table file ( create table file (
id integer primary key auto_increment, id integer primary key auto_increment,
url varchar(255), mimetype varchar(50), url varchar(255) comment 'destination URL after following redirections',
size integer, mimetype varchar(50) comment 'mime type of resource',
title varchar(255), size integer comment 'size of resource when available',
date integer(11), title varchar(255) comment 'title of resource when available',
protected integer(1), date integer(11) comment 'date of resource according to http query',
protected integer(1) comment 'true when URL is private (needs login)',
unique(url) unique(url)
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci; ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
create table file_oembed ( create table file_oembed (
id integer primary key auto_increment, id integer primary key auto_increment,
file_id integer, file_id integer comment 'oEmbed for that URL/file' references file (id),
version varchar(20), version varchar(20) comment 'oEmbed spec. version',
type varchar(20), type varchar(20) comment 'oEmbed type: photo, video, link, rich',
provider varchar(50), provider varchar(50) comment 'name of this oEmbed provider',
provider_url varchar(255), provider_url varchar(255) comment 'URL of this oEmbed provider',
width integer, width integer comment 'width of oEmbed resource when available',
height integer, height integer comment 'height of oEmbed resource when available',
html text, html text comment 'html representation of this oEmbed resource when applicable',
title varchar(255), title varchar(255) comment 'title of oEmbed resource when available',
author_name varchar(50), author_name varchar(50) comment 'author name for this oEmbed resource',
author_url varchar(255), author_url varchar(255) comment 'author URL for this oEmbed resource',
url varchar(255), url varchar(255) comment 'URL for this oEmbed resource when applicable (photo, link)',
unique(file_id) unique(file_id)
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci; ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
create table file_redirection ( create table file_redirection (
id integer primary key auto_increment, id integer primary key auto_increment,
url varchar(255), url varchar(255) comment 'short URL (or any other kind of redirect) for file (id)',
file_id integer, file_id integer comment 'short URL for what URL/file' references file (id),
redirections integer, redirections integer comment 'redirect count',
httpcode integer, httpcode integer comment 'HTTP status code (20x, 30x, etc.)',
unique(url) unique(url)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table file_thumbnail ( create table file_thumbnail (
id integer primary key auto_increment, id integer primary key auto_increment,
file_id integer, file_id integer comment 'thumbnail for what URL/file' references file (id),
url varchar(255), url varchar(255) comment 'URL of thumbnail',
width integer, width integer comment 'width of thumbnail',
height integer, height integer comment 'height of thumbnail',
unique(file_id), unique(file_id),
unique(url) unique(url)
@ -481,8 +482,8 @@ create table file_thumbnail (
create table file_to_post ( create table file_to_post (
id integer primary key auto_increment, id integer primary key auto_increment,
file_id integer, file_id integer comment 'id of URL/file' references file (id),
post_id integer, post_id integer comment 'id of the notice it belongs to' references notice (id),
unique(file_id, post_id) unique(file_id, post_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
@ -496,3 +497,23 @@ create table design (
linkcolor integer comment 'link color', linkcolor integer comment 'link color',
backgroundimage varchar(255) comment 'background image, if any' backgroundimage varchar(255) comment 'background image, if any'
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) 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;
create table group_alias (
alias varchar(64) primary key comment 'additional nickname for the group',
group_id integer not null comment 'group profile is blocked from' references user_group (id),
modified timestamp comment 'date alias was created',
index group_alias_group_id_idx (group_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;

View File

@ -5,12 +5,16 @@ create table status_network (
nickname varchar(64) primary key comment 'nickname', nickname varchar(64) primary key comment 'nickname',
hostname varchar(255) unique key comment 'alternate hostname if any', hostname varchar(255) unique key comment 'alternate hostname if any',
pathname varchar(255) unique key comment 'alternate pathname if any', pathname varchar(255) unique key comment 'alternate pathname if any',
sitename varchar(255) comment 'display name',
dbhost varchar(255) comment 'database host', dbhost varchar(255) comment 'database host',
dbuser varchar(255) comment 'database username', dbuser varchar(255) comment 'database username',
dbpass varchar(255) comment 'database password', dbpass varchar(255) comment 'database password',
dbname varchar(255) comment 'database name', dbname varchar(255) comment 'database name',
sitename varchar(255) comment 'display name',
theme varchar(255) comment 'theme name',
logo varchar(255) comment 'site logo',
created datetime not null comment 'date this record was created', created datetime not null comment 'date this record was created',
modified timestamp comment 'date this record was modified' modified timestamp comment 'date this record was modified'

View File

@ -48,13 +48,18 @@ function handleError($error)
$logmsg .= " : ". $error->getDebugInfo(); $logmsg .= " : ". $error->getDebugInfo();
} }
common_log(LOG_ERR, $logmsg); common_log(LOG_ERR, $logmsg);
$msg = sprintf(_('The database for %s isn\'t responding correctly, '. if ($error instanceof DB_DataObject_Error) {
'so the site won\'t work properly. '. $msg = sprintf(_('The database for %s isn\'t responding correctly, '.
'The site admins probably know about the problem, '. 'so the site won\'t work properly. '.
'but you can contact them at %s to make sure. '. 'The site admins probably know about the problem, '.
'Otherwise, wait a few minutes and try again.'), 'but you can contact them at %s to make sure. '.
common_config('site', 'name'), 'Otherwise, wait a few minutes and try again.'),
common_config('site', 'email')); common_config('site', 'name'),
common_config('site', 'email'));
} else {
$msg = _('An important error occured, probably related to email setup. '.
'Check logfiles for more info..');
}
$dac = new DBErrorAction($msg, 500); $dac = new DBErrorAction($msg, 500);
$dac->showPage(); $dac->showPage();
@ -70,7 +75,7 @@ function main()
global $user, $action, $config; global $user, $action, $config;
Snapshot::check(); Snapshot::check();
if (!_have_config()) { if (!_have_config()) {
$msg = sprintf(_("No configuration file found. Try running ". $msg = sprintf(_("No configuration file found. Try running ".
"the installation program first.")); "the installation program first."));

View File

@ -206,6 +206,8 @@ $config =
'user_quota' => 50000000, 'user_quota' => 50000000,
'monthly_quota' => 15000000, 'monthly_quota' => 15000000,
), ),
'group' =>
array('maxaliases' => 3),
); );
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');

View File

@ -111,7 +111,6 @@ class GroupEditForm extends Form
} }
} }
/** /**
* Name of the form * Name of the form
* *
@ -157,6 +156,16 @@ class GroupEditForm extends Form
($this->out->arg('location')) ? $this->out->arg('location') : $this->group->location, ($this->out->arg('location')) ? $this->out->arg('location') : $this->group->location,
_('Location for the group, if any, like "City, State (or Region), Country"')); _('Location for the group, if any, like "City, State (or Region), Country"'));
$this->out->elementEnd('li'); $this->out->elementEnd('li');
if (common_config('group', 'maxaliases') > 0) {
$aliases = (empty($this->group)) ? array() : $this->group->getAliases();
$this->out->elementStart('li');
$this->out->input('aliases', _('Aliases'),
($this->out->arg('aliases')) ? $this->out->arg('aliases') :
(!empty($aliases)) ? implode(' ', $aliases) : '',
sprintf(_('Extra nicknames for the group, comma- or space- separated, max %d'),
common_config('group', 'maxaliases')));;
$this->out->elementEnd('li');
}
$this->out->elementEnd('ul'); $this->out->elementEnd('ul');
} }

View File

@ -166,7 +166,7 @@ class GroupList extends Widget
if ($user->isMember($this->group)) { if ($user->isMember($this->group)) {
$lf = new LeaveForm($this->out, $this->group); $lf = new LeaveForm($this->out, $this->group);
$lf->show(); $lf->show();
} else { } else if (!Group_block::isBlocked($this->group, $user->getProfile())) {
$jf = new JoinForm($this->out, $this->group); $jf = new JoinForm($this->out, $this->group);
$jf->show(); $jf->show();
} }

View File

@ -95,6 +95,12 @@ class GroupNav extends Widget
$cur = common_current_user(); $cur = common_current_user();
if ($cur && $cur->isAdmin($this->group)) { 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' => $this->out->menuItem(common_local_url('editgroup', array('nickname' =>
$nickname)), $nickname)),
_('Admin'), _('Admin'),

View File

@ -148,12 +148,12 @@ class NoticeForm extends Form
$this->out->element('dd', array('id' => 'notice_text-count'), $this->out->element('dd', array('id' => 'notice_text-count'),
'140'); '140');
$this->out->elementEnd('dl'); $this->out->elementEnd('dl');
$this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota')); $this->out->element('label', array('for' => 'notice_data-attach'),_('Attach'));
$this->out->element('label', array('for' => 'notice_data-attach'), _('Attach'));
$this->out->element('input', array('id' => 'notice_data-attach', $this->out->element('input', array('id' => 'notice_data-attach',
'type' => 'file', 'type' => 'file',
'name' => 'attach', 'name' => 'attach',
'title' => _('Attach a file'))); 'title' => _('Attach a file')));
$this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota'));
if ($this->action) { if ($this->action) {
$this->out->hidden('notice_return-to', $this->action, 'returnto'); $this->out->hidden('notice_return-to', $this->action, 'returnto');
} }

View File

@ -205,24 +205,10 @@ class NoticeListItem extends Widget
return 'shownotice' !== $this->out->args['action']; return 'shownotice' !== $this->out->args['action'];
} }
/*
function attachmentCount($discriminant = true) {
$file_oembed = new File_oembed;
$query = "select count(*) as c from file_oembed join file_to_post on file_oembed.file_id = file_to_post.file_id where post_id=" . $this->notice->id;
$file_oembed->query($query);
$file_oembed->fetch();
return intval($file_oembed->c);
}
*/
function showWithAttachment() {
}
function showNoticeInfo() function showNoticeInfo()
{ {
$this->out->elementStart('div', 'entry-content'); $this->out->elementStart('div', 'entry-content');
$this->showNoticeLink(); $this->showNoticeLink();
// $this->showWithAttachment();
$this->showNoticeSource(); $this->showNoticeSource();
$this->showContext(); $this->showContext();
$this->out->elementEnd('div'); $this->out->elementEnd('div');

View File

@ -56,20 +56,25 @@ class PeopleSearchResults extends ProfileList
function __construct($profile, $terms, $action) function __construct($profile, $terms, $action)
{ {
parent::__construct($profile, $terms, $action); parent::__construct($profile, $action);
$this->terms = array_map('preg_quote', $this->terms = array_map('preg_quote',
array_map('htmlspecialchars', $terms)); array_map('htmlspecialchars', $terms));
$this->pattern = '/('.implode('|',$terms).')/i'; $this->pattern = '/('.implode('|',$terms).')/i';
} }
function newProfileItem($profile)
{
return new PeopleSearchResultItem($profile, $this->action);
}
}
class PeopleSearchResultItem extends ProfileListItem
{
function highlight($text) function highlight($text)
{ {
return preg_replace($this->pattern, '<strong>\\1</strong>', htmlspecialchars($text)); return preg_replace($this->pattern, '<strong>\\1</strong>', htmlspecialchars($text));
} }
function isReadOnly($args)
{
return true;
}
} }

View File

@ -109,7 +109,7 @@ class ProfileAction extends OwnerDesignAction
$this->element('h2', null, _('Subscriptions')); $this->element('h2', null, _('Subscriptions'));
if ($profile) { if ($profile) {
$pml = new ProfileMiniList($profile, $this->user, $this); $pml = new ProfileMiniList($profile, $this);
$cnt = $pml->show(); $cnt = $pml->show();
if ($cnt == 0) { if ($cnt == 0) {
$this->element('p', null, _('(None)')); $this->element('p', null, _('(None)'));
@ -138,7 +138,7 @@ class ProfileAction extends OwnerDesignAction
$this->element('h2', null, _('Subscribers')); $this->element('h2', null, _('Subscribers'));
if ($profile) { if ($profile) {
$pml = new ProfileMiniList($profile, $this->user, $this); $pml = new ProfileMiniList($profile, $this);
$cnt = $pml->show(); $cnt = $pml->show();
if ($cnt == 0) { if ($cnt == 0) {
$this->element('p', null, _('(None)')); $this->element('p', null, _('(None)'));

View File

@ -49,25 +49,37 @@ class ProfileList extends Widget
{ {
/** Current profile, profile query. */ /** Current profile, profile query. */
var $profile = null; var $profile = null;
/** Owner of this list */
var $owner = null;
/** Action object using us. */ /** Action object using us. */
var $action = null; var $action = null;
function __construct($profile, $owner=null, $action=null) function __construct($profile, $action=null)
{ {
parent::__construct($action); parent::__construct($action);
$this->profile = $profile; $this->profile = $profile;
$this->owner = $owner;
$this->action = $action; $this->action = $action;
} }
function show() function show()
{ {
$this->startList();
$cnt = $this->showProfiles();
$this->endList();
return $cnt;
}
function startList()
{
$this->out->elementStart('ul', 'profiles'); $this->out->elementStart('ul', 'profiles');
}
function endList()
{
$this->out->elementEnd('ul');
}
function showProfiles()
{
$cnt = 0; $cnt = 0;
while ($this->profile->fetch()) { while ($this->profile->fetch()) {
@ -75,24 +87,66 @@ class ProfileList extends Widget
if($cnt > PROFILES_PER_PAGE) { if($cnt > PROFILES_PER_PAGE) {
break; break;
} }
$this->showProfile(); $pli = $this->newListItem($this->profile);
$pli->show();
} }
$this->out->elementEnd('ul');
return $cnt; return $cnt;
} }
function showProfile() function newListItem($profile)
{
return new ProfileListItem($this->profile, $this->action);
}
}
class ProfileListItem extends Widget
{
/** Current profile. */
var $profile = null;
/** Action object using us. */
var $action = null;
function __construct($profile, $action)
{
parent::__construct($action);
$this->profile = $profile;
$this->action = $action;
}
function show()
{
$this->startItem();
$this->showProfile();
$this->showActions();
$this->endItem();
}
function startItem()
{ {
$this->out->elementStart('li', array('class' => 'profile', $this->out->elementStart('li', array('class' => 'profile',
'id' => 'profile-' . $this->profile->id)); 'id' => 'profile-' . $this->profile->id));
}
$user = common_current_user(); function showProfile()
$is_own = !is_null($user) && isset($this->owner) && ($user->id === $this->owner->id); {
$this->startProfile();
$this->showAvatar();
$this->showFullName();
$this->showLocation();
$this->showHomepage();
$this->showBio();
$this->endProfile();
}
function startProfile()
{
$this->out->elementStart('div', 'entity_profile vcard'); $this->out->elementStart('div', 'entity_profile vcard');
}
function showAvatar()
{
$avatar = $this->profile->getAvatar(AVATAR_STREAM_SIZE); $avatar = $this->profile->getAvatar(AVATAR_STREAM_SIZE);
$this->out->elementStart('a', array('href' => $this->profile->profileurl, $this->out->elementStart('a', array('href' => $this->profile->profileurl,
'class' => 'url')); 'class' => 'url'));
@ -108,7 +162,10 @@ class ProfileList extends Widget
$this->out->raw($this->highlight($this->profile->nickname)); $this->out->raw($this->highlight($this->profile->nickname));
$this->out->elementEnd('span'); $this->out->elementEnd('span');
$this->out->elementEnd('a'); $this->out->elementEnd('a');
}
function showFullName()
{
if (!empty($this->profile->fullname)) { if (!empty($this->profile->fullname)) {
$this->out->elementStart('dl', 'entity_fn'); $this->out->elementStart('dl', 'entity_fn');
$this->out->element('dt', null, 'Full name'); $this->out->element('dt', null, 'Full name');
@ -119,6 +176,10 @@ class ProfileList extends Widget
$this->out->elementEnd('dd'); $this->out->elementEnd('dd');
$this->out->elementEnd('dl'); $this->out->elementEnd('dl');
} }
}
function showLocation()
{
if (!empty($this->profile->location)) { if (!empty($this->profile->location)) {
$this->out->elementStart('dl', 'entity_location'); $this->out->elementStart('dl', 'entity_location');
$this->out->element('dt', null, _('Location')); $this->out->element('dt', null, _('Location'));
@ -127,6 +188,10 @@ class ProfileList extends Widget
$this->out->elementEnd('dd'); $this->out->elementEnd('dd');
$this->out->elementEnd('dl'); $this->out->elementEnd('dl');
} }
}
function showHomepage()
{
if (!empty($this->profile->homepage)) { if (!empty($this->profile->homepage)) {
$this->out->elementStart('dl', 'entity_url'); $this->out->elementStart('dl', 'entity_url');
$this->out->element('dt', null, _('URL')); $this->out->element('dt', null, _('URL'));
@ -138,6 +203,10 @@ class ProfileList extends Widget
$this->out->elementEnd('dd'); $this->out->elementEnd('dd');
$this->out->elementEnd('dl'); $this->out->elementEnd('dl');
} }
}
function showBio()
{
if (!empty($this->profile->bio)) { if (!empty($this->profile->bio)) {
$this->out->elementStart('dl', 'entity_note'); $this->out->elementStart('dl', 'entity_note');
$this->out->element('dt', null, _('Note')); $this->out->element('dt', null, _('Note'));
@ -146,57 +215,33 @@ class ProfileList extends Widget
$this->out->elementEnd('dd'); $this->out->elementEnd('dd');
$this->out->elementEnd('dl'); $this->out->elementEnd('dl');
} }
}
# If we're on a list with an owner (subscriptions or subscribers)... function endProfile()
{
if ($this->owner) {
# Get tags
$tags = Profile_tag::getTags($this->owner->id, $this->profile->id);
$this->out->elementStart('dl', 'entity_tags');
$this->out->elementStart('dt');
if ($is_own) {
$this->out->element('a', array('href' => common_local_url('tagother',
array('id' => $this->profile->id))),
_('Tags'));
} else {
$this->out->text(_('Tags'));
}
$this->out->elementEnd('dt');
$this->out->elementStart('dd');
if ($tags) {
$this->out->elementStart('ul', 'tags xoxo');
foreach ($tags as $tag) {
$this->out->elementStart('li');
$this->out->element('span', 'mark_hash', '#');
$this->out->element('a', array('rel' => 'tag',
'href' => common_local_url($this->action->trimmed('action'),
array('nickname' => $this->owner->nickname,
'tag' => $tag))),
$tag);
$this->out->elementEnd('li');
}
$this->out->elementEnd('ul');
} else {
$this->out->text(_('(none)'));
}
$this->out->elementEnd('dd');
$this->out->elementEnd('dl');
}
if ($is_own) {
$this->showOwnerControls($this->profile);
}
$this->out->elementEnd('div'); $this->out->elementEnd('div');
}
function showActions()
{
$this->startActions();
$this->showSubscribeButton();
$this->endActions();
}
function startActions()
{
$this->out->elementStart('div', 'entity_actions'); $this->out->elementStart('div', 'entity_actions');
$this->out->elementStart('ul'); $this->out->elementStart('ul');
}
function showSubscribeButton()
{
// Is this a logged-in user, looking at someone else's // Is this a logged-in user, looking at someone else's
// profile? // profile?
$user = common_current_user();
if (!empty($user) && $this->profile->id != $user->id) { if (!empty($user) && $this->profile->id != $user->id) {
$this->out->elementStart('li', 'entity_subscribe'); $this->out->elementStart('li', 'entity_subscribe');
if ($user->isSubscribed($this->profile)) { if ($user->isSubscribed($this->profile)) {
@ -207,33 +252,22 @@ class ProfileList extends Widget
$sf->show(); $sf->show();
} }
$this->out->elementEnd('li'); $this->out->elementEnd('li');
$this->out->elementStart('li', 'entity_block');
if ($user->id == $this->owner->id) {
$this->showBlockForm();
}
$this->out->elementEnd('li');
} }
$this->out->elementEnd('ul');
$this->out->elementEnd('div');
$this->out->elementEnd('li');
} }
/* Override this in subclasses. */ function endActions()
function showOwnerControls($profile)
{ {
return; $this->out->elementEnd('ul');
$this->out->elementEnd('div');
}
function endItem()
{
$this->out->elementEnd('li');
} }
function highlight($text) function highlight($text)
{ {
return htmlspecialchars($text); return htmlspecialchars($text);
} }
function showBlockForm()
{
}
} }

View File

@ -47,26 +47,20 @@ define('PROFILES_PER_MINILIST', 27);
class ProfileMiniList extends ProfileList class ProfileMiniList extends ProfileList
{ {
function show() function startList()
{ {
$this->out->elementStart('ul', 'entities users xoxo'); $this->out->elementStart('ul', 'entities users xoxo');
$cnt = 0;
while ($this->profile->fetch()) {
$cnt++;
if($cnt > PROFILES_PER_MINILIST) {
break;
}
$this->showProfile();
}
$this->out->elementEnd('ul');
return $cnt;
} }
function showProfile() function newListItem($profile)
{
return new ProfileMiniListItem($profile, $this->action);
}
}
class ProfileMiniListItem extends ProfileListItem
{
function show()
{ {
$this->out->elementStart('li', 'vcard'); $this->out->elementStart('li', 'vcard');
$this->out->elementStart('a', array('title' => $this->profile->getBestName(), $this->out->elementStart('a', array('title' => $this->profile->getBestName(),

View File

@ -101,7 +101,8 @@ class Router
$main = array('login', 'logout', 'register', 'subscribe', $main = array('login', 'logout', 'register', 'subscribe',
'unsubscribe', 'confirmaddress', 'recoverpassword', 'unsubscribe', 'confirmaddress', 'recoverpassword',
'invite', 'favor', 'disfavor', 'sup', 'invite', 'favor', 'disfavor', 'sup',
'block', 'subedit'); 'block', 'unblock', 'subedit',
'groupblock', 'groupunblock');
foreach ($main as $a) { foreach ($main as $a) {
$m->connect('main/'.$a, array('action' => $a)); $m->connect('main/'.$a, array('action' => $a));
@ -164,10 +165,10 @@ class Router
array('action' => 'newnotice'), array('action' => 'newnotice'),
array('replyto' => '[A-Za-z0-9_-]+')); array('replyto' => '[A-Za-z0-9_-]+'));
$m->connect('notice/:notice/file', $m->connect('notice/:notice/file',
array('action' => 'file'), array('action' => 'file'),
array('notice' => '[0-9]+')); array('notice' => '[0-9]+'));
$m->connect('notice/:notice', $m->connect('notice/:notice',
array('action' => 'shownotice'), array('action' => 'shownotice'),
array('notice' => '[0-9]+')); array('notice' => '[0-9]+'));
@ -228,6 +229,14 @@ class Router
array('nickname' => '[a-zA-Z0-9]+')); array('nickname' => '[a-zA-Z0-9]+'));
} }
$m->connect('group/:nickname/blocked',
array('action' => 'blockedfromgroup'),
array('nickname' => '[a-zA-Z0-9]+'));
$m->connect('group/:nickname/makeadmin',
array('action' => 'makeadmin'),
array('nickname' => '[a-zA-Z0-9]+'));
$m->connect('group/:id/id', $m->connect('group/:id/id',
array('action' => 'groupbyid'), array('action' => 'groupbyid'),
array('id' => '[0-9]+')); array('id' => '[0-9]+'));

131
lib/subscriptionlist.php Normal file
View File

@ -0,0 +1,131 @@
<?php
/**
* Laconica, the distributed open-source microblogging tool
*
* Widget to show a list of profiles
*
* PHP version 5
*
* LICENCE: This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @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);
}
require_once INSTALLDIR.'/lib/profilelist.php';
/**
* Widget to show a list of subscriptions
*
* @category Public
* @package Laconica
* @author Zach Copley <zach@controlyourself.ca>
* @author Evan Prodromou <evan@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://laconi.ca/
*/
class SubscriptionList extends ProfileList
{
/** Owner of this list */
var $owner = null;
function __construct($profile, $owner=null, $action=null)
{
parent::__construct($profile, $action);
$this->owner = $owner;
}
function newListItem($profile)
{
return new SubscriptionListItem($profile, $this->owner, $this->action);
}
}
class SubscriptionListItem extends ProfileListItem
{
/** Owner of this list */
var $owner = null;
function __construct($profile, $owner, $action)
{
parent::__construct($profile, $action);
$this->owner = $owner;
}
function showProfile()
{
$this->startProfile();
$this->showAvatar();
$this->showFullName();
$this->showLocation();
$this->showHomepage();
$this->showBio();
// Relevant portion!
$this->showTags();
$this->endProfile();
}
function isOwn()
{
$user = common_current_user();
return (!empty($user) && ($this->owner->id == $user->id));
}
function showTags()
{
$tags = Profile_tag::getTags($this->owner->id, $this->profile->id);
$this->out->elementStart('dl', 'entity_tags');
$this->out->elementStart('dt');
if ($this->isOwn()) {
$this->out->element('a', array('href' => common_local_url('tagother',
array('id' => $this->profile->id))),
_('Tags'));
} else {
$this->out->text(_('Tags'));
}
$this->out->elementEnd('dt');
$this->out->elementStart('dd');
if ($tags) {
$this->out->elementStart('ul', 'tags xoxo');
foreach ($tags as $tag) {
$this->out->elementStart('li');
$this->out->element('span', 'mark_hash', '#');
$this->out->element('a', array('rel' => 'tag',
'href' => common_local_url($this->action->trimmed('action'),
array('nickname' => $this->owner->nickname,
'tag' => $tag))),
$tag);
$this->out->elementEnd('li');
}
$this->out->elementEnd('ul');
} else {
$this->out->text(_('(none)'));
}
$this->out->elementEnd('dd');
$this->out->elementEnd('dl');
}
}

View File

@ -70,30 +70,3 @@ function theme_path($relative, $theme=null)
return common_path('theme/'.$theme.'/'.$relative); return common_path('theme/'.$theme.'/'.$relative);
} }
} }
/**
* Gets the full URL of a file in a skin dir based on its relative name
*
* @param string $relative relative path within the theme, skin directory
* @param string $theme name of the theme; defaults to current theme
* @param string $skin name of the skin; defaults to current theme
*
* @return string URL of the file
*/
function skin_path($relative, $theme=null, $skin=null)
{
if (!$theme) {
$theme = common_config('site', 'theme');
}
if (!$skin) {
$skin = common_config('site', 'skin');
}
$server = common_config('theme', 'server');
if ($server) {
return 'http://'.$server.'/'.$theme.'/skin/'.$skin.'/'.$relative;
} else {
return common_path('theme/'.$theme.'/skin/'.$skin.'/'.$relative);
}
}

View File

@ -591,7 +591,7 @@ function common_at_link($sender_id, $nickname)
function common_group_link($sender_id, $nickname) function common_group_link($sender_id, $nickname)
{ {
$sender = Profile::staticGet($sender_id); $sender = Profile::staticGet($sender_id);
$group = User_group::staticGet('nickname', common_canonical_nickname($nickname)); $group = User_group::getForNickname($nickname);
if ($group && $sender->isMember($group)) { if ($group && $sender->isMember($group)) {
$attrs = array('href' => $group->permalink(), $attrs = array('href' => $group->permalink(),
'class' => 'url'); 'class' => 'url');

View File

@ -66,7 +66,13 @@ class MailerDaemon
return true; return true;
} }
$msg = $this->cleanup_msg($msg); $msg = $this->cleanup_msg($msg);
$this->add_notice($user, $msg); $err = $this->add_notice($user, $msg);
if (is_string($err)) {
$this->error($from, $err);
return false;
} else {
return true;
}
} }
function error($from, $msg) function error($from, $msg)
@ -130,17 +136,15 @@ class MailerDaemon
function add_notice($user, $msg) function add_notice($user, $msg)
{ {
// should test
// $msg_shortened = common_shorten_links($msg);
// if (mb_strlen($msg_shortened) > 140) ERROR and STOP
$notice = Notice::saveNew($user->id, $msg, 'mail'); $notice = Notice::saveNew($user->id, $msg, 'mail');
if (is_string($notice)) { if (is_string($notice)) {
$this->log(LOG_ERR, $notice); $this->log(LOG_ERR, $notice);
return; return $notice;
} }
common_broadcast_notice($notice); common_broadcast_notice($notice);
$this->log(LOG_INFO, $this->log(LOG_INFO,
'Added notice ' . $notice->id . ' from user ' . $user->nickname); 'Added notice ' . $notice->id . ' from user ' . $user->nickname);
return true;
} }
function parse_message($fname) function parse_message($fname)

View File

@ -445,6 +445,8 @@ width:80.789%;
height:67px; height:67px;
line-height:1.5; line-height:1.5;
padding:7px 7px 16px 7px; padding:7px 7px 16px 7px;
position:relative;
z-index:2;
} }
#form_notice label { #form_notice label {
display:block; display:block;
@ -452,23 +454,23 @@ float:left;
font-size:1.3em; font-size:1.3em;
margin-bottom:7px; margin-bottom:7px;
} }
#form_notice label[for=notice_data-attach] {
text-indent:-9999px;
}
#form_notice label[for=notice_data-attach], #form_notice label[for=notice_data-attach],
#form_notice #notice_data-attach { #form_notice #notice_data-attach {
position:absolute; position:absolute;
top:25px; top:25px;
right:49px;
width:16px;
height:16px;
cursor:pointer; cursor:pointer;
} }
#form_notice #notice_data-attach { #form_notice label[for=notice_data-attach] {
text-indent:-279px; text-indent:-9999px;
left:394px;
width:16px;
height:16px;
} }
#form_notice #notice_submit label { #form_notice #notice_data-attach {
display:none; left:183px;
padding:0;
height:16px;
} }
#form_notice .form_note { #form_notice .form_note {
position:absolute; position:absolute;
@ -616,6 +618,8 @@ display:block;
.form_user_block input.submit, .form_user_block input.submit,
.form_user_unblock input.submit, .form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit,
.entity_send-a-message a, .entity_send-a-message a,
.entity_edit a, .entity_edit a,
.form_user_nudge input.submit, .form_user_nudge input.submit,

View File

@ -8,6 +8,15 @@ top:0;
#form_notice textarea { #form_notice textarea {
width:78%; width:78%;
} }
#form_notice .form_note + label {
position:absolute;
top:25px;
left:380px;
text-indent:-9999px;
height:16px;
width:16px;
display:block;
}
#form_notice #notice_action-submit { #form_notice #notice_action-submit {
width:17%; width:17%;
max-width:17%; max-width:17%;

View File

@ -57,6 +57,8 @@ a,
div.notice-options input, div.notice-options input,
.form_user_block input.submit, .form_user_block input.submit,
.form_user_unblock input.submit, .form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit,
.entity_send-a-message a, .entity_send-a-message a,
.form_user_nudge input.submit, .form_user_nudge input.submit,
.entity_nudge p, .entity_nudge p,
@ -148,6 +150,8 @@ background-image:url(../../base/images/icons/icon_foaf.gif);
.form_user_nudge input.submit, .form_user_nudge input.submit,
.form_user_block input.submit, .form_user_block input.submit,
.form_user_unblock input.submit, .form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit,
.entity_nudge p { .entity_nudge p {
background-position: 0 40%; background-position: 0 40%;
background-repeat: no-repeat; background-repeat: no-repeat;
@ -177,7 +181,9 @@ background-image:url(../../base/images/icons/twotone/green/quote.gif);
background-image:url(../../base/images/icons/twotone/green/mail.gif); background-image:url(../../base/images/icons/twotone/green/mail.gif);
} }
.form_user_block input.submit, .form_user_block input.submit,
.form_user_unblock input.submit { .form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit {
background-image:url(../../base/images/icons/twotone/green/shield.gif); background-image:url(../../base/images/icons/twotone/green/shield.gif);
} }

View File

@ -3,7 +3,12 @@
.notice-options input.submit { .notice-options input.submit {
color:#fff; color:#fff;
} }
#site_nav_local_views a { #site_nav_local_views a {
background-color:#ACCCDA; background-color:#ACCCDA;
} }
#form_notice .form_note + label {
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
}
#form_notice #notice_data-attach {
filter: alpha(opacity=0);
}

View File

@ -57,6 +57,8 @@ a,
div.notice-options input, div.notice-options input,
.form_user_block input.submit, .form_user_block input.submit,
.form_user_unblock input.submit, .form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit,
.entity_send-a-message a, .entity_send-a-message a,
.form_user_nudge input.submit, .form_user_nudge input.submit,
.entity_nudge p, .entity_nudge p,
@ -148,6 +150,8 @@ background-image:url(../../base/images/icons/icon_foaf.gif);
.form_user_nudge input.submit, .form_user_nudge input.submit,
.form_user_block input.submit, .form_user_block input.submit,
.form_user_unblock input.submit, .form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit,
.entity_nudge p { .entity_nudge p {
background-position: 0 40%; background-position: 0 40%;
background-repeat: no-repeat; background-repeat: no-repeat;
@ -177,7 +181,9 @@ background-image:url(../../base/images/icons/twotone/green/quote.gif);
background-image:url(../../base/images/icons/twotone/green/mail.gif); background-image:url(../../base/images/icons/twotone/green/mail.gif);
} }
.form_user_block input.submit, .form_user_block input.submit,
.form_user_unblock input.submit { .form_user_unblock input.submit,
.form_group_block input.submit,
.form_group_unblock input.submit {
background-image:url(../../base/images/icons/twotone/green/shield.gif); background-image:url(../../base/images/icons/twotone/green/shield.gif);
} }

View File

@ -3,7 +3,12 @@
.notice-options input.submit { .notice-options input.submit {
color:#fff; color:#fff;
} }
#site_nav_local_views a { #site_nav_local_views a {
background-color:#D0DFE7; background-color:#D0DFE7;
} }
#form_notice .form_note + label {
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
}
#form_notice #notice_data-attach {
filter: alpha(opacity=0);
}