Merge remote-tracking branch 'mainline/1.0.x' into people_tags_rebase
Conflicts: actions/tagother.php classes/Profile.php classes/Profile_tag.php js/util.min.js
This commit is contained in:
commit
5a2bab07b2
2
README
2
README
@ -1472,6 +1472,8 @@ Configuration options specific to notices.
|
||||
contentlimit: max length of the plain-text content of a notice.
|
||||
Default is null, meaning to use the site-wide text limit.
|
||||
0 means no limit.
|
||||
defaultscope: default scope for notices. Defaults to 0; set to
|
||||
1 to keep notices private to this site by default.
|
||||
|
||||
message
|
||||
-------
|
||||
|
@ -78,22 +78,6 @@ class ApiStatusesRetweetAction extends ApiAuthAction
|
||||
|
||||
$this->user = $this->auth_user;
|
||||
|
||||
if ($this->user->id == $this->original->profile_id) {
|
||||
// TRANS: Client error displayed trying to repeat an own notice through the API.
|
||||
$this->clientError(_('Cannot repeat your own notice.'),
|
||||
400, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
if ($profile->hasRepeated($id)) {
|
||||
// TRANS: Client error displayed trying to re-repeat a notice through the API.
|
||||
$this->clientError(_('Already repeated that notice.'),
|
||||
400, $this->format);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,7 @@ class ApprovegroupAction extends Action
|
||||
|
||||
$cur = common_current_user();
|
||||
if (empty($cur)) {
|
||||
// TRANS: Client error displayed trying to approve group membership while not logged in.
|
||||
$this->clientError(_('Must be logged in.'), 403);
|
||||
return false;
|
||||
}
|
||||
@ -105,10 +106,12 @@ class ApprovegroupAction extends Action
|
||||
if ($cur->isAdmin($this->group)) {
|
||||
$this->profile = Profile::staticGet('id', $this->arg('profile_id'));
|
||||
} else {
|
||||
// TRANS: Client error displayed trying to approve group membership while not a group administrator.
|
||||
$this->clientError(_('Only group admin can approve or cancel join requests.'), 403);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// TRANS: Client error displayed trying to approve group membership without specifying a profile to approve.
|
||||
$this->clientError(_('Must specify a profile.'));
|
||||
return false;
|
||||
}
|
||||
@ -117,8 +120,21 @@ class ApprovegroupAction extends Action
|
||||
'group_id' => $this->group->id));
|
||||
|
||||
if (empty($this->request)) {
|
||||
// TRANS: Client error displayed trying to approve group membership for a non-existing request.
|
||||
// TRANS: %s is a nickname.
|
||||
$this->clientError(sprintf(_('%s is not in the moderation queue for this group.'), $this->profile->nickname), 403);
|
||||
}
|
||||
|
||||
$this->approve = (bool)$this->arg('approve');
|
||||
$this->cancel = (bool)$this->arg('cancel');
|
||||
if (!$this->approve && !$this->cancel) {
|
||||
// TRANS: Client error displayed trying to approve/deny group membership.
|
||||
$this->clientError(_('Internal error: received neither cancel nor abort.'));
|
||||
}
|
||||
if ($this->approve && $this->cancel) {
|
||||
// TRANS: Client error displayed trying to approve/deny group membership.
|
||||
$this->clientError(_('Internal error: received both cancel and abort.'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -136,9 +152,13 @@ class ApprovegroupAction extends Action
|
||||
parent::handle($args);
|
||||
|
||||
try {
|
||||
$this->profile->completeJoinGroup($this->group);
|
||||
if ($this->approve) {
|
||||
$this->request->complete();
|
||||
} elseif ($this->cancel) {
|
||||
$this->request->abort();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_ERROR, "Exception canceling group sub: " . $e->getMessage());
|
||||
common_log(LOG_ERR, "Exception canceling group sub: " . $e->getMessage());
|
||||
// TRANS: Server error displayed when cancelling a queued group join request fails.
|
||||
// TRANS: %1$s is the leaving user's nickname, $2$s is the group nickname for which the leave failed.
|
||||
$this->serverError(sprintf(_('Could not cancel request for user %1$s to join group %2$s.'),
|
||||
@ -149,14 +169,20 @@ class ApprovegroupAction extends Action
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Title for leave group page after leaving.
|
||||
$this->element('title', null, sprintf(_m('TITLE','%1$s left group %2$s'),
|
||||
// TRANS: Title for leave group page after group join request is approved/disapproved.
|
||||
// TRANS: %1$s is the user nickname, %2$s is the group nickname.
|
||||
$this->element('title', null, sprintf(_m('TITLE','%1$s\'s request for %2$s'),
|
||||
$this->profile->nickname,
|
||||
$this->group->nickname));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$jf = new JoinForm($this, $this->group);
|
||||
$jf->show();
|
||||
if ($this->approve) {
|
||||
// TRANS: Message on page for group admin after approving a join request.
|
||||
$this->element('p', 'success', _('Join request approved.'));
|
||||
} elseif ($this->cancel) {
|
||||
// TRANS: Message on page for group admin after rejecting a join request.
|
||||
$this->element('p', 'success', _('Join request canceled.'));
|
||||
}
|
||||
$this->elementEnd('body');
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
|
145
actions/approvesub.php
Normal file
145
actions/approvesub.php
Normal file
@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Approve group subscription request
|
||||
*
|
||||
* 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 StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave a group
|
||||
*
|
||||
* This is the action for leaving a group. It works more or less like the subscribe action
|
||||
* for users.
|
||||
*
|
||||
* @category Group
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ApprovesubAction extends Action
|
||||
{
|
||||
var $profile = null;
|
||||
|
||||
/**
|
||||
* Prepare to run
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$cur = common_current_user();
|
||||
if (empty($cur)) {
|
||||
// TRANS: Client error displayed trying to approve group membership while not logged in.
|
||||
$this->clientError(_('Must be logged in.'), 403);
|
||||
return false;
|
||||
}
|
||||
if ($this->arg('profile_id')) {
|
||||
$this->profile = Profile::staticGet('id', $this->arg('profile_id'));
|
||||
} else {
|
||||
// TRANS: Client error displayed trying to approve subscriptionswithout specifying a profile to approve.
|
||||
$this->clientError(_('Must specify a profile.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->request = Subscription_queue::pkeyGet(array('subscriber' => $this->profile->id,
|
||||
'subscribed' => $cur->id));
|
||||
|
||||
if (empty($this->request)) {
|
||||
// TRANS: Client error displayed trying to approve subscription for a non-existing request.
|
||||
$this->clientError(sprintf(_('%s is not in the moderation queue for your subscriptions.'), $this->profile->nickname), 403);
|
||||
}
|
||||
|
||||
$this->approve = (bool)$this->arg('approve');
|
||||
$this->cancel = (bool)$this->arg('cancel');
|
||||
if (!$this->approve && !$this->cancel) {
|
||||
// TRANS: Client error displayed trying to approve/deny subscription.
|
||||
$this->clientError(_('Internal error: received neither cancel nor abort.'));
|
||||
}
|
||||
if ($this->approve && $this->cancel) {
|
||||
// TRANS: Client error displayed trying to approve/deny subscription
|
||||
$this->clientError(_('Internal error: received both cancel and abort.'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* On POST, add the current user to the group
|
||||
*
|
||||
* @param array $args unused
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$cur = common_current_user();
|
||||
|
||||
try {
|
||||
if ($this->approve) {
|
||||
$this->request->complete();
|
||||
} elseif ($this->cancel) {
|
||||
$this->request->abort();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_ERR, "Exception canceling sub: " . $e->getMessage());
|
||||
// TRANS: Server error displayed when cancelling a queued subscription request fails.
|
||||
// TRANS: %1$s is the leaving user's nickname, $2$s is the nickname for which the leave failed.
|
||||
$this->serverError(sprintf(_('Could not cancel or approve request for user %1$s to join group %2$s.'),
|
||||
$this->profile->nickname, $cur->nickname));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Title for subscription approval ajax return
|
||||
// TRANS: %1$s is the approved user's nickname
|
||||
$this->element('title', null, sprintf(_m('TITLE','%1$s\'s request'),
|
||||
$this->profile->nickname));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
if ($this->approve) {
|
||||
// TRANS: Message on page for user after approving a subscription request.
|
||||
$this->element('p', 'success', _('Subscription approved.'));
|
||||
} elseif ($this->cancel) {
|
||||
// TRANS: Message on page for user after rejecting a subscription request.
|
||||
$this->element('p', 'success', _('Subscription canceled.'));
|
||||
}
|
||||
$this->elementEnd('body');
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
common_redirect(common_local_url('subqueue', array('nickname' =>
|
||||
$cur->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
@ -141,7 +141,7 @@ class AtompubmembershipfeedAction extends ApiAuthAction
|
||||
|
||||
// TRANS: Title for group membership feed.
|
||||
// TRANS: %s is a username.
|
||||
$feed->setTitle(sprintf(_("%s group memberships"),
|
||||
$feed->setTitle(sprintf(_('Group memberships of %s'),
|
||||
$this->_profile->getBestName()));
|
||||
|
||||
// TRANS: Subtitle for group membership feed.
|
||||
@ -237,8 +237,7 @@ class AtompubmembershipfeedAction extends ApiAuthAction
|
||||
|
||||
if (Event::handle('StartAtomPubNewActivity', array(&$activity))) {
|
||||
if ($activity->verb != ActivityVerb::JOIN) {
|
||||
// TRANS: Client error displayed when not using the POST verb.
|
||||
// TRANS: Do not translate POST.
|
||||
// TRANS: Client error displayed when not using the join verb.
|
||||
throw new ClientException(_('Can only handle join activities.'));
|
||||
return;
|
||||
}
|
||||
|
@ -68,7 +68,6 @@ class CancelgroupAction extends Action
|
||||
$nickname = common_canonical_nickname($nickname_arg);
|
||||
|
||||
// Permanent redirect on non-canonical nickname
|
||||
|
||||
if ($nickname_arg != $nickname) {
|
||||
$args = array('nickname' => $nickname);
|
||||
common_redirect(common_local_url('leavegroup', $args), 301);
|
||||
@ -98,6 +97,7 @@ class CancelgroupAction extends Action
|
||||
|
||||
$cur = common_current_user();
|
||||
if (empty($cur)) {
|
||||
// TRANS: Client error displayed when trying to leave a group while not logged in.
|
||||
$this->clientError(_('Must be logged in.'), 403);
|
||||
return false;
|
||||
}
|
||||
@ -105,6 +105,8 @@ class CancelgroupAction extends Action
|
||||
if ($cur->isAdmin($this->group)) {
|
||||
$this->profile = Profile::staticGet('id', $this->arg('profile_id'));
|
||||
} else {
|
||||
// TRANS: Client error displayed when trying to approve or cancel a group join request without
|
||||
// TRANS: being a group administrator.
|
||||
$this->clientError(_('Only group admin can approve or cancel join requests.'), 403);
|
||||
return false;
|
||||
}
|
||||
@ -116,6 +118,8 @@ class CancelgroupAction extends Action
|
||||
'group_id' => $this->group->id));
|
||||
|
||||
if (empty($this->request)) {
|
||||
// TRANS: Client error displayed when trying to approve a non-existing group join request.
|
||||
// TRANS: %s is a user nickname.
|
||||
$this->clientError(sprintf(_('%s is not in the moderation queue for this group.'), $this->profile->nickname), 403);
|
||||
}
|
||||
return true;
|
||||
@ -135,9 +139,9 @@ class CancelgroupAction extends Action
|
||||
parent::handle($args);
|
||||
|
||||
try {
|
||||
$this->profile->cancelJoinGroup($this->group);
|
||||
$this->request->abort();
|
||||
} catch (Exception $e) {
|
||||
common_log(LOG_ERROR, "Exception canceling group sub: " . $e->getMessage());
|
||||
common_log(LOG_ERR, "Exception canceling group sub: " . $e->getMessage());
|
||||
// TRANS: Server error displayed when cancelling a queued group join request fails.
|
||||
// TRANS: %1$s is the leaving user's nickname, $2$s is the group nickname for which the leave failed.
|
||||
$this->serverError(sprintf(_('Could not cancel request for user %1$s to join group %2$s.'),
|
||||
@ -149,6 +153,7 @@ class CancelgroupAction extends Action
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Title for leave group page after leaving.
|
||||
// TRANS: %s$s is the leaving user's name, %2$s is the group name.
|
||||
$this->element('title', null, sprintf(_m('TITLE','%1$s left group %2$s'),
|
||||
$this->profile->nickname,
|
||||
$this->group->nickname));
|
||||
|
123
actions/cancelsubscription.php
Normal file
123
actions/cancelsubscription.php
Normal file
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Leave a group
|
||||
*
|
||||
* 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 StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave a group
|
||||
*
|
||||
* This is the action for leaving a group. It works more or less like the subscribe action
|
||||
* for users.
|
||||
*
|
||||
* @category Group
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class CancelsubscriptionAction extends Action
|
||||
{
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
if ($this->boolean('ajax')) {
|
||||
StatusNet::setApi(true);
|
||||
}
|
||||
if (!common_logged_in()) {
|
||||
// TRANS: Client error displayed when trying to leave a group while not logged in.
|
||||
$this->clientError(_('Not logged in.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
|
||||
common_redirect(common_local_url('subscriptions',
|
||||
array('nickname' => $user->nickname)));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Use a session token for CSRF protection. */
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->clientError(_('There was a problem with your session token. ' .
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$other_id = $this->arg('unsubscribeto');
|
||||
|
||||
if (!$other_id) {
|
||||
// TRANS: Client error displayed when trying to leave a group without specifying an ID.
|
||||
$this->clientError(_('No profile ID in request.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$other = Profile::staticGet('id', $other_id);
|
||||
|
||||
if (!$other) {
|
||||
// TRANS: Client error displayed when trying to leave a non-existing group.
|
||||
$this->clientError(_('No profile with that ID.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->request = Subscription_queue::pkeyGet(array('subscriber' => $user->id,
|
||||
'subscribed' => $other->id));
|
||||
|
||||
if (empty($this->request)) {
|
||||
// TRANS: Client error displayed when trying to approve a non-existing group join request.
|
||||
// TRANS: %s is a user nickname.
|
||||
$this->clientError(sprintf(_('%s is not in the moderation queue for this group.'), $this->profile->nickname), 403);
|
||||
}
|
||||
|
||||
$this->request->abort();
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Title after unsubscribing from a group.
|
||||
$this->element('title', null, _m('TITLE','Unsubscribed'));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$subscribe = new SubscribeForm($this, $other);
|
||||
$subscribe->show();
|
||||
$this->elementEnd('body');
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
common_redirect(common_local_url('subscriptions',
|
||||
array('nickname' => $user->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
@ -52,7 +52,7 @@ class GroupqueueAction extends GroupDesignAction
|
||||
return true;
|
||||
}
|
||||
|
||||
// fixme most of this belongs in a base class, sounds common to most group actions?
|
||||
// @todo FIXME: most of this belongs in a base class, sounds common to most group actions?
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
@ -96,6 +96,7 @@ class GroupqueueAction extends GroupDesignAction
|
||||
|
||||
$cur = common_current_user();
|
||||
if (!$cur || !$cur->isAdmin($this->group)) {
|
||||
// TRANS: Client error displayed when trying to approve group applicants without being a group administrator.
|
||||
$this->clientError(_('Only the group admin may approve users.'));
|
||||
return false;
|
||||
}
|
||||
@ -105,12 +106,12 @@ class GroupqueueAction extends GroupDesignAction
|
||||
function title()
|
||||
{
|
||||
if ($this->page == 1) {
|
||||
// TRANS: Title of the page showing pending group members still awaiting approval to join the group.
|
||||
// TRANS: Title of the first 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: Title of all but the first 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,
|
||||
@ -155,11 +156,12 @@ class GroupqueueAction extends GroupDesignAction
|
||||
$members->free();
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
|
||||
$this->page, 'groupmembers',
|
||||
$this->page, 'groupqueue',
|
||||
array('nickname' => $this->group->nickname));
|
||||
}
|
||||
}
|
||||
|
||||
// @todo FIXME: documentation missing.
|
||||
class GroupQueueList extends GroupMemberList
|
||||
{
|
||||
function newListItem($profile)
|
||||
@ -168,32 +170,24 @@ class GroupQueueList extends GroupMemberList
|
||||
}
|
||||
}
|
||||
|
||||
// @todo FIXME: documentation missing.
|
||||
class GroupQueueListItem extends GroupMemberListItem
|
||||
{
|
||||
function showActions()
|
||||
{
|
||||
$this->startActions();
|
||||
if (Event::handle('StartProfileListItemActionElements', array($this))) {
|
||||
$this->showApproveButton();
|
||||
$this->showCancelButton();
|
||||
$this->showApproveButtons();
|
||||
Event::handle('EndProfileListItemActionElements', array($this));
|
||||
}
|
||||
$this->endActions();
|
||||
}
|
||||
|
||||
function showApproveButton()
|
||||
function showApproveButtons()
|
||||
{
|
||||
$this->out->elementStart('li', 'entity_join');
|
||||
$this->out->elementStart('li', 'entity_approval');
|
||||
$form = new ApproveGroupForm($this->out, $this->group, $this->profile);
|
||||
$form->show();
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
|
||||
function showCancelButton()
|
||||
{
|
||||
$this->out->elementStart('li', 'entity_leave');
|
||||
$bf = new CancelGroupForm($this->out, $this->group, $this->profile);
|
||||
$bf->show();
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ class InviteAction extends CurrentUserDesignAction
|
||||
|
||||
function sendInvitations()
|
||||
{
|
||||
# CSRF protection
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. Try again, please.'));
|
||||
|
@ -154,7 +154,8 @@ class JoingroupAction extends Action
|
||||
$form = new CancelGroupForm($this, $this->group);
|
||||
} else {
|
||||
// wtf?
|
||||
throw new Exception(_m("Unknown error joining group."));
|
||||
// TRANS: Exception thrown when there is an unknown error joining a group.
|
||||
throw new Exception(_("Unknown error joining group."));
|
||||
}
|
||||
$form->show();
|
||||
$this->elementEnd('body');
|
||||
|
@ -209,6 +209,10 @@ class NewnoticeAction extends Action
|
||||
$author_id = $user->id;
|
||||
$text = $content_shortened;
|
||||
|
||||
// Does the heavy-lifting for getting "To:" information
|
||||
|
||||
ToSelector::fillOptions($this, $options);
|
||||
|
||||
if (Event::handle('StartNoticeSaveWeb', array($this, &$author_id, &$text, &$options))) {
|
||||
|
||||
$notice = Notice::saveNew($user->id, $content_shortened, 'web', $options);
|
||||
@ -344,7 +348,9 @@ class NewnoticeAction extends Action
|
||||
$inreplyto = null;
|
||||
}
|
||||
|
||||
$notice_form = new NoticeForm($this, '', $content, null, $inreplyto);
|
||||
$notice_form = new NoticeForm($this, array('content' => $content,
|
||||
'inreplyto' => $inreplyto));
|
||||
|
||||
$notice_form->show();
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ class PasswordsettingsAction extends SettingsAction
|
||||
$newpassword = $this->arg('newpassword');
|
||||
$confirm = $this->arg('confirm');
|
||||
|
||||
# Some validation
|
||||
// Some validation
|
||||
|
||||
if (strlen($newpassword) < 6) {
|
||||
// TRANS: Form validation error on page where to change password.
|
||||
|
@ -33,8 +33,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Change profile settings
|
||||
*
|
||||
@ -46,7 +44,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ProfilesettingsAction extends SettingsAction
|
||||
{
|
||||
/**
|
||||
@ -127,15 +124,15 @@ class ProfilesettingsAction extends SettingsAction
|
||||
// TRANS: Tooltip for field label in form for profile settings. Plural
|
||||
// TRANS: is decided by the number of characters available for the
|
||||
// TRANS: biography (%d).
|
||||
$bioInstr = sprintf(_m('Describe yourself and your interests in %d character',
|
||||
'Describe yourself and your interests in %d characters',
|
||||
$bioInstr = sprintf(_m('Describe yourself and your interests in %d character.',
|
||||
'Describe yourself and your interests in %d characters.',
|
||||
$maxBio),
|
||||
$maxBio);
|
||||
} else {
|
||||
// TRANS: Tooltip for field label in form for profile settings.
|
||||
$bioInstr = _('Describe yourself and your interests');
|
||||
$bioInstr = _('Describe yourself and your interests.');
|
||||
}
|
||||
// TRANS: Text area label in form for profile settings where users can provide.
|
||||
// TRANS: Text area label in form for profile settings where users can provide
|
||||
// TRANS: their biography.
|
||||
$this->textarea('bio', _('Bio'),
|
||||
($this->arg('bio')) ? $this->arg('bio') : $profile->bio,
|
||||
@ -146,7 +143,7 @@ class ProfilesettingsAction extends SettingsAction
|
||||
$this->input('location', _('Location'),
|
||||
($this->arg('location')) ? $this->arg('location') : $profile->location,
|
||||
// TRANS: Tooltip for field label in form for profile settings.
|
||||
_('Where you are, like "City, State (or Region), Country"'));
|
||||
_('Where you are, like "City, State (or Region), Country".'));
|
||||
$this->elementEnd('li');
|
||||
if (common_config('location', 'share') == 'user') {
|
||||
$this->elementStart('li');
|
||||
@ -192,6 +189,19 @@ class ProfilesettingsAction extends SettingsAction
|
||||
($this->arg('autosubscribe')) ?
|
||||
$this->boolean('autosubscribe') : $user->autosubscribe);
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->dropdown('subscribe_policy',
|
||||
// TRANS: Dropdown field label on profile settings, for what policies to apply when someone else tries to subscribe to your updates.
|
||||
_('Subscription policy'),
|
||||
// TRANS: Dropdown field option for following policy.
|
||||
array(User::SUBSCRIBE_POLICY_OPEN => _('Let anyone follow me'),
|
||||
// TRANS: Dropdown field option for following policy.
|
||||
User::SUBSCRIBE_POLICY_MODERATE => _('Ask me first')),
|
||||
// TRANS: Dropdown field title on group edit form.
|
||||
_('Whether other users need your permission to follow your updates.'),
|
||||
false,
|
||||
(empty($user->subscribe_policy)) ? User::SUBSCRIBE_POLICY_OPEN : $user->subscribe_policy);
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
// TRANS: Button to save input in profile settings.
|
||||
@ -234,6 +244,7 @@ class ProfilesettingsAction extends SettingsAction
|
||||
$bio = $this->trimmed('bio');
|
||||
$location = $this->trimmed('location');
|
||||
$autosubscribe = $this->boolean('autosubscribe');
|
||||
$subscribe_policy = $this->trimmed('subscribe_policy');
|
||||
$language = $this->trimmed('language');
|
||||
$timezone = $this->trimmed('timezone');
|
||||
$tagstring = $this->trimmed('tags');
|
||||
@ -339,11 +350,12 @@ class ProfilesettingsAction extends SettingsAction
|
||||
}
|
||||
|
||||
// XXX: XOR
|
||||
if ($user->autosubscribe ^ $autosubscribe) {
|
||||
if (($user->autosubscribe ^ $autosubscribe) || $user->subscribe_policy != $subscribe_policy) {
|
||||
|
||||
$original = clone($user);
|
||||
|
||||
$user->autosubscribe = $autosubscribe;
|
||||
$user->subscribe_policy = $subscribe_policy;
|
||||
|
||||
$result = $user->update($original);
|
||||
|
||||
@ -351,7 +363,7 @@ class ProfilesettingsAction extends SettingsAction
|
||||
common_log_db_error($user, 'UPDATE', __FILE__);
|
||||
// TRANS: Server error thrown when user profile settings could not be updated to
|
||||
// TRANS: automatically subscribe to any subscriber.
|
||||
$this->serverError(_('Could not update user for autosubscribe.'));
|
||||
$this->serverError(_('Could not update user for autosubscribe or subscribe_policy.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -85,8 +85,11 @@ class PublicAction extends Action
|
||||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
$this->notice = Notice::publicStream(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1);
|
||||
$stream = new PublicNoticeStream(PublicNoticeStream::THREADED);
|
||||
$this->notice = $stream->getNotices(($this->page-1)*NOTICES_PER_PAGE,
|
||||
NOTICES_PER_PAGE + 1,
|
||||
0,
|
||||
0);
|
||||
|
||||
if (!$this->notice) {
|
||||
// TRANS: Server error displayed when a public timeline cannot be retrieved.
|
||||
|
@ -100,7 +100,7 @@ class PublictagcloudAction extends Action
|
||||
|
||||
function showContent()
|
||||
{
|
||||
# This should probably be cached rather than recalculated
|
||||
// This should probably be cached rather than recalculated
|
||||
$tags = new Notice_tag();
|
||||
|
||||
#Need to clear the selection and then only re-add the field
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
# You have 24 hours to claim your password
|
||||
// You have 24 hours to claim your password
|
||||
|
||||
define('MAX_RECOVERY_TIME', 24 * 60 * 60);
|
||||
|
||||
@ -81,7 +81,7 @@ class RecoverpasswordAction extends Action
|
||||
$touched = strtotime($confirm->modified);
|
||||
$email = $confirm->address;
|
||||
|
||||
# Burn this code
|
||||
// Burn this code
|
||||
|
||||
$result = $confirm->delete();
|
||||
|
||||
@ -92,8 +92,8 @@ class RecoverpasswordAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
# These should be reaped, but for now we just check mod time
|
||||
# Note: it's still deleted; let's avoid a second attempt!
|
||||
// These should be reaped, but for now we just check mod time
|
||||
// Note: it's still deleted; let's avoid a second attempt!
|
||||
|
||||
if ((time() - $touched) > MAX_RECOVERY_TIME) {
|
||||
common_log(LOG_WARNING,
|
||||
@ -105,8 +105,8 @@ class RecoverpasswordAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
# If we used an outstanding confirmation to send the email,
|
||||
# it's been confirmed at this point.
|
||||
// If we used an outstanding confirmation to send the email,
|
||||
// it's been confirmed at this point.
|
||||
|
||||
if (!$user->email) {
|
||||
$orig = clone($user);
|
||||
@ -120,7 +120,7 @@ class RecoverpasswordAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
# Success!
|
||||
// Success!
|
||||
|
||||
$this->setTempUser($user);
|
||||
$this->showPasswordForm();
|
||||
@ -289,7 +289,7 @@ class RecoverpasswordAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
# See if it's an unconfirmed email address
|
||||
// See if it's an unconfirmed email address
|
||||
|
||||
if (!$user) {
|
||||
// Warning: it may actually be legit to have multiple folks
|
||||
@ -314,7 +314,7 @@ class RecoverpasswordAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
# Try to get an unconfirmed email address if they used a user name
|
||||
// Try to get an unconfirmed email address if they used a user name
|
||||
|
||||
if (!$user->email && !$confirm_email) {
|
||||
$confirm_email = new Confirm_address();
|
||||
@ -332,7 +332,7 @@ class RecoverpasswordAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
# Success! We have a valid user and a confirmed or unconfirmed email address
|
||||
// Success! We have a valid user and a confirmed or unconfirmed email address
|
||||
|
||||
$confirm = new Confirm_address();
|
||||
$confirm->code = common_confirmation_code(128);
|
||||
@ -380,7 +380,7 @@ class RecoverpasswordAction extends Action
|
||||
|
||||
function resetPassword()
|
||||
{
|
||||
# CSRF protection
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
// TRANS: Form validation error message.
|
||||
@ -410,7 +410,7 @@ class RecoverpasswordAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
# OK, we're ready to go
|
||||
// OK, we're ready to go
|
||||
|
||||
$original = clone($user);
|
||||
|
||||
|
@ -531,7 +531,7 @@ class RegisterAction extends Action
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
// TRANS: Field label on account registration page.
|
||||
// TRANS: Button text to register a user on account registration page.
|
||||
$this->submit('submit', _m('BUTTON','Register'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
|
@ -73,12 +73,6 @@ class RepeatAction extends Action
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->user->id == $this->notice->profile_id) {
|
||||
// TRANS: Client error displayed when trying to repeat an own notice.
|
||||
$this->clientError(_('You cannot repeat your own notice.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$token = $this->trimmed('token-'.$id);
|
||||
|
||||
if (empty($token) || $token != common_session_token()) {
|
||||
@ -86,14 +80,6 @@ class RepeatAction extends Action
|
||||
return false;
|
||||
}
|
||||
|
||||
$profile = $this->user->getProfile();
|
||||
|
||||
if ($profile->hasRepeated($id)) {
|
||||
// TRANS: Client error displayed when trying to repeat an already repeated notice.
|
||||
$this->clientError(_('You already repeated that notice.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,6 @@ if (!defined('STATUSNET')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class SandboxAction extends ProfileFormAction
|
||||
{
|
||||
/**
|
||||
@ -50,7 +49,6 @@ class SandboxAction extends ProfileFormAction
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
if (!parent::prepare($args)) {
|
||||
@ -62,6 +60,7 @@ class SandboxAction extends ProfileFormAction
|
||||
assert(!empty($cur)); // checked by parent
|
||||
|
||||
if (!$cur->hasRight(Right::SANDBOXUSER)) {
|
||||
// TRANS: Client error displayed trying to sandbox users on a site where the feature is not enabled.
|
||||
$this->clientError(_('You cannot sandbox users on this site.'));
|
||||
return false;
|
||||
}
|
||||
@ -69,6 +68,7 @@ class SandboxAction extends ProfileFormAction
|
||||
assert(!empty($this->profile)); // checked by parent
|
||||
|
||||
if ($this->profile->isSandboxed()) {
|
||||
// TRANS: Client error displayed trying to sandbox an already sandboxed user.
|
||||
$this->clientError(_('User is already sandboxed.'));
|
||||
return false;
|
||||
}
|
||||
@ -81,7 +81,6 @@ class SandboxAction extends ProfileFormAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
$this->profile->sandbox();
|
||||
|
@ -40,7 +40,6 @@ if (!defined('STATUSNET')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class SessionsadminpanelAction extends AdminPanelAction
|
||||
{
|
||||
/**
|
||||
@ -48,10 +47,10 @@ class SessionsadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Sessions');
|
||||
// TRANS: Title for the sessions administration panel.
|
||||
return _m('TITLE','Sessions');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,9 +58,9 @@ class SessionsadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return string instructions
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
// TRANS: Instructions for the sessions administration panel.
|
||||
return _('Session settings for this StatusNet site');
|
||||
}
|
||||
|
||||
@ -70,7 +69,6 @@ class SessionsadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showForm()
|
||||
{
|
||||
$form = new SessionsAdminPanelForm($this);
|
||||
@ -83,7 +81,6 @@ class SessionsadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function saveSettings()
|
||||
{
|
||||
static $booleans = array('sessions' => array('handle', 'debug'));
|
||||
@ -123,6 +120,7 @@ class SessionsadminpanelAction extends AdminPanelAction
|
||||
}
|
||||
}
|
||||
|
||||
// @todo FIXME: Class documentation missing.
|
||||
class SessionsAdminPanelForm extends AdminForm
|
||||
{
|
||||
/**
|
||||
@ -130,7 +128,6 @@ class SessionsAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return int ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'sessionsadminpanel';
|
||||
@ -141,7 +138,6 @@ class SessionsAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return string class of the form
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_settings';
|
||||
@ -152,7 +148,6 @@ class SessionsAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('sessionsadminpanel');
|
||||
@ -163,24 +158,31 @@ class SessionsAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_user_sessions'));
|
||||
$this->out->element('legend', null, _('Sessions'));
|
||||
// TRANS: Fieldset legend on the sessions administration panel.
|
||||
$this->out->element('legend', null, _m('LEGEND','Sessions'));
|
||||
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
|
||||
$this->li();
|
||||
// TRANS: Checkbox title on the sessions administration panel.
|
||||
// TRANS: Indicates if StatusNet should handle session administration.
|
||||
$this->out->checkbox('handle', _('Handle sessions'),
|
||||
(bool) $this->value('handle', 'sessions'),
|
||||
_('Whether to handle sessions ourselves.'));
|
||||
// TRANS: Checkbox title on the sessions administration panel.
|
||||
// TRANS: Indicates if StatusNet should handle session administration.
|
||||
_('Handle sessions ourselves.'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
// TRANS: Checkbox label on the sessions administration panel.
|
||||
// TRANS: Indicates if StatusNet should write session debugging output.
|
||||
$this->out->checkbox('debug', _('Session debugging'),
|
||||
(bool) $this->value('debug', 'sessions'),
|
||||
_('Turn on debugging output for sessions.'));
|
||||
// TRANS: Checkbox title on the sessions administration panel.
|
||||
_('Enable debugging output for sessions.'));
|
||||
$this->unli();
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
@ -193,9 +195,14 @@ class SessionsAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Save'), 'submit', null, _('Save site settings'));
|
||||
$this->out->submit('submit',
|
||||
// TRANS: Submit button text on the sessions administration panel.
|
||||
_m('BUTTON','Save'),
|
||||
'submit',
|
||||
null,
|
||||
// TRANS: Title for submit button on the sessions administration panel.
|
||||
_('Save session settings'));
|
||||
}
|
||||
}
|
||||
|
@ -75,11 +75,13 @@ class ShowApplicationAction extends OwnerDesignAction
|
||||
$this->owner = User::staticGet($this->application->owner);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
// TRANS: Client error displayed trying to display an OAuth application while not logged in.
|
||||
$this->clientError(_('You must be logged in to view an application.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($this->application)) {
|
||||
// TRANS: Client error displayed trying to display a non-existing OAuth application.
|
||||
$this->clientError(_('No such application.'), 404);
|
||||
return false;
|
||||
}
|
||||
@ -87,6 +89,7 @@ class ShowApplicationAction extends OwnerDesignAction
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($cur->id != $this->owner->id) {
|
||||
// TRANS: Client error displayed trying to display an OAuth application for which the logged in user is not the owner.
|
||||
$this->clientError(_('You are not the owner of this application.'), 401);
|
||||
return false;
|
||||
}
|
||||
@ -148,6 +151,7 @@ class ShowApplicationAction extends OwnerDesignAction
|
||||
$consumer = $this->application->getConsumer();
|
||||
|
||||
$this->elementStart('div', 'entity_profile vcard');
|
||||
// TRANS: Header on the OAuth application page.
|
||||
$this->element('h2', null, _('Application profile'));
|
||||
if (!empty($this->application->icon)) {
|
||||
$this->element('img', array('src' => $this->application->icon,
|
||||
@ -176,7 +180,12 @@ class ShowApplicationAction extends OwnerDesignAction
|
||||
$userCnt = $appUsers->count();
|
||||
|
||||
$this->raw(sprintf(
|
||||
_('Created by %1$s - %2$s access by default - %3$d users'),
|
||||
// TRANS: Information output on an OAuth application page.
|
||||
// TRANS: %1$s is the application creator, %2$s is "read-only" or "read-write",
|
||||
// TRANS: %3$d is the number of users using the OAuth application.
|
||||
_m('Created by %1$s - %2$s access by default - %3$d user',
|
||||
'Created by %1$s - %2$s access by default - %3$d users',
|
||||
$userCnt),
|
||||
$profile->getBestName(),
|
||||
$defaultAccess,
|
||||
$userCnt
|
||||
@ -186,13 +195,15 @@ class ShowApplicationAction extends OwnerDesignAction
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('div', 'entity_actions');
|
||||
// TRANS: Header on the OAuth application page.
|
||||
$this->element('h2', null, _('Application actions'));
|
||||
$this->elementStart('ul');
|
||||
$this->elementStart('li', 'entity_edit');
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('editapplication',
|
||||
array('id' => $this->application->id))),
|
||||
'Edit');
|
||||
// TRANS: Link text to edit application on the OAuth application page.
|
||||
_m('EDITAPP','Edit'));
|
||||
$this->elementEnd('li');
|
||||
|
||||
$this->elementStart('li', 'entity_reset_keysecret');
|
||||
@ -209,6 +220,8 @@ class ShowApplicationAction extends OwnerDesignAction
|
||||
'id' => 'reset',
|
||||
'name' => 'reset',
|
||||
'class' => 'submit',
|
||||
// TRANS: Button text on the OAuth application page.
|
||||
// TRANS: Resets the OAuth consumer key and secret.
|
||||
'value' => _('Reset key & secret'),
|
||||
'onClick' => 'return confirmReset()'));
|
||||
$this->elementEnd('fieldset');
|
||||
@ -225,7 +238,8 @@ class ShowApplicationAction extends OwnerDesignAction
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->submit('delete', _('Delete'));
|
||||
// TRANS: Submit button text the OAuth application page to delete an application.
|
||||
$this->submit('delete', _m('BUTTON','Delete'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
$this->elementEnd('li');
|
||||
@ -234,6 +248,7 @@ class ShowApplicationAction extends OwnerDesignAction
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('div', 'entity_data');
|
||||
// TRANS: Header on the OAuth application page.
|
||||
$this->element('h2', null, _('Application info'));
|
||||
$this->element('div',
|
||||
'entity_consumer_key',
|
||||
@ -252,7 +267,8 @@ class ShowApplicationAction extends OwnerDesignAction
|
||||
$this->element('div', 'entity_authorize_url', common_local_url('ApiOauthAuthorize'));
|
||||
|
||||
$this->element('p', 'note',
|
||||
_('Note: We support HMAC-SHA1 signatures. We do not support the plaintext signature method.'));
|
||||
// TRANS: Note on the OAuth application page about signature support.
|
||||
_('Note: HMAC-SHA1 signatures are supported. The plaintext signature method is not supported.'));
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('p', array('id' => 'application_action'));
|
||||
@ -272,6 +288,7 @@ class ShowApplicationAction extends OwnerDesignAction
|
||||
{
|
||||
parent::showScripts();
|
||||
|
||||
// TRANS: Text in confirmation dialog to reset consumer key and secret for an OAuth application.
|
||||
$msg = _('Are you sure you want to reset your consumer key and secret?');
|
||||
|
||||
$js = 'function confirmReset() { ';
|
||||
|
@ -324,6 +324,8 @@ class ShowgroupAction extends GroupDesignAction
|
||||
$this->element('h2', null, _('Statistics'));
|
||||
|
||||
$this->elementStart('dl');
|
||||
|
||||
// TRANS: Label for group creation date.
|
||||
$this->element('dt', null, _m('LABEL','Created'));
|
||||
$this->element('dd', 'entity_created', date('j M Y',
|
||||
strtotime($this->group->created)));
|
||||
@ -363,6 +365,18 @@ class ShowgroupAction extends GroupDesignAction
|
||||
$this->raw(common_markup_to_html($m));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function noticeFormOptions()
|
||||
{
|
||||
$options = parent::noticeFormOptions();
|
||||
$cur = common_current_user();
|
||||
|
||||
if (!empty($cur) && $cur->isMember($this->group)) {
|
||||
$options['to_group'] = $this->group;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
|
||||
class GroupAdminSection extends ProfileSection
|
||||
@ -382,8 +396,8 @@ class GroupAdminSection extends ProfileSection
|
||||
|
||||
function title()
|
||||
{
|
||||
// TRANS: Header for list of group administrators on a group page (h2).
|
||||
return _('Admins');
|
||||
// TRANS: Title for list of group administrators on a group page.
|
||||
return _m('TITLE','Admins');
|
||||
}
|
||||
|
||||
function divId()
|
||||
|
@ -44,25 +44,21 @@ require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ShownoticeAction extends OwnerDesignAction
|
||||
{
|
||||
/**
|
||||
* Notice object to show
|
||||
*/
|
||||
|
||||
var $notice = null;
|
||||
|
||||
/**
|
||||
* Profile of the notice object
|
||||
*/
|
||||
|
||||
var $profile = null;
|
||||
|
||||
/**
|
||||
* Avatar of the profile of the notice object
|
||||
*/
|
||||
|
||||
var $avatar = null;
|
||||
|
||||
/**
|
||||
@ -74,7 +70,6 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
*
|
||||
* @return success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
@ -82,24 +77,25 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
StatusNet::setApi(true);
|
||||
}
|
||||
|
||||
$id = $this->arg('notice');
|
||||
$this->notice = $this->getNotice();
|
||||
|
||||
$this->notice = Notice::staticGet($id);
|
||||
$cur = common_current_user();
|
||||
|
||||
if (empty($this->notice)) {
|
||||
// Did we used to have it, and it got deleted?
|
||||
$deleted = Deleted_notice::staticGet($id);
|
||||
if (!empty($deleted)) {
|
||||
$this->clientError(_('Notice deleted.'), 410);
|
||||
if (!empty($cur)) {
|
||||
$curProfile = $cur->getProfile();
|
||||
} else {
|
||||
$this->clientError(_('No such notice.'), 404);
|
||||
$curProfile = null;
|
||||
}
|
||||
return false;
|
||||
|
||||
if (!$this->notice->inScope($curProfile)) {
|
||||
// TRANS: Client exception thrown when trying a view a notice the user has no access to.
|
||||
throw new ClientException(_('Not available.'), 403);
|
||||
}
|
||||
|
||||
$this->profile = $this->notice->getProfile();
|
||||
|
||||
if (empty($this->profile)) {
|
||||
// TRANS: Server error displayed trying to show a notice without a connected profile.
|
||||
$this->serverError(_('Notice has no profile.'), 500);
|
||||
return false;
|
||||
}
|
||||
@ -111,12 +107,38 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the notice to show. This may be overridden by child classes to
|
||||
* customize what we fetch without duplicating all of the prepare() method.
|
||||
*
|
||||
* @return Notice
|
||||
*/
|
||||
function getNotice()
|
||||
{
|
||||
$id = $this->arg('notice');
|
||||
|
||||
$notice = Notice::staticGet('id', $id);
|
||||
|
||||
if (empty($notice)) {
|
||||
// Did we used to have it, and it got deleted?
|
||||
$deleted = Deleted_notice::staticGet($id);
|
||||
if (!empty($deleted)) {
|
||||
// TRANS: Client error displayed trying to show a deleted notice.
|
||||
$this->clientError(_('Notice deleted.'), 410);
|
||||
} else {
|
||||
// TRANS: Client error displayed trying to show a non-existing notice.
|
||||
$this->clientError(_('No such notice.'), 404);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return $notice;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read-only?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
@ -130,7 +152,6 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
*
|
||||
* @return int last-modified date as unix timestamp
|
||||
*/
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
return max(strtotime($this->notice->modified),
|
||||
@ -147,7 +168,6 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
|
||||
function etag()
|
||||
{
|
||||
$avtime = ($this->avatar) ?
|
||||
@ -167,11 +187,12 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
*
|
||||
* @return string title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
$base = $this->profile->getFancyName();
|
||||
|
||||
// TRANS: Title of the page that shows a notice.
|
||||
// TRANS: %1$s is a user name, %2$s is the notice creation date/time.
|
||||
return sprintf(_('%1$s\'s status on %2$s'),
|
||||
$base,
|
||||
common_exact_date($this->notice->created));
|
||||
@ -186,7 +207,6 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
@ -218,7 +238,6 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showLocalNavBlock()
|
||||
{
|
||||
}
|
||||
@ -230,7 +249,6 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('ol', array('class' => 'notices xoxo'));
|
||||
@ -245,7 +263,8 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
$this->xw->startDocument('1.0', 'UTF-8');
|
||||
$this->elementStart('html');
|
||||
$this->elementStart('head');
|
||||
$this->element('title', null, _('Notice'));
|
||||
// TRANS: Title for page that shows a notice.
|
||||
$this->element('title', null, _m('TITLE','Notice'));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$nli = new NoticeListItem($this->notice, $this);
|
||||
@ -259,7 +278,6 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showPageNoticeBlock()
|
||||
{
|
||||
}
|
||||
@ -269,7 +287,6 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showAside() {
|
||||
}
|
||||
|
||||
@ -280,7 +297,6 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function extraHead()
|
||||
{
|
||||
$user = User::staticGet($this->profile->id);
|
||||
@ -323,16 +339,16 @@ class ShownoticeAction extends OwnerDesignAction
|
||||
}
|
||||
}
|
||||
|
||||
// @todo FIXME: Class documentation missing.
|
||||
class SingleNoticeItem extends DoFollowListItem
|
||||
{
|
||||
/**
|
||||
* recipe function for displaying a single notice.
|
||||
* Recipe function for displaying a single notice.
|
||||
*
|
||||
* We overload to show attachments.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function show()
|
||||
{
|
||||
$this->showStart();
|
||||
@ -363,7 +379,6 @@ class SingleNoticeItem extends DoFollowListItem
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showAvatar()
|
||||
{
|
||||
$avatar_size = AVATAR_PROFILE_SIZE;
|
||||
|
@ -65,7 +65,8 @@ class ShowstreamAction extends ProfileAction
|
||||
$base = $this->profile->getFancyName();
|
||||
if (!empty($this->tag)) {
|
||||
if ($this->page == 1) {
|
||||
// TRANS: Page title showing tagged notices in one user's stream. %1$s is the username, %2$s is the hash tag.
|
||||
// TRANS: Page title showing tagged notices in one user's stream.
|
||||
// TRANS: %1$s is the username, %2$s is the hash tag.
|
||||
return sprintf(_('%1$s tagged %2$s'), $base, $this->tag);
|
||||
} else {
|
||||
// TRANS: Page title showing tagged notices in one user's stream.
|
||||
@ -153,6 +154,8 @@ class ShowstreamAction extends ProfileAction
|
||||
array(
|
||||
'id' => $this->user->id,
|
||||
'format' => 'atom')),
|
||||
// TRANS: Title for link to notice feed.
|
||||
// TRANS: %s is a user nickname.
|
||||
sprintf(_('Notice feed for %s (Atom)'),
|
||||
$this->user->nickname)),
|
||||
new Feed(Feed::FOAF,
|
||||
@ -275,6 +278,18 @@ class ShowstreamAction extends ProfileAction
|
||||
$cloud = new PersonalTagCloudSection($this, $this->user);
|
||||
$cloud->show();
|
||||
}
|
||||
|
||||
function noticeFormOptions()
|
||||
{
|
||||
$options = parent::noticeFormOptions();
|
||||
$cur = common_current_user();
|
||||
|
||||
if (empty($cur) || $cur->id != $this->profile->id) {
|
||||
$options['to_profile'] = $this->profile;
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't show the author for a profile, since we already know who it is!
|
||||
|
@ -40,7 +40,6 @@ if (!defined('STATUSNET')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class SilenceAction extends ProfileFormAction
|
||||
{
|
||||
/**
|
||||
@ -50,7 +49,6 @@ class SilenceAction extends ProfileFormAction
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
if (!parent::prepare($args)) {
|
||||
@ -62,6 +60,7 @@ class SilenceAction extends ProfileFormAction
|
||||
assert(!empty($cur)); // checked by parent
|
||||
|
||||
if (!$cur->hasRight(Right::SILENCEUSER)) {
|
||||
// TRANS: Client error displayed trying to silence a user on a site where the feature is not enabled.
|
||||
$this->clientError(_('You cannot silence users on this site.'));
|
||||
return false;
|
||||
}
|
||||
@ -69,6 +68,7 @@ class SilenceAction extends ProfileFormAction
|
||||
assert(!empty($this->profile)); // checked by parent
|
||||
|
||||
if ($this->profile->isSilenced()) {
|
||||
// TRANS: Client error displayed trying to silence an already silenced user.
|
||||
$this->clientError(_('User is already silenced.'));
|
||||
return false;
|
||||
}
|
||||
@ -81,7 +81,6 @@ class SilenceAction extends ProfileFormAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
$this->profile->silence();
|
||||
|
@ -44,7 +44,6 @@ if (!defined('STATUSNET')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class SiteadminpanelAction extends AdminPanelAction
|
||||
{
|
||||
/**
|
||||
@ -52,10 +51,10 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Site');
|
||||
// TRANS: Title for site administration panel.
|
||||
return _m('TITLE','Site');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,9 +62,9 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return string instructions
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
// TRANS: Instructions for site administration panel.
|
||||
return _('Basic settings for this StatusNet site');
|
||||
}
|
||||
|
||||
@ -74,7 +73,6 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showForm()
|
||||
{
|
||||
$form = new SiteAdminPanelForm($this);
|
||||
@ -87,7 +85,6 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function saveSettings()
|
||||
{
|
||||
static $settings = array(
|
||||
@ -130,6 +127,7 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
// Validate site name
|
||||
|
||||
if (empty($values['site']['name'])) {
|
||||
// TRANS: Client error displayed trying to save an empty site name.
|
||||
$this->clientError(_('Site name must have non-zero length.'));
|
||||
}
|
||||
|
||||
@ -138,9 +136,11 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
$values['site']['email'] = common_canonical_email($values['site']['email']);
|
||||
|
||||
if (empty($values['site']['email'])) {
|
||||
// TRANS: Client error displayed trying to save site settings without a contact address.
|
||||
$this->clientError(_('You must have a valid contact email address.'));
|
||||
}
|
||||
if (!Validate::email($values['site']['email'], common_config('email', 'check_domain'))) {
|
||||
// TRANS: Client error displayed trying to save site settings without a valid contact address.
|
||||
$this->clientError(_('Not a valid email address.'));
|
||||
}
|
||||
|
||||
@ -148,6 +148,7 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
|
||||
if (is_null($values['site']['timezone']) ||
|
||||
!in_array($values['site']['timezone'], DateTimeZone::listIdentifiers())) {
|
||||
// TRANS: Client error displayed trying to save site settings without a timezone.
|
||||
$this->clientError(_('Timezone not selected.'));
|
||||
return;
|
||||
}
|
||||
@ -156,24 +157,28 @@ class SiteadminpanelAction extends AdminPanelAction
|
||||
|
||||
if (!is_null($values['site']['language']) &&
|
||||
!in_array($values['site']['language'], array_keys(get_nice_language_list()))) {
|
||||
// TRANS: Client error displayed trying to save site settings with an invalid language code.
|
||||
// TRANS: %s is the invalid language code.
|
||||
$this->clientError(sprintf(_('Unknown language "%s".'), $values['site']['language']));
|
||||
}
|
||||
|
||||
// Validate text limit
|
||||
|
||||
if (!Validate::number($values['site']['textlimit'], array('min' => 0))) {
|
||||
$this->clientError(_("Minimum text limit is 0 (unlimited)."));
|
||||
// TRANS: Client error displayed trying to save site settings with a text limit below 0.
|
||||
$this->clientError(_('Minimum text limit is 0 (unlimited).'));
|
||||
}
|
||||
|
||||
// Validate dupe limit
|
||||
|
||||
if (!Validate::number($values['site']['dupelimit'], array('min' => 1))) {
|
||||
// TRANS: Client error displayed trying to save site settings with a text limit below 1.
|
||||
$this->clientError(_("Dupe limit must be one or more seconds."));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// @todo FIXME: Class documentation missing.
|
||||
class SiteAdminPanelForm extends AdminForm
|
||||
{
|
||||
/**
|
||||
@ -181,7 +186,6 @@ class SiteAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return int ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'form_site_admin_panel';
|
||||
@ -192,7 +196,6 @@ class SiteAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return string class of the form
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_settings';
|
||||
@ -203,7 +206,6 @@ class SiteAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('siteadminpanel');
|
||||
@ -214,35 +216,44 @@ class SiteAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_general'));
|
||||
$this->out->element('legend', null, _('General'));
|
||||
// TRANS: Fieldset legend on site settings panel.
|
||||
$this->out->element('legend', null, _m('LEGEND','General'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$this->li();
|
||||
$this->input('name', _('Site name'),
|
||||
_('The name of your site, like "Yourcompany Microblog"'));
|
||||
// TRANS: Field label on site settings panel.
|
||||
$this->input('name', _m('LABEL','Site name'),
|
||||
// TRANS: Field title on site settings panel.
|
||||
_('The name of your site, like "Yourcompany Microblog".'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
// TRANS: Field label on site settings panel.
|
||||
$this->input('broughtby', _('Brought by'),
|
||||
_('Text used for credits link in footer of each page'));
|
||||
// TRANS: Field title on site settings panel.
|
||||
_('Text used for credits link in footer of each page.'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
// TRANS: Field label on site settings panel.
|
||||
$this->input('broughtbyurl', _('Brought by URL'),
|
||||
_('URL used for credits link in footer of each page'));
|
||||
// TRANS: Field title on site settings panel.
|
||||
_('URL used for credits link in footer of each page.'));
|
||||
$this->unli();
|
||||
$this->li();
|
||||
// TRANS: Field label on site settings panel.
|
||||
$this->input('email', _('Email'),
|
||||
_('Contact email address for your site'));
|
||||
// TRANS: Field title on site settings panel.
|
||||
_('Contact email address for your site.'));
|
||||
$this->unli();
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_local'));
|
||||
$this->out->element('legend', null, _('Local'));
|
||||
// TRANS: Fieldset legend on site settings panel.
|
||||
$this->out->element('legend', null, _m('LEGEND','Local'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$timezones = array();
|
||||
|
||||
@ -253,14 +264,20 @@ class SiteAdminPanelForm extends AdminForm
|
||||
asort($timezones);
|
||||
|
||||
$this->li();
|
||||
// TRANS: Dropdown label on site settings panel.
|
||||
$this->out->dropdown('timezone', _('Default timezone'),
|
||||
// TRANS: Dropdown title on site settings panel.
|
||||
$timezones, _('Default timezone for the site; usually UTC.'),
|
||||
true, $this->value('timezone'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->out->dropdown('language', _('Default language'),
|
||||
get_nice_language_list(), _('Site language when autodetection from browser settings is not available'),
|
||||
$this->out->dropdown('language',
|
||||
// TRANS: Dropdown label on site settings panel.
|
||||
_('Default language'),
|
||||
get_nice_language_list(),
|
||||
// TRANS: Dropdown title on site settings panel.
|
||||
_('Site language when autodetection from browser settings is not available'),
|
||||
false, $this->value('language'));
|
||||
$this->unli();
|
||||
|
||||
@ -268,14 +285,23 @@ class SiteAdminPanelForm extends AdminForm
|
||||
$this->out->elementEnd('fieldset');
|
||||
|
||||
$this->out->elementStart('fieldset', array('id' => 'settings_admin_limits'));
|
||||
$this->out->element('legend', null, _('Limits'));
|
||||
// TRANS: Fieldset legend on site settings panel.
|
||||
$this->out->element('legend', null, _m('LEGEND','Limits'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$this->li();
|
||||
$this->input('textlimit', _('Text limit'), _('Maximum number of characters for notices.'));
|
||||
$this->input('textlimit',
|
||||
// TRANS: Field label on site settings panel.
|
||||
_('Text limit'),
|
||||
// TRANS: Field title on site settings panel.
|
||||
_('Maximum number of characters for notices.'));
|
||||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->input('dupelimit', _('Dupe limit'), _('How long users must wait (in seconds) to post the same thing again.'));
|
||||
$this->input('dupelimit',
|
||||
// TRANS: Field label on site settings panel.
|
||||
_('Dupe limit'),
|
||||
// TRANS: Field title on site settings panel.
|
||||
_('How long users must wait (in seconds) to post the same thing again.'));
|
||||
$this->unli();
|
||||
$this->out->elementEnd('ul');
|
||||
$this->out->elementEnd('fieldset');
|
||||
@ -286,9 +312,14 @@ class SiteAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Save'), 'submit', null, _('Save site settings'));
|
||||
$this->out->submit('submit',
|
||||
// TRANS: Button text for saving site settings.
|
||||
_m('BUTTON','Save'),
|
||||
'submit',
|
||||
null,
|
||||
// TRANS: Button title for saving site settings.
|
||||
_('Save site settings'));
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ if (!defined('STATUSNET')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class SnapshotadminpanelAction extends AdminPanelAction
|
||||
{
|
||||
/**
|
||||
@ -48,10 +47,10 @@ class SnapshotadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return string page title
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Snapshots');
|
||||
// TRANS: Title for admin panel to configure snapshots.
|
||||
return _m('TITLE','Snapshots');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,9 +58,9 @@ class SnapshotadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return string instructions
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
// TRANS: Instructions for admin panel to configure snapshots.
|
||||
return _('Manage snapshot configuration');
|
||||
}
|
||||
|
||||
@ -70,7 +69,6 @@ class SnapshotadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showForm()
|
||||
{
|
||||
$form = new SnapshotAdminPanelForm($this);
|
||||
@ -83,7 +81,6 @@ class SnapshotadminpanelAction extends AdminPanelAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function saveSettings()
|
||||
{
|
||||
static $settings = array(
|
||||
@ -124,12 +121,14 @@ class SnapshotadminpanelAction extends AdminPanelAction
|
||||
// Validate snapshot run value
|
||||
|
||||
if (!in_array($values['snapshot']['run'], array('web', 'cron', 'never'))) {
|
||||
// TRANS: Client error displayed on admin panel for snapshots when providing an invalid run value.
|
||||
$this->clientError(_('Invalid snapshot run value.'));
|
||||
}
|
||||
|
||||
// Validate snapshot frequency value
|
||||
|
||||
if (!Validate::number($values['snapshot']['frequency'])) {
|
||||
// TRANS: Client error displayed on admin panel for snapshots when providing an invalid value for frequency.
|
||||
$this->clientError(_('Snapshot frequency must be a number.'));
|
||||
}
|
||||
|
||||
@ -141,11 +140,13 @@ class SnapshotadminpanelAction extends AdminPanelAction
|
||||
array('allowed_schemes' => array('http', 'https')
|
||||
)
|
||||
)) {
|
||||
// TRANS: Client error displayed on admin panel for snapshots when providing an invalid report URL.
|
||||
$this->clientError(_('Invalid snapshot report URL.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @todo FIXME: add documentation
|
||||
class SnapshotAdminPanelForm extends AdminForm
|
||||
{
|
||||
/**
|
||||
@ -153,7 +154,6 @@ class SnapshotAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return int ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'form_snapshot_admin_panel';
|
||||
@ -164,7 +164,6 @@ class SnapshotAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return string class of the form
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_settings';
|
||||
@ -175,7 +174,6 @@ class SnapshotAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
return common_local_url('snapshotadminpanel');
|
||||
@ -186,26 +184,31 @@ class SnapshotAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
$this->out->elementStart(
|
||||
'fieldset',
|
||||
array('id' => 'settings_admin_snapshots')
|
||||
);
|
||||
$this->out->element('legend', null, _('Snapshots'));
|
||||
// TRANS: Fieldset legend on admin panel for snapshots.
|
||||
$this->out->element('legend', null, _m('LEGEND','Snapshots'));
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$this->li();
|
||||
$snapshot = array(
|
||||
// TRANS: Option in dropdown for snapshot method in admin panel for snapshots.
|
||||
'web' => _('Randomly during web hit'),
|
||||
// TRANS: Option in dropdown for snapshot method in admin panel for snapshots.
|
||||
'cron' => _('In a scheduled job'),
|
||||
// TRANS: Option in dropdown for snapshot method in admin panel for snapshots.
|
||||
'never' => _('Never')
|
||||
);
|
||||
$this->out->dropdown(
|
||||
'run',
|
||||
// TRANS: Dropdown label for snapshot method in admin panel for snapshots.
|
||||
_('Data snapshots'),
|
||||
$snapshot,
|
||||
_('When to send statistical data to status.net servers'),
|
||||
// TRANS: Dropdown title for snapshot method in admin panel for snapshots.
|
||||
_('When to send statistical data to status.net servers.'),
|
||||
false,
|
||||
$this->value('run', 'snapshot')
|
||||
);
|
||||
@ -214,8 +217,10 @@ class SnapshotAdminPanelForm extends AdminForm
|
||||
$this->li();
|
||||
$this->input(
|
||||
'frequency',
|
||||
// TRANS: Input field label for snapshot frequency in admin panel for snapshots.
|
||||
_('Frequency'),
|
||||
_('Snapshots will be sent once every N web hits'),
|
||||
// TRANS: Input field title for snapshot frequency in admin panel for snapshots.
|
||||
_('Snapshots will be sent once every N web hits.'),
|
||||
'snapshot'
|
||||
);
|
||||
$this->unli();
|
||||
@ -223,8 +228,10 @@ class SnapshotAdminPanelForm extends AdminForm
|
||||
$this->li();
|
||||
$this->input(
|
||||
'reporturl',
|
||||
// TRANS: Input field label for snapshot report URL in admin panel for snapshots.
|
||||
_('Report URL'),
|
||||
_('Snapshots will be sent to this URL'),
|
||||
// TRANS: Input field title for snapshot report URL in admin panel for snapshots.
|
||||
_('Snapshots will be sent to this URL.'),
|
||||
'snapshot'
|
||||
);
|
||||
$this->unli();
|
||||
@ -237,15 +244,16 @@ class SnapshotAdminPanelForm extends AdminForm
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit(
|
||||
'submit',
|
||||
_('Save'),
|
||||
// TRANS: Button text to save snapshot settings.
|
||||
_m('BUTTON','Save'),
|
||||
'submit',
|
||||
null,
|
||||
_('Save snapshot settings')
|
||||
// TRANS: Title for button to save snapshot settings.
|
||||
_('Save snapshot settings.')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
142
actions/subqueue.php
Normal file
142
actions/subqueue.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, 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 StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @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');
|
||||
|
||||
/**
|
||||
* List of group members
|
||||
*
|
||||
* @category Group
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class SubqueueAction extends GalleryAction
|
||||
{
|
||||
var $page = null;
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// @todo FIXME: most of this belongs in a base class, sounds common to most group actions?
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$cur = common_current_user();
|
||||
if (!$cur || $cur->id != $this->profile->id) {
|
||||
// TRANS: Client error displayed when trying to approve group applicants without being a group administrator.
|
||||
$this->clientError(_('You may only approve your own pending subscriptions.'));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
if ($this->page == 1) {
|
||||
// TRANS: Title of the first page showing pending subscribers still awaiting approval.
|
||||
// TRANS: %s is the name of the user.
|
||||
return sprintf(_('%s subscribers awaiting approval'),
|
||||
$this->profile->nickname);
|
||||
} else {
|
||||
// TRANS: Title of all but the first page showing pending subscribersmembers still awaiting approval.
|
||||
// TRANS: %1$s is the name of the user, %2$d is the page number of the members list.
|
||||
return sprintf(_('%1$s subscribers awaiting approval, page %2$d'),
|
||||
$this->profile->nickname,
|
||||
$this->page);
|
||||
}
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
$this->element('p', 'instructions',
|
||||
// TRANS: Page notice for group members page.
|
||||
_('A list of users awaiting approval to subscribe to you.'));
|
||||
}
|
||||
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$offset = ($this->page-1) * PROFILES_PER_PAGE;
|
||||
$limit = PROFILES_PER_PAGE + 1;
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
$members = $this->profile->getRequests($offset, $limit);
|
||||
|
||||
if ($members) {
|
||||
// @fixme change!
|
||||
$member_list = new SubQueueList($members, $this);
|
||||
$cnt = $member_list->show();
|
||||
}
|
||||
|
||||
$members->free();
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > PROFILES_PER_PAGE,
|
||||
$this->page, 'subqueue',
|
||||
array('nickname' => $this->profile->nickname)); // urgh
|
||||
}
|
||||
}
|
||||
|
||||
class SubQueueList extends ProfileList
|
||||
{
|
||||
function newListItem($profile)
|
||||
{
|
||||
return new SubQueueListItem($profile, $this->action);
|
||||
}
|
||||
}
|
||||
|
||||
class SubQueueListItem extends ProfileListItem
|
||||
{
|
||||
function showActions()
|
||||
{
|
||||
$this->startActions();
|
||||
if (Event::handle('StartProfileListItemActionElements', array($this))) {
|
||||
$this->showApproveButtons();
|
||||
Event::handle('EndProfileListItemActionElements', array($this));
|
||||
}
|
||||
$this->endActions();
|
||||
}
|
||||
|
||||
function showApproveButtons()
|
||||
{
|
||||
$this->out->elementStart('li', 'entity_approval');
|
||||
$form = new ApproveSubForm($this->out, $this->profile);
|
||||
$form->show();
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
}
|
@ -139,7 +139,7 @@ class SubscribeAction extends Action
|
||||
{
|
||||
// Throws exception on error
|
||||
|
||||
Subscription::start($this->user->getProfile(),
|
||||
$sub = Subscription::start($this->user->getProfile(),
|
||||
$this->other);
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
@ -149,8 +149,12 @@ class SubscribeAction extends Action
|
||||
$this->element('title', null, _('Subscribed'));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$unsubscribe = new UnsubscribeForm($this, $this->other);
|
||||
$unsubscribe->show();
|
||||
if ($sub instanceof Subscription) {
|
||||
$form = new UnsubscribeForm($this, $this->other);
|
||||
} else {
|
||||
$form = new CancelSubscriptionForm($this, $this->other);
|
||||
}
|
||||
$form->show();
|
||||
$this->elementEnd('body');
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
|
@ -61,8 +61,8 @@ class SupAction extends Action
|
||||
{
|
||||
$notice = new Notice();
|
||||
|
||||
# XXX: cache this. Depends on how big this protocol becomes;
|
||||
# Re-doing this query every 15 seconds isn't the end of the world.
|
||||
// XXX: cache this. Depends on how big this protocol becomes;
|
||||
// Re-doing this query every 15 seconds isn't the end of the world.
|
||||
|
||||
$divider = common_sql_date(time() - $seconds);
|
||||
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
// @todo FIXME: documentation missing.
|
||||
class TagAction extends Action
|
||||
{
|
||||
|
||||
var $notice;
|
||||
|
||||
function prepare($args)
|
||||
@ -48,7 +48,7 @@ class TagAction extends Action
|
||||
$this->notice = Notice_tag::getStream($this->tag, (($this->page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
|
||||
|
||||
if($this->page > 1 && $this->notice->N == 0){
|
||||
// TRANS: Server error when page not found (404)
|
||||
// TRANS: Server error when page not found (404).
|
||||
$this->serverError(_('No such page.'),$code=404);
|
||||
}
|
||||
|
||||
@ -88,18 +88,24 @@ class TagAction extends Action
|
||||
return array(new Feed(Feed::RSS1,
|
||||
common_local_url('tagrss',
|
||||
array('tag' => $this->tag)),
|
||||
// TRANS: Link label for feed on "notices with tag" page.
|
||||
// TRANS: %s is the tag the feed is for.
|
||||
sprintf(_('Notice feed for tag %s (RSS 1.0)'),
|
||||
$this->tag)),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('ApiTimelineTag',
|
||||
array('format' => 'rss',
|
||||
'tag' => $this->tag)),
|
||||
// TRANS: Link label for feed on "notices with tag" page.
|
||||
// TRANS: %s is the tag the feed is for.
|
||||
sprintf(_('Notice feed for tag %s (RSS 2.0)'),
|
||||
$this->tag)),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('ApiTimelineTag',
|
||||
array('format' => 'atom',
|
||||
'tag' => $this->tag)),
|
||||
// TRANS: Link label for feed on "notices with tag" page.
|
||||
// TRANS: %s is the tag the feed is for.
|
||||
sprintf(_('Notice feed for tag %s (Atom)'),
|
||||
$this->tag)));
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
require_once(INSTALLDIR.'/lib/rssaction.php');
|
||||
|
||||
// Formatting of RSS handled by Rss10Action
|
||||
|
||||
class TagrssAction extends Rss10Action
|
||||
{
|
||||
var $tag;
|
||||
@ -32,6 +31,7 @@ class TagrssAction extends Rss10Action
|
||||
$tag = common_canonical_tag($this->trimmed('tag'));
|
||||
$this->tag = Notice_tag::staticGet('tag', $tag);
|
||||
if (!$this->tag) {
|
||||
// TRANS: Client error when requesting a tag feed for a non-existing tag.
|
||||
$this->clientError(_('No such tag.'));
|
||||
return false;
|
||||
} else {
|
||||
@ -62,6 +62,8 @@ class TagrssAction extends Rss10Action
|
||||
$c = array('url' => common_local_url('tagrss', array('tag' => $tagname)),
|
||||
'title' => $tagname,
|
||||
'link' => common_local_url('tagrss', array('tag' => $tagname)),
|
||||
// TRANS: Tag feed description.
|
||||
// TRANS: %1$s is the tag name, %2$s is the StatusNet sitename.
|
||||
'description' => sprintf(_('Updates tagged with %1$s on %2$s!'),
|
||||
$tagname, common_config('site', 'name')));
|
||||
return $c;
|
||||
|
@ -40,7 +40,6 @@ if (!defined('STATUSNET')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class UnsandboxAction extends ProfileFormAction
|
||||
{
|
||||
/**
|
||||
@ -50,7 +49,6 @@ class UnsandboxAction extends ProfileFormAction
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
if (!parent::prepare($args)) {
|
||||
@ -62,6 +60,7 @@ class UnsandboxAction extends ProfileFormAction
|
||||
assert(!empty($cur)); // checked by parent
|
||||
|
||||
if (!$cur->hasRight(Right::SANDBOXUSER)) {
|
||||
// TRANS: Client error on page to unsandbox a user when the feature is not enabled.
|
||||
$this->clientError(_('You cannot sandbox users on this site.'));
|
||||
return false;
|
||||
}
|
||||
@ -69,6 +68,7 @@ class UnsandboxAction extends ProfileFormAction
|
||||
assert(!empty($this->profile)); // checked by parent
|
||||
|
||||
if (!$this->profile->isSandboxed()) {
|
||||
// TRANS: Client error on page to unsilence a user when the to be unsandboxed user has not been sandboxed.
|
||||
$this->clientError(_('User is not sandboxed.'));
|
||||
return false;
|
||||
}
|
||||
@ -81,7 +81,6 @@ class UnsandboxAction extends ProfileFormAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
$this->profile->unsandbox();
|
||||
|
@ -40,7 +40,6 @@ if (!defined('STATUSNET')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class UnsilenceAction extends ProfileFormAction
|
||||
{
|
||||
/**
|
||||
@ -50,7 +49,6 @@ class UnsilenceAction extends ProfileFormAction
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
if (!parent::prepare($args)) {
|
||||
@ -62,6 +60,7 @@ class UnsilenceAction extends ProfileFormAction
|
||||
assert(!empty($cur)); // checked by parent
|
||||
|
||||
if (!$cur->hasRight(Right::SILENCEUSER)) {
|
||||
// TRANS: Client error on page to unsilence a user when the feature is not enabled.
|
||||
$this->clientError(_('You cannot silence users on this site.'));
|
||||
return false;
|
||||
}
|
||||
@ -69,6 +68,7 @@ class UnsilenceAction extends ProfileFormAction
|
||||
assert(!empty($this->profile)); // checked by parent
|
||||
|
||||
if (!$this->profile->isSilenced()) {
|
||||
// TRANS: Client error on page to unsilence a user when the to be unsilenced user has not been silenced.
|
||||
$this->clientError(_('User is not silenced.'));
|
||||
return false;
|
||||
}
|
||||
@ -81,7 +81,6 @@ class UnsilenceAction extends ProfileFormAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
$this->profile->unsilence();
|
||||
|
@ -44,11 +44,11 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
*/
|
||||
class UnsubscribeAction extends Action
|
||||
{
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
if (!common_logged_in()) {
|
||||
// TRANS: Client error displayed when trying to unsubscribe while not logged in.
|
||||
$this->clientError(_('Not logged in.'));
|
||||
return;
|
||||
}
|
||||
@ -74,6 +74,7 @@ class UnsubscribeAction extends Action
|
||||
$other_id = $this->arg('unsubscribeto');
|
||||
|
||||
if (!$other_id) {
|
||||
// TRANS: Client error displayed when trying to unsubscribe without providing a profile ID.
|
||||
$this->clientError(_('No profile ID in request.'));
|
||||
return;
|
||||
}
|
||||
@ -81,6 +82,7 @@ class UnsubscribeAction extends Action
|
||||
$other = Profile::staticGet('id', $other_id);
|
||||
|
||||
if (!$other) {
|
||||
// TRANS: Client error displayed when trying to unsubscribe while providing a non-existing profile ID.
|
||||
$this->clientError(_('No profile with that ID.'));
|
||||
return;
|
||||
}
|
||||
@ -95,6 +97,7 @@ class UnsubscribeAction extends Action
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
// TRANS: Page title for page to unsubscribe.
|
||||
$this->element('title', null, _('Unsubscribed'));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
|
@ -45,7 +45,6 @@ require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
|
||||
*/
|
||||
class UpdateprofileAction extends Action
|
||||
{
|
||||
|
||||
/**
|
||||
* For initializing members of the class.
|
||||
*
|
||||
@ -61,8 +60,10 @@ class UpdateprofileAction extends Action
|
||||
$license = $_POST['omb_listenee_license'];
|
||||
$site_license = common_config('license', 'url');
|
||||
if (!common_compatible_license($license, $site_license)) {
|
||||
$this->clientError(sprintf(_('Listenee stream license ‘%1$s’ is not '.
|
||||
'compatible with site license ‘%2$s’.'),
|
||||
// TRANS: Client error displayed when trying to update profile with an incompatible license.
|
||||
// TRANS: %1$s is the license incompatible with site license %2$s.
|
||||
$this->clientError(sprintf(_('Listenee stream license "%1$s" is not '.
|
||||
'compatible with site license "%2$s".'),
|
||||
$license, $site_license));
|
||||
return false;
|
||||
}
|
||||
|
@ -32,8 +32,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Miscellaneous settings actions
|
||||
*
|
||||
@ -46,7 +44,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class UrlsettingsAction extends SettingsAction
|
||||
{
|
||||
/**
|
||||
@ -54,9 +51,9 @@ class UrlsettingsAction extends SettingsAction
|
||||
*
|
||||
* @return string Title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
// TRANS: Title of URL settings tab in profile settings.
|
||||
return _('URL settings');
|
||||
}
|
||||
|
||||
@ -65,7 +62,6 @@ class UrlsettingsAction extends SettingsAction
|
||||
*
|
||||
* @return instructions for use
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
// TRANS: Instructions for tab "Other" in user profile settings.
|
||||
@ -85,7 +81,6 @@ class UrlsettingsAction extends SettingsAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
@ -118,11 +113,12 @@ class UrlsettingsAction extends SettingsAction
|
||||
|
||||
// Include default values
|
||||
|
||||
// TRANS: Default value for URL shortening settings.
|
||||
$services['none'] = _('[none]');
|
||||
// TRANS: Default value for URL shortening settings.
|
||||
$services['internal'] = _('[internal]');
|
||||
|
||||
if ($services) {
|
||||
|
||||
asort($services);
|
||||
|
||||
$this->elementStart('li');
|
||||
@ -135,16 +131,20 @@ class UrlsettingsAction extends SettingsAction
|
||||
}
|
||||
$this->elementStart('li');
|
||||
$this->input('maxurllength',
|
||||
// TRANS: Field label in URL settings in profile.
|
||||
_('URL longer than'),
|
||||
(!is_null($this->arg('maxurllength'))) ?
|
||||
$this->arg('maxurllength') : User_urlshortener_prefs::maxUrlLength($user),
|
||||
// TRANS: Field title in URL settings in profile.
|
||||
_('URLs longer than this will be shortened, 0 means always shorten.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->input('maxnoticelength',
|
||||
// TRANS: Field label in URL settings in profile.
|
||||
_('Text longer than'),
|
||||
(!is_null($this->arg('maxnoticelength'))) ?
|
||||
$this->arg('maxnoticelength') : User_urlshortener_prefs::maxNoticeLength($user),
|
||||
// TRANS: Field title in URL settings in profile.
|
||||
_('URLs in notices longer than this will be shortened, 0 means always shorten.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
@ -162,7 +162,6 @@ class UrlsettingsAction extends SettingsAction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
// CSRF protection
|
||||
@ -184,13 +183,15 @@ class UrlsettingsAction extends SettingsAction
|
||||
$maxurllength = $this->trimmed('maxurllength');
|
||||
|
||||
if (!Validate::number($maxurllength, array('min' => 0))) {
|
||||
throw new ClientException(_('Invalid number for max url length.'));
|
||||
// TRANS: Client exception thrown when the maximum URL settings value is invalid in profile URL settings.
|
||||
throw new ClientException(_('Invalid number for maximum URL length.'));
|
||||
}
|
||||
|
||||
$maxnoticelength = $this->trimmed('maxnoticelength');
|
||||
|
||||
if (!Validate::number($maxnoticelength, array('min' => 0))) {
|
||||
throw new ClientException(_('Invalid number for max notice length.'));
|
||||
// TRANS: Client exception thrown when the maximum notice length settings value is invalid in profile URL settings.
|
||||
throw new ClientException(_('Invalid number for maximum notice length.'));
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
@ -235,6 +236,7 @@ class UrlsettingsAction extends SettingsAction
|
||||
}
|
||||
|
||||
if (!$result) {
|
||||
// TRANS: Server exception thrown in profile URL settings when preferences could not be saved.
|
||||
throw new ServerException(_('Error saving user URL shortening preferences.'));
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ class UserauthorizationAction extends Action
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
// TRANS: Page notice on "Auhtorize subscription" page.
|
||||
// TRANS: Page notice on "Authorize subscription" page.
|
||||
$this->element('p', null, _('Please check these details to make sure '.
|
||||
'that you want to subscribe to this ' .
|
||||
'user’s notices. If you didn’t just ask ' .
|
||||
@ -243,10 +243,10 @@ class UserauthorizationAction extends Action
|
||||
{
|
||||
// TRANS: Accept message header from Authorise subscription page.
|
||||
common_show_header(_('Subscription authorized'));
|
||||
// TRANS: Accept message text from Authorise subscription page.
|
||||
$this->element('p', null,
|
||||
// TRANS: Accept message text from Authorise subscription page.
|
||||
_('The subscription has been authorized, but no '.
|
||||
'callback URL was passed. Check with the site’s ' .
|
||||
'callback URL was passed. Check with the site\'s ' .
|
||||
'instructions for details on how to authorize the ' .
|
||||
'subscription. Your subscription token is:'));
|
||||
$this->element('blockquote', 'token', $tok);
|
||||
@ -257,10 +257,10 @@ class UserauthorizationAction extends Action
|
||||
{
|
||||
// TRANS: Reject message header from Authorise subscription page.
|
||||
common_show_header(_('Subscription rejected'));
|
||||
// TRANS: Reject message from Authorise subscription page.
|
||||
$this->element('p', null,
|
||||
// TRANS: Reject message from Authorise subscription page.
|
||||
_('The subscription has been rejected, but no '.
|
||||
'callback URL was passed. Check with the site’s ' .
|
||||
'callback URL was passed. Check with the site\'s ' .
|
||||
'instructions for details on how to fully reject ' .
|
||||
'the subscription.'));
|
||||
common_show_footer();
|
||||
|
@ -112,7 +112,7 @@ class UserrssAction extends Rss10Action
|
||||
return ($avatar) ? $avatar->url : null;
|
||||
}
|
||||
|
||||
# override parent to add X-SUP-ID URL
|
||||
// override parent to add X-SUP-ID URL
|
||||
|
||||
function initRss($limit=0)
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ class Avatar extends Memcached_DataObject
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
# We clean up the file, too
|
||||
// We clean up the file, too
|
||||
|
||||
function delete()
|
||||
{
|
||||
|
@ -79,70 +79,16 @@ class Fave extends Memcached_DataObject
|
||||
|
||||
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $own=false, $since_id=0, $max_id=0)
|
||||
{
|
||||
$ids = Notice::stream(array('Fave', '_streamDirect'),
|
||||
array($user_id, $own),
|
||||
($own) ? 'fave:ids_by_user_own:'.$user_id :
|
||||
'fave:ids_by_user:'.$user_id,
|
||||
$offset, $limit, $since_id, $max_id);
|
||||
return $ids;
|
||||
$stream = new FaveNoticeStream($user_id, $own);
|
||||
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that the sorting for this is by order of *fave* not order of *notice*.
|
||||
*
|
||||
* @fixme add since_id, max_id support?
|
||||
*
|
||||
* @param <type> $user_id
|
||||
* @param <type> $own
|
||||
* @param <type> $offset
|
||||
* @param <type> $limit
|
||||
* @param <type> $since_id
|
||||
* @param <type> $max_id
|
||||
* @return <type>
|
||||
*/
|
||||
function _streamDirect($user_id, $own, $offset, $limit, $since_id, $max_id)
|
||||
function idStream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $own=false, $since_id=0, $max_id=0)
|
||||
{
|
||||
$fav = new Fave();
|
||||
$qry = null;
|
||||
$stream = new FaveNoticeStream($user_id, $own);
|
||||
|
||||
if ($own) {
|
||||
$qry = 'SELECT fave.* FROM fave ';
|
||||
$qry .= 'WHERE fave.user_id = ' . $user_id . ' ';
|
||||
} else {
|
||||
$qry = 'SELECT fave.* FROM fave ';
|
||||
$qry .= 'INNER JOIN notice ON fave.notice_id = notice.id ';
|
||||
$qry .= 'WHERE fave.user_id = ' . $user_id . ' ';
|
||||
$qry .= 'AND notice.is_local != ' . Notice::GATEWAY . ' ';
|
||||
}
|
||||
|
||||
if ($since_id != 0) {
|
||||
$qry .= 'AND notice_id > ' . $since_id . ' ';
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$qry .= 'AND notice_id <= ' . $max_id . ' ';
|
||||
}
|
||||
|
||||
// NOTE: we sort by fave time, not by notice time!
|
||||
|
||||
$qry .= 'ORDER BY modified DESC ';
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$qry .= "LIMIT $limit OFFSET $offset";
|
||||
}
|
||||
|
||||
$fav->query($qry);
|
||||
|
||||
$ids = array();
|
||||
|
||||
while ($fav->fetch()) {
|
||||
$ids[] = $fav->notice_id;
|
||||
}
|
||||
|
||||
$fav->free();
|
||||
unset($fav);
|
||||
|
||||
return $ids;
|
||||
return $stream->getNoticeIds($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
function asActivity()
|
||||
|
@ -449,52 +449,8 @@ class File extends Memcached_DataObject
|
||||
|
||||
function stream($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_streamDirect'),
|
||||
array(),
|
||||
'file:notice-ids:'.$this->url,
|
||||
$offset, $limit, $since_id, $max_id);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream of notices linking to this URL
|
||||
*
|
||||
* @param integer $offset Offset to show; default is 0
|
||||
* @param integer $limit Limit of notices to show
|
||||
* @param integer $since_id Since this notice
|
||||
* @param integer $max_id Before this notice
|
||||
*
|
||||
* @return array ids of notices that link to this file
|
||||
*/
|
||||
|
||||
function _streamDirect($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$f2p = new File_to_post();
|
||||
|
||||
$f2p->selectAdd();
|
||||
$f2p->selectAdd('post_id');
|
||||
|
||||
$f2p->file_id = $this->id;
|
||||
|
||||
Notice::addWhereSinceId($f2p, $since_id, 'post_id', 'modified');
|
||||
Notice::addWhereMaxId($f2p, $max_id, 'post_id', 'modified');
|
||||
|
||||
$f2p->orderBy('modified DESC, post_id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$f2p->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($f2p->find()) {
|
||||
while ($f2p->fetch()) {
|
||||
$ids[] = $f2p->post_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
$stream = new FileNoticeStream($this);
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
function noticeCount()
|
||||
|
@ -91,7 +91,7 @@ class Foreign_link extends Memcached_DataObject
|
||||
$this->profilesync = 0;
|
||||
}
|
||||
|
||||
# Convenience methods
|
||||
// Convenience methods
|
||||
function getForeignUser()
|
||||
{
|
||||
$fuser = new Foreign_user();
|
||||
|
@ -65,7 +65,7 @@ class Foreign_user extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
if (count($parts) == 0) {
|
||||
# No changes
|
||||
// No changes
|
||||
return true;
|
||||
}
|
||||
$toupdate = implode(', ', $parts);
|
||||
|
@ -55,4 +55,80 @@ class Group_join_queue extends Managed_DataObject
|
||||
$rq->insert();
|
||||
return $rq;
|
||||
}
|
||||
|
||||
function getMember()
|
||||
{
|
||||
$member = Profile::staticGet('id', $this->profile_id);
|
||||
|
||||
if (empty($member)) {
|
||||
// TRANS: Exception thrown providing an invalid profile ID.
|
||||
// TRANS: %s is the invalid profile ID.
|
||||
throw new Exception(sprintf(_('Profile ID %s is invalid.'),$this->profile_id));
|
||||
}
|
||||
|
||||
return $member;
|
||||
}
|
||||
|
||||
function getGroup()
|
||||
{
|
||||
$group = User_group::staticGet('id', $this->group_id);
|
||||
|
||||
if (empty($group)) {
|
||||
// TRANS: Exception thrown providing an invalid group ID.
|
||||
// TRANS: %s is the invalid group ID.
|
||||
throw new Exception(sprintf(_('Group ID %s is invalid.'),$this->group_id));
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Abort the pending group join...
|
||||
*
|
||||
* @param User_group $group
|
||||
*/
|
||||
function abort()
|
||||
{
|
||||
$profile = $this->getMember();
|
||||
$group = $this->getGroup();
|
||||
if ($request) {
|
||||
if (Event::handle('StartCancelJoinGroup', array($profile, $group))) {
|
||||
$this->delete();
|
||||
Event::handle('EndCancelJoinGroup', array($profile, $group));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a pending group join...
|
||||
*
|
||||
* @return Group_member object on success
|
||||
*/
|
||||
function complete()
|
||||
{
|
||||
$join = null;
|
||||
$profile = $this->getMember();
|
||||
$group = $this->getGroup();
|
||||
if (Event::handle('StartJoinGroup', array($profile, $group))) {
|
||||
$join = Group_member::join($group->id, $profile->id);
|
||||
$this->delete();
|
||||
Event::handle('EndJoinGroup', array($profile, $group));
|
||||
}
|
||||
if (!$join) {
|
||||
throw new Exception('Internal error: group join failed.');
|
||||
}
|
||||
$join->notify();
|
||||
return $join;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notifications via email etc to group administrators about
|
||||
* this exciting new pending moderation queue item!
|
||||
*/
|
||||
public function notify()
|
||||
{
|
||||
$joiner = Profile::staticGet('id', $this->profile_id);
|
||||
$group = User_group::staticGet('id', $this->group_id);
|
||||
mail_notify_group_join_pending($group, $joiner);
|
||||
}
|
||||
}
|
||||
|
@ -162,4 +162,13 @@ class Group_member extends Memcached_DataObject
|
||||
|
||||
return $act;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notifications via email etc to group administrators about
|
||||
* this exciting new membership!
|
||||
*/
|
||||
public function notify()
|
||||
{
|
||||
mail_notify_group_join($this->getGroup(), $this->getMember());
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ class Inbox extends Memcached_DataObject
|
||||
// Do a bulk lookup for the first $limit items
|
||||
// Fast path when nothing's deleted.
|
||||
$firstChunk = array_slice($ids, 0, $offset + $limit);
|
||||
$notices = Notice::getStreamByIds($firstChunk);
|
||||
$notices = NoticeStream::getStreamByIds($firstChunk);
|
||||
|
||||
assert($notices instanceof ArrayWrapper);
|
||||
$items = $notices->_items;
|
||||
@ -292,7 +292,7 @@ class Inbox extends Memcached_DataObject
|
||||
// Do a bulk lookup for the first $limit items
|
||||
// Fast path when nothing's deleted.
|
||||
$firstChunk = array_slice($ids, 0, $limit);
|
||||
$notices = Notice::getStreamByIds($firstChunk);
|
||||
$notices = NoticeStream::getStreamByIds($firstChunk);
|
||||
|
||||
$wanted = count($firstChunk); // raw entry count in the inbox up to our $limit
|
||||
if ($notices->N >= $wanted) {
|
||||
|
@ -34,7 +34,7 @@ class Memcached_DataObject extends Safe_DataObject
|
||||
{
|
||||
if (is_null($v)) {
|
||||
$v = $k;
|
||||
# XXX: HACK!
|
||||
// XXX: HACK!
|
||||
$i = new $cls;
|
||||
$keys = $i->keys();
|
||||
$k = $keys[0];
|
||||
|
@ -45,7 +45,7 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
/* We keep 200 notices, the max number of notices available per API request,
|
||||
* in the memcached cache. */
|
||||
|
||||
define('NOTICE_CACHE_WINDOW', 200);
|
||||
define('NOTICE_CACHE_WINDOW', CachingNoticeStream::CACHE_WINDOW);
|
||||
|
||||
define('MAX_BOXCARS', 128);
|
||||
|
||||
@ -73,6 +73,7 @@ class Notice extends Memcached_DataObject
|
||||
public $location_ns; // int(4)
|
||||
public $repeat_of; // int(4)
|
||||
public $object_type; // varchar(255)
|
||||
public $scope; // int(4)
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL)
|
||||
@ -89,6 +90,12 @@ class Notice extends Memcached_DataObject
|
||||
const LOCAL_NONPUBLIC = -1;
|
||||
const GATEWAY = -2;
|
||||
|
||||
const PUBLIC_SCOPE = 0; // Useful fake constant
|
||||
const SITE_SCOPE = 1;
|
||||
const ADDRESSEE_SCOPE = 2;
|
||||
const GROUP_SCOPE = 4;
|
||||
const FOLLOWER_SCOPE = 8;
|
||||
|
||||
function getProfile()
|
||||
{
|
||||
$profile = Profile::staticGet('id', $this->profile_id);
|
||||
@ -243,6 +250,7 @@ class Notice extends Memcached_DataObject
|
||||
* notice in place of extracting links from content
|
||||
* boolean 'distribute' whether to distribute the notice, default true
|
||||
* string 'object_type' URL of the associated object type (default ActivityObject::NOTE)
|
||||
* int 'scope' Scope bitmask; default to SITE_SCOPE on private sites, 0 otherwise
|
||||
*
|
||||
* @fixme tag override
|
||||
*
|
||||
@ -254,6 +262,7 @@ class Notice extends Memcached_DataObject
|
||||
'url' => null,
|
||||
'reply_to' => null,
|
||||
'repeat_of' => null,
|
||||
'scope' => null,
|
||||
'distribute' => true);
|
||||
|
||||
if (!empty($options)) {
|
||||
@ -312,7 +321,7 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
$autosource = common_config('public', 'autosource');
|
||||
|
||||
# Sandboxed are non-false, but not 1, either
|
||||
// Sandboxed are non-false, but not 1, either
|
||||
|
||||
if (!$profile->hasRight(Right::PUBLICNOTICE) ||
|
||||
($source && $autosource && in_array($source, $autosource))) {
|
||||
@ -336,6 +345,37 @@ class Notice extends Memcached_DataObject
|
||||
// Handle repeat case
|
||||
|
||||
if (isset($repeat_of)) {
|
||||
|
||||
// Check for a private one
|
||||
|
||||
$repeat = Notice::staticGet('id', $repeat_of);
|
||||
|
||||
if (empty($repeat)) {
|
||||
throw new ClientException(_('Cannot repeat; original notice is missing or deleted.'));
|
||||
}
|
||||
|
||||
if ($profile->id == $repeat->profile_id) {
|
||||
// TRANS: Client error displayed when trying to repeat an own notice.
|
||||
throw new ClientException(_('You cannot repeat your own notice.'));
|
||||
}
|
||||
|
||||
if ($repeat->scope != Notice::SITE_SCOPE &&
|
||||
$repeat->scope != Notice::PUBLIC_SCOPE) {
|
||||
// TRANS: Client error displayed when trying to repeat a non-public notice.
|
||||
throw new ClientException(_('Cannot repeat a private notice.'), 403);
|
||||
}
|
||||
|
||||
if (!$repeat->inScope($profile)) {
|
||||
// The generic checks above should cover this, but let's be sure!
|
||||
// TRANS: Client error displayed when trying to repeat a notice you cannot access.
|
||||
throw new ClientException(_('Cannot repeat a notice you cannot read.'), 403);
|
||||
}
|
||||
|
||||
if ($profile->hasRepeated($repeat->id)) {
|
||||
// TRANS: Client error displayed when trying to repeat an already repeated notice.
|
||||
throw new ClientException(_('You already repeated that notice.'));
|
||||
}
|
||||
|
||||
$notice->repeat_of = $repeat_of;
|
||||
} else {
|
||||
$notice->reply_to = self::getReplyTo($reply_to, $profile_id, $source, $final);
|
||||
@ -343,6 +383,12 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
if (!empty($notice->reply_to)) {
|
||||
$reply = Notice::staticGet('id', $notice->reply_to);
|
||||
if (!$reply->inScope($profile)) {
|
||||
// TRANS: Client error displayed when trying to reply to a notice a the target has no access to.
|
||||
// TRANS: %1$s is a user nickname, %2$d is a notice ID (number).
|
||||
throw new ClientException(sprintf(_('%1$s has no access to notice %2$d.'),
|
||||
$profile->nickname, $reply->id), 403);
|
||||
}
|
||||
$notice->conversation = $reply->conversation;
|
||||
}
|
||||
|
||||
@ -368,6 +414,12 @@ class Notice extends Memcached_DataObject
|
||||
$notice->object_type = $object_type;
|
||||
}
|
||||
|
||||
if (is_null($scope)) { // 0 is a valid value
|
||||
$notice->scope = common_config('notice', 'defaultscope');
|
||||
} else {
|
||||
$notice->scope = $scope;
|
||||
}
|
||||
|
||||
if (Event::handle('StartNoticeSave', array(&$notice))) {
|
||||
|
||||
// XXX: some of these functions write to the DB
|
||||
@ -410,8 +462,8 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
}
|
||||
|
||||
# Clear the cache for subscribed users, so they'll update at next request
|
||||
# XXX: someone clever could prepend instead of clearing the cache
|
||||
// Clear the cache for subscribed users, so they'll update at next request
|
||||
// XXX: someone clever could prepend instead of clearing the cache
|
||||
|
||||
$notice->blowOnInsert();
|
||||
|
||||
@ -554,7 +606,7 @@ class Notice extends Memcached_DataObject
|
||||
if (empty($profile)) {
|
||||
return false;
|
||||
}
|
||||
$notice = $profile->getNotices(0, NOTICE_CACHE_WINDOW);
|
||||
$notice = $profile->getNotices(0, CachingNoticeStream::CACHE_WINDOW);
|
||||
if (!empty($notice)) {
|
||||
$last = 0;
|
||||
while ($notice->fetch()) {
|
||||
@ -565,8 +617,8 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
}
|
||||
# If we get here, oldest item in cache window is not
|
||||
# old enough for dupe limit; do direct check against DB
|
||||
// If we get here, oldest item in cache window is not
|
||||
// old enough for dupe limit; do direct check against DB
|
||||
$notice = new Notice();
|
||||
$notice->profile_id = $profile_id;
|
||||
$notice->content = $content;
|
||||
@ -582,16 +634,16 @@ class Notice extends Memcached_DataObject
|
||||
if (empty($profile)) {
|
||||
return false;
|
||||
}
|
||||
# Get the Nth notice
|
||||
// Get the Nth notice
|
||||
$notice = $profile->getNotices(common_config('throttle', 'count') - 1, 1);
|
||||
if ($notice && $notice->fetch()) {
|
||||
# If the Nth notice was posted less than timespan seconds ago
|
||||
// If the Nth notice was posted less than timespan seconds ago
|
||||
if (time() - strtotime($notice->created) <= common_config('throttle', 'timespan')) {
|
||||
# Then we throttle
|
||||
// Then we throttle
|
||||
return false;
|
||||
}
|
||||
}
|
||||
# Either not N notices in the stream, OR the Nth was not posted within timespan seconds
|
||||
// Either not N notices in the stream, OR the Nth was not posted within timespan seconds
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -635,134 +687,19 @@ class Notice extends Memcached_DataObject
|
||||
return $att;
|
||||
}
|
||||
|
||||
function getStreamByIds($ids)
|
||||
{
|
||||
$cache = Cache::instance();
|
||||
|
||||
if (!empty($cache)) {
|
||||
$notices = array();
|
||||
foreach ($ids as $id) {
|
||||
$n = Notice::staticGet('id', $id);
|
||||
if (!empty($n)) {
|
||||
$notices[] = $n;
|
||||
}
|
||||
}
|
||||
return new ArrayWrapper($notices);
|
||||
} else {
|
||||
$notice = new Notice();
|
||||
if (empty($ids)) {
|
||||
//if no IDs requested, just return the notice object
|
||||
return $notice;
|
||||
}
|
||||
$notice->whereAdd('id in (' . implode(', ', $ids) . ')');
|
||||
|
||||
$notice->find();
|
||||
|
||||
$temp = array();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$temp[$notice->id] = clone($notice);
|
||||
}
|
||||
|
||||
$wrapped = array();
|
||||
|
||||
foreach ($ids as $id) {
|
||||
if (array_key_exists($id, $temp)) {
|
||||
$wrapped[] = $temp[$id];
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayWrapper($wrapped);
|
||||
}
|
||||
}
|
||||
|
||||
function publicStream($offset=0, $limit=20, $since_id=0, $max_id=0)
|
||||
{
|
||||
$ids = Notice::stream(array('Notice', '_publicStreamDirect'),
|
||||
array(),
|
||||
'public',
|
||||
$offset, $limit, $since_id, $max_id);
|
||||
return Notice::getStreamByIds($ids);
|
||||
$stream = new PublicNoticeStream();
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
function _publicStreamDirect($offset=0, $limit=20, $since_id=0, $max_id=0)
|
||||
{
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->selectAdd(); // clears it
|
||||
$notice->selectAdd('id');
|
||||
|
||||
$notice->orderBy('created DESC, id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$notice->limit($offset, $limit);
|
||||
}
|
||||
|
||||
if (common_config('public', 'localonly')) {
|
||||
$notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
|
||||
} else {
|
||||
# -1 == blacklisted, -2 == gateway (i.e. Twitter)
|
||||
$notice->whereAdd('is_local !='. Notice::LOCAL_NONPUBLIC);
|
||||
$notice->whereAdd('is_local !='. Notice::GATEWAY);
|
||||
}
|
||||
|
||||
Notice::addWhereSinceId($notice, $since_id);
|
||||
Notice::addWhereMaxId($notice, $max_id);
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($notice->find()) {
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function conversationStream($id, $offset=0, $limit=20, $since_id=0, $max_id=0)
|
||||
{
|
||||
$ids = Notice::stream(array('Notice', '_conversationStreamDirect'),
|
||||
array($id),
|
||||
'notice:conversation_ids:'.$id,
|
||||
$offset, $limit, $since_id, $max_id);
|
||||
$stream = new ConversationNoticeStream($id);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _conversationStreamDirect($id, $offset=0, $limit=20, $since_id=0, $max_id=0)
|
||||
{
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->selectAdd(); // clears it
|
||||
$notice->selectAdd('id');
|
||||
|
||||
$notice->conversation = $id;
|
||||
|
||||
$notice->orderBy('created DESC, id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$notice->limit($offset, $limit);
|
||||
}
|
||||
|
||||
Notice::addWhereSinceId($notice, $since_id);
|
||||
Notice::addWhereMaxId($notice, $max_id);
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($notice->find()) {
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1655,61 +1592,6 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
function stream($fn, $args, $cachekey, $offset=0, $limit=20, $since_id=0, $max_id=0)
|
||||
{
|
||||
$cache = Cache::instance();
|
||||
|
||||
if (empty($cache) ||
|
||||
$since_id != 0 || $max_id != 0 ||
|
||||
is_null($limit) ||
|
||||
($offset + $limit) > NOTICE_CACHE_WINDOW) {
|
||||
return call_user_func_array($fn, array_merge($args, array($offset, $limit, $since_id,
|
||||
$max_id)));
|
||||
}
|
||||
|
||||
$idkey = Cache::key($cachekey);
|
||||
|
||||
$idstr = $cache->get($idkey);
|
||||
|
||||
if ($idstr !== false) {
|
||||
// Cache hit! Woohoo!
|
||||
$window = explode(',', $idstr);
|
||||
$ids = array_slice($window, $offset, $limit);
|
||||
return $ids;
|
||||
}
|
||||
|
||||
$laststr = $cache->get($idkey.';last');
|
||||
|
||||
if ($laststr !== false) {
|
||||
$window = explode(',', $laststr);
|
||||
$last_id = $window[0];
|
||||
$new_ids = call_user_func_array($fn, array_merge($args, array(0, NOTICE_CACHE_WINDOW,
|
||||
$last_id, 0, null)));
|
||||
|
||||
$new_window = array_merge($new_ids, $window);
|
||||
|
||||
$new_windowstr = implode(',', $new_window);
|
||||
|
||||
$result = $cache->set($idkey, $new_windowstr);
|
||||
$result = $cache->set($idkey . ';last', $new_windowstr);
|
||||
|
||||
$ids = array_slice($new_window, $offset, $limit);
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
$window = call_user_func_array($fn, array_merge($args, array(0, NOTICE_CACHE_WINDOW,
|
||||
0, 0, null)));
|
||||
|
||||
$windowstr = implode(',', $window);
|
||||
|
||||
$result = $cache->set($idkey, $windowstr);
|
||||
$result = $cache->set($idkey . ';last', $windowstr);
|
||||
|
||||
$ids = array_slice($window, $offset, $limit);
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine which notice, if any, a new notice is in reply to.
|
||||
@ -1820,6 +1702,15 @@ class Notice extends Memcached_DataObject
|
||||
return $location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for posting a repeat of an existing message.
|
||||
*
|
||||
* @param int $repeater_id: profile ID of user doing the repeat
|
||||
* @param string $source: posting source key, eg 'web', 'api', etc
|
||||
* @return Notice
|
||||
*
|
||||
* @throws Exception on failure or permission problems
|
||||
*/
|
||||
function repeat($repeater_id, $source)
|
||||
{
|
||||
$author = Profile::staticGet('id', $this->profile_id);
|
||||
@ -1841,8 +1732,13 @@ class Notice extends Memcached_DataObject
|
||||
$content = mb_substr($content, 0, $maxlen - 4) . ' ...';
|
||||
}
|
||||
|
||||
return self::saveNew($repeater_id, $content, $source,
|
||||
array('repeat_of' => $this->id));
|
||||
// Scope is same as this one's
|
||||
|
||||
return self::saveNew($repeater_id,
|
||||
$content,
|
||||
$source,
|
||||
array('repeat_of' => $this->id,
|
||||
'scope' => $this->scope));
|
||||
}
|
||||
|
||||
// These are supposed to be in chron order!
|
||||
@ -1867,7 +1763,7 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
return NoticeStream::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _repeatStreamDirect($limit)
|
||||
@ -2296,4 +2192,94 @@ class Notice extends Memcached_DataObject
|
||||
($this->is_local != Notice::GATEWAY));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the given profile is allowed to read, respond to, or otherwise
|
||||
* act on this notice.
|
||||
*
|
||||
* The $scope member is a bitmask of scopes, representing a logical AND of the
|
||||
* scope requirement. So, 0x03 (Notice::ADDRESSEE_SCOPE | Notice::SITE_SCOPE) means
|
||||
* "only visible to people who are mentioned in the notice AND are users on this site."
|
||||
* Users on the site who are not mentioned in the notice will not be able to see the
|
||||
* notice.
|
||||
*
|
||||
* @param Profile $profile The profile to check; pass null to check for public/unauthenticated users.
|
||||
*
|
||||
* @return boolean whether the profile is in the notice's scope
|
||||
*/
|
||||
function inScope($profile)
|
||||
{
|
||||
// If there's no scope, anyone (even anon) is in scope.
|
||||
|
||||
if ($this->scope == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there's scope, anon cannot be in scope
|
||||
|
||||
if (empty($profile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Author is always in scope
|
||||
|
||||
if ($this->profile_id == $profile->id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only for users on this site
|
||||
|
||||
if ($this->scope & Notice::SITE_SCOPE) {
|
||||
$user = $profile->getUser();
|
||||
if (empty($user)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only for users mentioned in the notice
|
||||
|
||||
if ($this->scope & Notice::ADDRESSEE_SCOPE) {
|
||||
|
||||
// XXX: just query for the single reply
|
||||
|
||||
$replies = $this->getReplies();
|
||||
|
||||
if (!in_array($profile->id, $replies)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only for members of the given group
|
||||
|
||||
if ($this->scope & Notice::GROUP_SCOPE) {
|
||||
|
||||
// XXX: just query for the single membership
|
||||
|
||||
$groups = $this->getGroups();
|
||||
|
||||
$foundOne = false;
|
||||
|
||||
foreach ($groups as $group) {
|
||||
if ($profile->isMember($group)) {
|
||||
$foundOne = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$foundOne) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only for followers of the author
|
||||
|
||||
if ($this->scope & Notice::FOLLOWER_SCOPE) {
|
||||
$author = $this->getProfile();
|
||||
if (!Subscription::exists($profile, $author)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -36,43 +36,11 @@ class Notice_tag extends Memcached_DataObject
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
static function getStream($tag, $offset=0, $limit=20) {
|
||||
|
||||
$ids = Notice::stream(array('Notice_tag', '_streamDirect'),
|
||||
array($tag),
|
||||
'notice_tag:notice_ids:' . Cache::keyize($tag),
|
||||
$offset, $limit);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _streamDirect($tag, $offset, $limit, $since_id, $max_id)
|
||||
static function getStream($tag, $offset=0, $limit=20, $sinceId=0, $maxId=0)
|
||||
{
|
||||
$nt = new Notice_tag();
|
||||
$stream = new TagNoticeStream($tag);
|
||||
|
||||
$nt->tag = $tag;
|
||||
|
||||
$nt->selectAdd();
|
||||
$nt->selectAdd('notice_id');
|
||||
|
||||
Notice::addWhereSinceId($nt, $since_id, 'notice_id');
|
||||
Notice::addWhereMaxId($nt, $max_id, 'notice_id');
|
||||
|
||||
$nt->orderBy('created DESC, notice_id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$nt->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($nt->find()) {
|
||||
while ($nt->fetch()) {
|
||||
$ids[] = $nt->notice_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
return $stream->getNotices($offset, $limit, $sinceId, $maxId);
|
||||
}
|
||||
|
||||
function blowCache($blowLast=false)
|
||||
|
@ -51,7 +51,7 @@ class Oauth_application_user extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
if (count($parts) == 0) {
|
||||
# No changes
|
||||
// No changes
|
||||
return true;
|
||||
}
|
||||
$toupdate = implode(', ', $parts);
|
||||
|
@ -93,7 +93,7 @@ class Profile extends Memcached_DataObject
|
||||
$avatar->url = Avatar::url($filename);
|
||||
$avatar->created = DB_DataObject_Cast::dateTime(); # current time
|
||||
|
||||
# XXX: start a transaction here
|
||||
// XXX: start a transaction here
|
||||
|
||||
if (!$this->delete_avatars() || !$avatar->insert()) {
|
||||
@unlink(Avatar::path($filename));
|
||||
@ -101,7 +101,7 @@ class Profile extends Memcached_DataObject
|
||||
}
|
||||
|
||||
foreach (array(AVATAR_PROFILE_SIZE, AVATAR_STREAM_SIZE, AVATAR_MINI_SIZE) as $size) {
|
||||
# We don't do a scaled one if original is our scaled size
|
||||
// We don't do a scaled one if original is our scaled size
|
||||
if (!($avatar->width == $size && $avatar->height == $size)) {
|
||||
$scaled_filename = $imagefile->resize($size);
|
||||
|
||||
@ -168,7 +168,7 @@ class Profile extends Memcached_DataObject
|
||||
function getFancyName()
|
||||
{
|
||||
if ($this->fullname) {
|
||||
// TRANS: Full name of a profile or group followed by nickname in parens
|
||||
// TRANS: Full name of a profile or group (%1$s) followed by nickname (%2$s) in parentheses.
|
||||
return sprintf(_m('FANCYNAME','%1$s (%2$s)'), $this->fullname, $this->nickname);
|
||||
} else {
|
||||
return $this->nickname;
|
||||
@ -180,7 +180,6 @@ class Profile extends Memcached_DataObject
|
||||
*
|
||||
* @return mixed Notice or null
|
||||
*/
|
||||
|
||||
function getCurrentNotice()
|
||||
{
|
||||
$notice = $this->getNotices(0, 1);
|
||||
@ -198,90 +197,16 @@ class Profile extends Memcached_DataObject
|
||||
|
||||
function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_streamTaggedDirect'),
|
||||
array($tag),
|
||||
'profile:notice_ids_tagged:' . $this->id . ':' . $tag,
|
||||
$offset, $limit, $since_id, $max_id);
|
||||
return Notice::getStreamByIds($ids);
|
||||
$stream = new TaggedProfileNoticeStream($this, $tag);
|
||||
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
|
||||
{
|
||||
// XXX: I'm not sure this is going to be any faster. It probably isn't.
|
||||
$ids = Notice::stream(array($this, '_streamDirect'),
|
||||
array(),
|
||||
'profile:notice_ids:' . $this->id,
|
||||
$offset, $limit, $since_id, $max_id);
|
||||
$stream = new ProfileNoticeStream($this);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _streamTaggedDirect($tag, $offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
// XXX It would be nice to do this without a join
|
||||
// (necessary to do it efficiently on accounts with long history)
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
$query =
|
||||
"select id from notice join notice_tag on id=notice_id where tag='".
|
||||
$notice->escape($tag) .
|
||||
"' and profile_id=" . intval($this->id);
|
||||
|
||||
$since = Notice::whereSinceId($since_id, 'id', 'notice.created');
|
||||
if ($since) {
|
||||
$query .= " and ($since)";
|
||||
}
|
||||
|
||||
$max = Notice::whereMaxId($max_id, 'id', 'notice.created');
|
||||
if ($max) {
|
||||
$query .= " and ($max)";
|
||||
}
|
||||
|
||||
$query .= ' order by notice.created DESC, id DESC';
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$query .= " LIMIT " . intval($limit) . " OFFSET " . intval($offset);
|
||||
}
|
||||
|
||||
$notice->query($query);
|
||||
|
||||
$ids = array();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function _streamDirect($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->profile_id = $this->id;
|
||||
|
||||
$notice->selectAdd();
|
||||
$notice->selectAdd('id');
|
||||
|
||||
Notice::addWhereSinceId($notice, $since_id);
|
||||
Notice::addWhereMaxId($notice, $max_id);
|
||||
|
||||
$notice->orderBy('created DESC, id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$notice->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$notice->find();
|
||||
|
||||
$ids = array();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
|
||||
return $ids;
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
function isMember($group)
|
||||
@ -532,55 +457,20 @@ class Profile extends Memcached_DataObject
|
||||
*/
|
||||
function joinGroup(User_group $group)
|
||||
{
|
||||
$ok = null;
|
||||
$join = null;
|
||||
if ($group->join_policy == User_group::JOIN_POLICY_MODERATE) {
|
||||
$ok = Group_join_queue::saveNew($this, $group);
|
||||
$join = Group_join_queue::saveNew($this, $group);
|
||||
} else {
|
||||
if (Event::handle('StartJoinGroup', array($group, $this))) {
|
||||
$ok = Group_member::join($group->id, $this->id);
|
||||
$join = Group_member::join($group->id, $this->id);
|
||||
Event::handle('EndJoinGroup', array($group, $this));
|
||||
}
|
||||
}
|
||||
return $ok;
|
||||
if ($join) {
|
||||
// Send any applicable notifications...
|
||||
$join->notify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a pending group join...
|
||||
*
|
||||
* @param User_group $group
|
||||
*/
|
||||
function cancelJoinGroup(User_group $group)
|
||||
{
|
||||
$request = Group_join_queue::pkeyGet(array('profile_id' => $this->id,
|
||||
'group_id' => $group->id));
|
||||
if ($request) {
|
||||
if (Event::handle('StartCancelJoinGroup', array($group, $this))) {
|
||||
$request->delete();
|
||||
Event::handle('EndCancelJoinGroup', array($group, $this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a pending group join on our end...
|
||||
*
|
||||
* @param User_group $group
|
||||
*/
|
||||
function completeJoinGroup(User_group $group)
|
||||
{
|
||||
$ok = null;
|
||||
$request = Group_join_queue::pkeyGet(array('profile_id' => $this->id,
|
||||
'group_id' => $group->id));
|
||||
if ($request) {
|
||||
if (Event::handle('StartJoinGroup', array($group, $this))) {
|
||||
$ok = Group_member::join($group->id, $this->id);
|
||||
$request->delete();
|
||||
Event::handle('EndJoinGroup', array($group, $this));
|
||||
}
|
||||
} else {
|
||||
throw new Exception(_m('Invalid group join approval: not pending.'));
|
||||
}
|
||||
return $ok;
|
||||
return $join;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -642,7 +532,6 @@ class Profile extends Memcached_DataObject
|
||||
return new ArrayWrapper($profiles);
|
||||
}
|
||||
|
||||
|
||||
function getTaggedSubscribers($tag)
|
||||
{
|
||||
$qry =
|
||||
@ -668,6 +557,36 @@ class Profile extends Memcached_DataObject
|
||||
return $tagged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pending subscribers, 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 subscription_queue '.
|
||||
'ON profile.id = subscription_queue.subscriber ' .
|
||||
'WHERE subscription_queue.subscribed = %d ' .
|
||||
'ORDER BY subscription_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 subscriptionCount()
|
||||
{
|
||||
$c = Cache::instance();
|
||||
@ -726,6 +645,17 @@ class Profile extends Memcached_DataObject
|
||||
return Subscription::exists($this, $other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a pending subscription request is outstanding for this...
|
||||
*
|
||||
* @param Profile $other
|
||||
* @return boolean
|
||||
*/
|
||||
function hasPendingSubscription($other)
|
||||
{
|
||||
return Subscription_queue::exists($this, $other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Are these two profiles subscribed to each other?
|
||||
*
|
||||
@ -748,7 +678,7 @@ class Profile extends Memcached_DataObject
|
||||
// This is the stream of favorite notices, in rev chron
|
||||
// order. This forces it into cache.
|
||||
|
||||
$ids = Fave::stream($this->id, 0, NOTICE_CACHE_WINDOW);
|
||||
$ids = Fave::idStream($this->id, 0, CachingNoticeStream::CACHE_WINDOW);
|
||||
|
||||
// If it's in the list, then it's a fave
|
||||
|
||||
@ -760,7 +690,7 @@ class Profile extends Memcached_DataObject
|
||||
// then the cache has all available faves, so this one
|
||||
// is not a fave.
|
||||
|
||||
if (count($ids) < NOTICE_CACHE_WINDOW) {
|
||||
if (count($ids) < CachingNoticeStream::CACHE_WINDOW) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1359,4 +1289,44 @@ class Profile extends Memcached_DataObject
|
||||
|
||||
return $profile;
|
||||
}
|
||||
|
||||
function canRead(Notice $notice)
|
||||
{
|
||||
if ($notice->scope & Notice::SITE_SCOPE) {
|
||||
$user = $this->getUser();
|
||||
if (empty($user)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($notice->scope & Notice::ADDRESSEE_SCOPE) {
|
||||
$replies = $notice->getReplies();
|
||||
|
||||
if (!in_array($this->id, $replies)) {
|
||||
$groups = $notice->getGroups();
|
||||
|
||||
$foundOne = false;
|
||||
|
||||
foreach ($groups as $group) {
|
||||
if ($this->isMember($group)) {
|
||||
$foundOne = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$foundOne) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($notice->scope & Notice::FOLLOWER_SCOPE) {
|
||||
$author = $notice->getProfile();
|
||||
if (!Subscription::exists($this, $author)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -106,11 +106,11 @@ class Profile_tag extends Memcached_DataObject
|
||||
|
||||
$ptag = new Profile_tag();
|
||||
|
||||
# Delete stuff that's in old and not in new
|
||||
// Delete stuff that's in old and not in new
|
||||
|
||||
$to_delete = array_diff($oldtags, $newtags);
|
||||
|
||||
# Insert stuff that's in new and not in old
|
||||
// Insert stuff that's in new and not in old
|
||||
|
||||
$to_insert = array_diff($newtags, $oldtags);
|
||||
|
||||
@ -271,4 +271,19 @@ class Profile_tag extends Memcached_DataObject
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return profiles with a given tag
|
||||
static function getTagged($tagger, $tag) {
|
||||
$profile = new Profile();
|
||||
$profile->query('SELECT profile.* ' .
|
||||
'FROM profile JOIN profile_tag ' .
|
||||
'ON profile.id = profile_tag.tagged ' .
|
||||
'WHERE profile_tag.tagger = ' . $tagger . ' ' .
|
||||
'AND profile_tag.tag = "' . $tag . '" ');
|
||||
$tagged = array();
|
||||
while ($profile->fetch()) {
|
||||
$tagged[] = clone($profile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -46,9 +46,9 @@ class Queue_item extends Memcached_DataObject
|
||||
$cnt = $qi->find(true);
|
||||
|
||||
if ($cnt) {
|
||||
# XXX: potential race condition
|
||||
# can we force it to only update if claimed is still null
|
||||
# (or old)?
|
||||
// XXX: potential race condition
|
||||
// can we force it to only update if claimed is still null
|
||||
// (or old)?
|
||||
common_log(LOG_INFO, 'claiming queue item id = ' . $qi->id .
|
||||
' for transport ' . $qi->transport);
|
||||
$orig = clone($qi);
|
||||
|
@ -38,35 +38,8 @@ class Reply extends Memcached_DataObject
|
||||
|
||||
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
|
||||
{
|
||||
$ids = Notice::stream(array('Reply', '_streamDirect'),
|
||||
array($user_id),
|
||||
'reply:stream:' . $user_id,
|
||||
$offset, $limit, $since_id, $max_id);
|
||||
return $ids;
|
||||
}
|
||||
$stream = new ReplyNoticeStream($user_id);
|
||||
|
||||
function _streamDirect($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
|
||||
{
|
||||
$reply = new Reply();
|
||||
$reply->profile_id = $user_id;
|
||||
|
||||
Notice::addWhereSinceId($reply, $since_id, 'notice_id', 'modified');
|
||||
Notice::addWhereMaxId($reply, $max_id, 'notice_id', 'modified');
|
||||
|
||||
$reply->orderBy('modified DESC, notice_id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$reply->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($reply->find()) {
|
||||
while ($reply->fetch()) {
|
||||
$ids[] = $reply->notice_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
class Subscription extends Memcached_DataObject
|
||||
{
|
||||
const CACHE_WINDOW = 201;
|
||||
const FORCE = true;
|
||||
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
@ -58,11 +59,12 @@ class Subscription extends Memcached_DataObject
|
||||
*
|
||||
* @param Profile $subscriber party to receive new notices
|
||||
* @param Profile $other party sending notices; publisher
|
||||
* @param bool $force pass Subscription::FORCE to override local subscription approval
|
||||
*
|
||||
* @return Subscription new subscription
|
||||
* @return mixed Subscription or Subscription_queue: new subscription info
|
||||
*/
|
||||
|
||||
static function start($subscriber, $other)
|
||||
static function start($subscriber, $other, $force=false)
|
||||
{
|
||||
// @fixme should we enforce this as profiles in callers instead?
|
||||
if ($subscriber instanceof User) {
|
||||
@ -88,6 +90,11 @@ class Subscription extends Memcached_DataObject
|
||||
}
|
||||
|
||||
if (Event::handle('StartSubscribe', array($subscriber, $other))) {
|
||||
$otherUser = User::staticGet('id', $other->id);
|
||||
if ($otherUser && $otherUser->subscribe_policy == User::SUBSCRIBE_POLICY_MODERATE && !$force) {
|
||||
$sub = Subscription_queue::saveNew($subscriber, $other);
|
||||
$sub->notify();
|
||||
} else {
|
||||
$sub = self::saveNew($subscriber->id, $other->id);
|
||||
$sub->notify();
|
||||
|
||||
@ -99,8 +106,6 @@ class Subscription extends Memcached_DataObject
|
||||
$subscriber->blowSubscriptionCount();
|
||||
$other->blowSubscriberCount();
|
||||
|
||||
$otherUser = User::staticGet('id', $other->id);
|
||||
|
||||
if (!empty($otherUser) &&
|
||||
$otherUser->autosubscribe &&
|
||||
!self::exists($other, $subscriber) &&
|
||||
@ -112,11 +117,12 @@ class Subscription extends Memcached_DataObject
|
||||
common_log(LOG_ERR, "Exception during autosubscribe of {$other->nickname} to profile {$subscriber->id}: {$e->getMessage()}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Event::handle('EndSubscribe', array($subscriber, $other));
|
||||
}
|
||||
|
||||
return true;
|
||||
return $sub;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,9 +152,9 @@ class Subscription extends Memcached_DataObject
|
||||
|
||||
function notify()
|
||||
{
|
||||
# XXX: add other notifications (Jabber, SMS) here
|
||||
# XXX: queue this and handle it offline
|
||||
# XXX: Whatever happens, do it in Twitter-like API, too
|
||||
// XXX: add other notifications (Jabber, SMS) here
|
||||
// XXX: queue this and handle it offline
|
||||
// XXX: Whatever happens, do it in Twitter-like API, too
|
||||
|
||||
$this->notifyEmail();
|
||||
}
|
||||
@ -261,8 +267,8 @@ class Subscription extends Memcached_DataObject
|
||||
common_date_iso8601($this->created));
|
||||
|
||||
$act->time = strtotime($this->created);
|
||||
// TRANS: Activity tile when subscribing to another person.
|
||||
$act->title = _("Follow");
|
||||
// TRANS: Activity title when subscribing to another person.
|
||||
$act->title = _m('TITLE','Follow');
|
||||
// TRANS: Notification given when one person starts following another.
|
||||
// TRANS: %1$s is the subscriber, %2$s is the subscribed.
|
||||
$act->content = sprintf(_('%1$s is now following %2$s.'),
|
||||
@ -295,7 +301,6 @@ class Subscription extends Memcached_DataObject
|
||||
*
|
||||
* @return Subscription stream of subscriptions; use fetch() to iterate
|
||||
*/
|
||||
|
||||
static function bySubscriber($subscriberId,
|
||||
$offset = 0,
|
||||
$limit = PROFILES_PER_PAGE)
|
||||
@ -356,7 +361,6 @@ class Subscription extends Memcached_DataObject
|
||||
*
|
||||
* @return Subscription stream of subscriptions; use fetch() to iterate
|
||||
*/
|
||||
|
||||
static function bySubscribed($subscribedId,
|
||||
$offset = 0,
|
||||
$limit = PROFILES_PER_PAGE)
|
||||
@ -414,7 +418,6 @@ class Subscription extends Memcached_DataObject
|
||||
*
|
||||
* @return boolean success flag.
|
||||
*/
|
||||
|
||||
function update($orig=null)
|
||||
{
|
||||
$result = parent::update($orig);
|
||||
|
105
classes/Subscription_queue.php
Normal file
105
classes/Subscription_queue.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Definition for subscription_queue
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Subscription_queue extends Managed_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'subscription_queue'; // table name
|
||||
public $subscriber;
|
||||
public $subscribed;
|
||||
public $created;
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=null)
|
||||
{ return Memcached_DataObject::staticGet('Subscription_queue',$k,$v); }
|
||||
|
||||
/* Pkey get */
|
||||
function pkeyGet($k)
|
||||
{ return Memcached_DataObject::pkeyGet('Subscription_queue',$k); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
public static function schemaDef()
|
||||
{
|
||||
return array(
|
||||
'description' => 'Holder for subscription requests awaiting moderation.',
|
||||
'fields' => array(
|
||||
'subscriber' => array('type' => 'int', 'not null' => true, 'description' => 'remote or local profile making the request'),
|
||||
'subscribed' => array('type' => 'int', 'not null' => true, 'description' => 'remote or local profile being subscribed to'),
|
||||
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
|
||||
),
|
||||
'primary key' => array('subscriber', 'subscribed'),
|
||||
'indexes' => array(
|
||||
'subscription_queue_subscriber_created_idx' => array('subscriber', 'created'),
|
||||
'subscription_queue_subscribed_created_idx' => array('subscribed', 'created'),
|
||||
),
|
||||
'foreign keys' => array(
|
||||
'subscription_queue_subscriber_fkey' => array('profile', array('subscriber' => 'id')),
|
||||
'subscription_queue_subscribed_fkey' => array('profile', array('subscribed' => 'id')),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static function saveNew(Profile $subscriber, Profile $subscribed)
|
||||
{
|
||||
$rq = new Subscription_queue();
|
||||
$rq->subscriber = $subscriber->id;
|
||||
$rq->subscribed = $subscribed->id;
|
||||
$rq->created = common_sql_now();
|
||||
$rq->insert();
|
||||
return $rq;
|
||||
}
|
||||
|
||||
function exists($subscriber, $other)
|
||||
{
|
||||
$sub = Subscription_queue::pkeyGet(array('subscriber' => $subscriber->id,
|
||||
'subscribed' => $other->id));
|
||||
return (empty($sub)) ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete a pending subscription, as we've got approval of some sort.
|
||||
*
|
||||
* @return Subscription
|
||||
*/
|
||||
public function complete()
|
||||
{
|
||||
$subscriber = Profile::staticGet('id', $this->subscriber);
|
||||
$subscribed = Profile::staticGet('id', $this->subscribed);
|
||||
$sub = Subscription::start($subscriber, $subscribed, Subscription::FORCE);
|
||||
if ($sub) {
|
||||
$this->delete();
|
||||
}
|
||||
return $sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel an outstanding subscription request to the other profile.
|
||||
*/
|
||||
public function abort()
|
||||
{
|
||||
$subscriber = Profile::staticGet('id', $this->subscriber);
|
||||
$subscribed = Profile::staticGet('id', $this->subscribed);
|
||||
if (Event::handle('StartCancelSubscription', array($subscriber, $subscribed))) {
|
||||
$this->delete();
|
||||
Event::handle('EndCancelSubscription', array($subscriber, $subscribed));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notifications via email etc to group administrators about
|
||||
* this exciting new pending moderation queue item!
|
||||
*/
|
||||
public function notify()
|
||||
{
|
||||
$other = Profile::staticGet('id', $this->subscriber);
|
||||
$listenee = User::staticGet('id', $this->subscribed);
|
||||
mail_subscribe_pending_notify_profile($listenee, $other);
|
||||
}
|
||||
}
|
102
classes/User.php
102
classes/User.php
@ -30,6 +30,9 @@ require_once 'Validate.php';
|
||||
|
||||
class User extends Memcached_DataObject
|
||||
{
|
||||
const SUBSCRIBE_POLICY_OPEN = 0;
|
||||
const SUBSCRIBE_POLICY_MODERATE = 1;
|
||||
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
@ -55,6 +58,7 @@ class User extends Memcached_DataObject
|
||||
public $smsemail; // varchar(255)
|
||||
public $uri; // varchar(255) unique_key
|
||||
public $autosubscribe; // tinyint(1)
|
||||
public $subscribe_policy; // tinyint(1)
|
||||
public $urlshorteningservice; // varchar(50) default_ur1.ca
|
||||
public $inboxed; // tinyint(1)
|
||||
public $design_id; // int(4)
|
||||
@ -86,6 +90,12 @@ class User extends Memcached_DataObject
|
||||
return $profile->isSubscribed($other);
|
||||
}
|
||||
|
||||
function hasPendingSubscription($other)
|
||||
{
|
||||
$profile = $this->getProfile();
|
||||
return $profile->hasPendingSubscription($other);
|
||||
}
|
||||
|
||||
// 'update' won't write key columns, so we have to do it ourselves.
|
||||
|
||||
function updateKeys(&$orig)
|
||||
@ -448,8 +458,7 @@ class User extends Memcached_DataObject
|
||||
|
||||
function getReplies($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0)
|
||||
{
|
||||
$ids = Reply::stream($this->id, $offset, $limit, $since_id, $before_id);
|
||||
return Notice::getStreamByIds($ids);
|
||||
return Reply::stream($this->id, $offset, $limit, $since_id, $before_id);
|
||||
}
|
||||
|
||||
function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) {
|
||||
@ -465,8 +474,7 @@ class User extends Memcached_DataObject
|
||||
|
||||
function favoriteNotices($own=false, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
|
||||
{
|
||||
$ids = Fave::stream($this->id, $offset, $limit, $own, $since_id, $max_id);
|
||||
return Notice::getStreamByIds($ids);
|
||||
return Fave::stream($this->id, $offset, $limit, $own, $since_id, $max_id);
|
||||
}
|
||||
|
||||
function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0)
|
||||
@ -769,95 +777,18 @@ class User extends Memcached_DataObject
|
||||
|
||||
function repeatedByMe($offset=0, $limit=20, $since_id=null, $max_id=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_repeatedByMeDirect'),
|
||||
array(),
|
||||
'user:repeated_by_me:'.$this->id,
|
||||
$offset, $limit, $since_id, $max_id, null);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
$stream = new RepeatedByMeNoticeStream($this);
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
function _repeatedByMeDirect($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->selectAdd(); // clears it
|
||||
$notice->selectAdd('id');
|
||||
|
||||
$notice->profile_id = $this->id;
|
||||
$notice->whereAdd('repeat_of IS NOT NULL');
|
||||
|
||||
$notice->orderBy('created DESC, id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$notice->limit($offset, $limit);
|
||||
}
|
||||
|
||||
Notice::addWhereSinceId($notice, $since_id);
|
||||
Notice::addWhereMaxId($notice, $max_id);
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($notice->find()) {
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function repeatsOfMe($offset=0, $limit=20, $since_id=null, $max_id=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_repeatsOfMeDirect'),
|
||||
array(),
|
||||
'user:repeats_of_me:'.$this->id,
|
||||
$offset, $limit, $since_id, $max_id);
|
||||
$stream = new RepeatsOfMeNoticeStream($this);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
function _repeatsOfMeDirect($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$qry =
|
||||
'SELECT DISTINCT original.id AS id ' .
|
||||
'FROM notice original JOIN notice rept ON original.id = rept.repeat_of ' .
|
||||
'WHERE original.profile_id = ' . $this->id . ' ';
|
||||
|
||||
$since = Notice::whereSinceId($since_id, 'original.id', 'original.created');
|
||||
if ($since) {
|
||||
$qry .= "AND ($since) ";
|
||||
}
|
||||
|
||||
$max = Notice::whereMaxId($max_id, 'original.id', 'original.created');
|
||||
if ($max) {
|
||||
$qry .= "AND ($max) ";
|
||||
}
|
||||
|
||||
$qry .= 'ORDER BY original.created, original.id DESC ';
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$qry .= "LIMIT $limit OFFSET $offset";
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->query($qry);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
|
||||
{
|
||||
@ -1034,5 +965,4 @@ class User extends Memcached_DataObject
|
||||
|
||||
return $apps;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -87,42 +87,11 @@ class User_group extends Memcached_DataObject
|
||||
|
||||
function getNotices($offset, $limit, $since_id=null, $max_id=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_streamDirect'),
|
||||
array(),
|
||||
'user_group:notice_ids:' . $this->id,
|
||||
$offset, $limit, $since_id, $max_id);
|
||||
$stream = new GroupNoticeStream($this);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
return $stream->getNotices($offset, $limit, $since_id, $max_id);
|
||||
}
|
||||
|
||||
function _streamDirect($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$inbox = new Group_inbox();
|
||||
|
||||
$inbox->group_id = $this->id;
|
||||
|
||||
$inbox->selectAdd();
|
||||
$inbox->selectAdd('notice_id');
|
||||
|
||||
Notice::addWhereSinceId($inbox, $since_id, 'notice_id');
|
||||
Notice::addWhereMaxId($inbox, $max_id, 'notice_id');
|
||||
|
||||
$inbox->orderBy('created DESC, notice_id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$inbox->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($inbox->find()) {
|
||||
while ($inbox->fetch()) {
|
||||
$ids[] = $inbox->notice_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function allowedNickname($nickname)
|
||||
{
|
||||
@ -306,11 +275,11 @@ class User_group extends Memcached_DataObject
|
||||
|
||||
$oldaliases = $this->getAliases();
|
||||
|
||||
# Delete stuff that's old that not in new
|
||||
// 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
|
||||
// Insert stuff that's in new and not in old
|
||||
|
||||
$to_insert = array_diff($newaliases, $oldaliases);
|
||||
|
||||
|
@ -337,6 +337,7 @@ location_id = 1
|
||||
location_ns = 1
|
||||
repeat_of = 1
|
||||
object_type = 2
|
||||
scope = 1
|
||||
|
||||
[notice__keys]
|
||||
id = N
|
||||
@ -627,6 +628,7 @@ smsreplies = 17
|
||||
smsemail = 2
|
||||
uri = 2
|
||||
autosubscribe = 17
|
||||
subscribe_policy = 17
|
||||
urlshorteningservice = 2
|
||||
inboxed = 17
|
||||
design_id = 1
|
||||
|
@ -118,6 +118,7 @@ $schema['user'] = array(
|
||||
'smsemail' => array('type' => 'varchar', 'length' => 255, 'description' => 'built from sms and carrier'),
|
||||
'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier, usually a tag URI'),
|
||||
'autosubscribe' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'automatically subscribe to users who subscribe to us'),
|
||||
'subscribe_policy' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => '0 = anybody can subscribe; 1 = require approval'),
|
||||
'urlshorteningservice' => array('type' => 'varchar', 'length' => 50, 'default' => 'internal', 'description' => 'service to use for auto-shortening URLs'),
|
||||
'inboxed' => array('type' => 'int', 'size' => 'tiny', 'default' => 0, 'description' => 'has an inbox been created for this user?'),
|
||||
'design_id' => array('type' => 'int', 'description' => 'id of a design'),
|
||||
@ -202,6 +203,9 @@ $schema['notice'] = array(
|
||||
'location_ns' => array('type' => 'int', 'description' => 'namespace for location'),
|
||||
'repeat_of' => array('type' => 'int', 'description' => 'notice this is a repeat of'),
|
||||
'object_type' => array('type' => 'varchar', 'length' => 255, 'description' => 'URI representing activity streams object type', 'default' => 'http://activitystrea.ms/schema/1.0/note'),
|
||||
'scope' => array('type' => 'int',
|
||||
'default' => '1',
|
||||
'description' => 'bit map for distribution scope; 0 = everywhere; 1 = this server only; 2 = addressees; 4 = followers'),
|
||||
),
|
||||
'primary key' => array('id'),
|
||||
'unique keys' => array(
|
||||
@ -1099,3 +1103,5 @@ $schema['schema_version'] = array(
|
||||
);
|
||||
|
||||
$schema['group_join_queue'] = Group_join_queue::schemaDef();
|
||||
|
||||
$schema['subscription_queue'] = Subscription_queue::schemaDef();
|
||||
|
@ -1,32 +1,40 @@
|
||||
<?php
|
||||
/* vim: set expandtab tabstop=4 shiftwidth=4: */
|
||||
// +----------------------------------------------------------------------+
|
||||
// | PHP Version 5 |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Copyright (c) 1997-2004 The PHP Group |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | This source file is subject to version 3.0 of the PHP license, |
|
||||
// | that is bundled with this package in the file LICENSE, and is |
|
||||
// | available through the world-wide-web at the following url: |
|
||||
// | http://www.php.net/license/3_0.txt. |
|
||||
// | If you did not receive a copy of the PHP license and are unable to |
|
||||
// | obtain it through the world-wide-web, please send a note to |
|
||||
// | license@php.net so we can mail you a copy immediately. |
|
||||
// +----------------------------------------------------------------------+
|
||||
// | Author: Andrei Zmievski <andrei@php.net> |
|
||||
// +----------------------------------------------------------------------+
|
||||
//
|
||||
// $Id: Getopt.php,v 1.4 2007/06/12 14:58:56 cellog Exp $
|
||||
/**
|
||||
* PHP Version 5
|
||||
*
|
||||
* Copyright (c) 1997-2004 The PHP Group
|
||||
*
|
||||
* This source file is subject to version 3.0 of the PHP license,
|
||||
* that is bundled with this package in the file LICENSE, and is
|
||||
* available through the world-wide-web at the following url:
|
||||
* http://www.php.net/license/3_0.txt.
|
||||
* If you did not receive a copy of the PHP license and are unable to
|
||||
* obtain it through the world-wide-web, please send a note to
|
||||
* license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category Console
|
||||
* @package Console_Getopt
|
||||
* @author Andrei Zmievski <andrei@php.net>
|
||||
* @license http://www.php.net/license/3_0.txt PHP 3.0
|
||||
* @version CVS: $Id: Getopt.php 306067 2010-12-08 00:13:31Z dufuz $
|
||||
* @link http://pear.php.net/package/Console_Getopt
|
||||
*/
|
||||
|
||||
require_once 'PEAR.php';
|
||||
|
||||
/**
|
||||
* Command-line options parsing class.
|
||||
*
|
||||
* @category Console
|
||||
* @package Console_Getopt
|
||||
* @author Andrei Zmievski <andrei@php.net>
|
||||
*
|
||||
* @license http://www.php.net/license/3_0.txt PHP 3.0
|
||||
* @link http://pear.php.net/package/Console_Getopt
|
||||
*/
|
||||
class Console_Getopt {
|
||||
class Console_Getopt
|
||||
{
|
||||
|
||||
/**
|
||||
* Parses the command-line options.
|
||||
*
|
||||
@ -56,42 +64,57 @@ class Console_Getopt {
|
||||
* @param array $args an array of command-line arguments
|
||||
* @param string $short_options specifies the list of allowed short options
|
||||
* @param array $long_options specifies the list of allowed long options
|
||||
* @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
|
||||
*
|
||||
* @return array two-element array containing the list of parsed options and
|
||||
* the non-option arguments
|
||||
*
|
||||
* @access public
|
||||
*
|
||||
*/
|
||||
function getopt2($args, $short_options, $long_options = null)
|
||||
function getopt2($args, $short_options, $long_options = null, $skip_unknown = false)
|
||||
{
|
||||
return Console_Getopt::doGetopt(2, $args, $short_options, $long_options);
|
||||
return Console_Getopt::doGetopt(2, $args, $short_options, $long_options, $skip_unknown);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function expects $args to start with the script name (POSIX-style).
|
||||
* Preserved for backwards compatibility.
|
||||
*
|
||||
* @param array $args an array of command-line arguments
|
||||
* @param string $short_options specifies the list of allowed short options
|
||||
* @param array $long_options specifies the list of allowed long options
|
||||
*
|
||||
* @see getopt2()
|
||||
* @return array two-element array containing the list of parsed options and
|
||||
* the non-option arguments
|
||||
*/
|
||||
function getopt($args, $short_options, $long_options = null)
|
||||
function getopt($args, $short_options, $long_options = null, $skip_unknown = false)
|
||||
{
|
||||
return Console_Getopt::doGetopt(1, $args, $short_options, $long_options);
|
||||
return Console_Getopt::doGetopt(1, $args, $short_options, $long_options, $skip_unknown);
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual implementation of the argument parsing code.
|
||||
*
|
||||
* @param int $version Version to use
|
||||
* @param array $args an array of command-line arguments
|
||||
* @param string $short_options specifies the list of allowed short options
|
||||
* @param array $long_options specifies the list of allowed long options
|
||||
* @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function doGetopt($version, $args, $short_options, $long_options = null)
|
||||
function doGetopt($version, $args, $short_options, $long_options = null, $skip_unknown = false)
|
||||
{
|
||||
// in case you pass directly readPHPArgv() as the first arg
|
||||
if (PEAR::isError($args)) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
if (empty($args)) {
|
||||
return array(array(), array());
|
||||
}
|
||||
$opts = array();
|
||||
$non_opts = array();
|
||||
|
||||
$non_opts = $opts = array();
|
||||
|
||||
settype($args, 'array');
|
||||
|
||||
@ -111,7 +134,6 @@ class Console_Getopt {
|
||||
|
||||
reset($args);
|
||||
while (list($i, $arg) = each($args)) {
|
||||
|
||||
/* The special element '--' means explicit end of
|
||||
options. Treat the rest of the arguments as non-options
|
||||
and end the loop. */
|
||||
@ -124,37 +146,59 @@ class Console_Getopt {
|
||||
$non_opts = array_merge($non_opts, array_slice($args, $i));
|
||||
break;
|
||||
} elseif (strlen($arg) > 1 && $arg{1} == '-') {
|
||||
$error = Console_Getopt::_parseLongOption(substr($arg, 2), $long_options, $opts, $args);
|
||||
if (PEAR::isError($error))
|
||||
$error = Console_Getopt::_parseLongOption(substr($arg, 2),
|
||||
$long_options,
|
||||
$opts,
|
||||
$args,
|
||||
$skip_unknown);
|
||||
if (PEAR::isError($error)) {
|
||||
return $error;
|
||||
}
|
||||
} elseif ($arg == '-') {
|
||||
// - is stdin
|
||||
$non_opts = array_merge($non_opts, array_slice($args, $i));
|
||||
break;
|
||||
} else {
|
||||
$error = Console_Getopt::_parseShortOption(substr($arg, 1), $short_options, $opts, $args);
|
||||
if (PEAR::isError($error))
|
||||
$error = Console_Getopt::_parseShortOption(substr($arg, 1),
|
||||
$short_options,
|
||||
$opts,
|
||||
$args,
|
||||
$skip_unknown);
|
||||
if (PEAR::isError($error)) {
|
||||
return $error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($opts, $non_opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
* Parse short option
|
||||
*
|
||||
* @param string $arg Argument
|
||||
* @param string[] $short_options Available short options
|
||||
* @param string[][] &$opts
|
||||
* @param string[] &$args
|
||||
* @param boolean $skip_unknown suppresses Console_Getopt: unrecognized option
|
||||
*
|
||||
* @access private
|
||||
* @return void
|
||||
*/
|
||||
function _parseShortOption($arg, $short_options, &$opts, &$args)
|
||||
function _parseShortOption($arg, $short_options, &$opts, &$args, $skip_unknown)
|
||||
{
|
||||
for ($i = 0; $i < strlen($arg); $i++) {
|
||||
$opt = $arg{$i};
|
||||
$opt_arg = null;
|
||||
|
||||
/* Try to find the short option in the specifier string. */
|
||||
if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':')
|
||||
{
|
||||
return PEAR::raiseError("Console_Getopt: unrecognized option -- $opt");
|
||||
if (($spec = strstr($short_options, $opt)) === false || $arg{$i} == ':') {
|
||||
if ($skip_unknown === true) {
|
||||
break;
|
||||
}
|
||||
|
||||
$msg = "Console_Getopt: unrecognized option -- $opt";
|
||||
return PEAR::raiseError($msg);
|
||||
}
|
||||
|
||||
if (strlen($spec) > 1 && $spec{1} == ':') {
|
||||
@ -173,11 +217,14 @@ class Console_Getopt {
|
||||
break;
|
||||
} else if (list(, $opt_arg) = each($args)) {
|
||||
/* Else use the next argument. */;
|
||||
if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
|
||||
return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
|
||||
if (Console_Getopt::_isShortOpt($opt_arg)
|
||||
|| Console_Getopt::_isLongOpt($opt_arg)) {
|
||||
$msg = "option requires an argument --$opt";
|
||||
return PEAR::raiseError("Console_Getopt:" . $msg);
|
||||
}
|
||||
} else {
|
||||
return PEAR::raiseError("Console_Getopt: option requires an argument -- $opt");
|
||||
$msg = "option requires an argument --$opt";
|
||||
return PEAR::raiseError("Console_Getopt:" . $msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -187,17 +234,26 @@ class Console_Getopt {
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
* Checks if an argument is a short option
|
||||
*
|
||||
* @param string $arg Argument to check
|
||||
*
|
||||
* @access private
|
||||
* @return bool
|
||||
*/
|
||||
function _isShortOpt($arg)
|
||||
{
|
||||
return strlen($arg) == 2 && $arg[0] == '-' && preg_match('/[a-zA-Z]/', $arg[1]);
|
||||
return strlen($arg) == 2 && $arg[0] == '-'
|
||||
&& preg_match('/[a-zA-Z]/', $arg[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
* Checks if an argument is a long option
|
||||
*
|
||||
* @param string $arg Argument to check
|
||||
*
|
||||
* @access private
|
||||
* @return bool
|
||||
*/
|
||||
function _isLongOpt($arg)
|
||||
{
|
||||
@ -206,17 +262,26 @@ class Console_Getopt {
|
||||
}
|
||||
|
||||
/**
|
||||
* @access private
|
||||
* Parse long option
|
||||
*
|
||||
* @param string $arg Argument
|
||||
* @param string[] $long_options Available long options
|
||||
* @param string[][] &$opts
|
||||
* @param string[] &$args
|
||||
*
|
||||
* @access private
|
||||
* @return void|PEAR_Error
|
||||
*/
|
||||
function _parseLongOption($arg, $long_options, &$opts, &$args)
|
||||
function _parseLongOption($arg, $long_options, &$opts, &$args, $skip_unknown)
|
||||
{
|
||||
@list($opt, $opt_arg) = explode('=', $arg, 2);
|
||||
|
||||
$opt_len = strlen($opt);
|
||||
|
||||
for ($i = 0; $i < count($long_options); $i++) {
|
||||
$long_opt = $long_options[$i];
|
||||
$opt_start = substr($long_opt, 0, $opt_len);
|
||||
|
||||
$long_opt_name = str_replace('=', '', $long_opt);
|
||||
|
||||
/* Option doesn't match. Go on to the next one. */
|
||||
@ -233,12 +298,15 @@ class Console_Getopt {
|
||||
} else {
|
||||
$next_option_rest = '';
|
||||
}
|
||||
|
||||
if ($opt_rest != '' && $opt{0} != '=' &&
|
||||
$i + 1 < count($long_options) &&
|
||||
$opt == substr($long_options[$i+1], 0, $opt_len) &&
|
||||
$next_option_rest != '' &&
|
||||
$next_option_rest{0} != '=') {
|
||||
return PEAR::raiseError("Console_Getopt: option --$opt is ambiguous");
|
||||
|
||||
$msg = "Console_Getopt: option --$opt is ambiguous";
|
||||
return PEAR::raiseError($msg);
|
||||
}
|
||||
|
||||
if (substr($long_opt, -1) == '=') {
|
||||
@ -246,20 +314,29 @@ class Console_Getopt {
|
||||
/* Long option requires an argument.
|
||||
Take the next argument if one wasn't specified. */;
|
||||
if (!strlen($opt_arg) && !(list(, $opt_arg) = each($args))) {
|
||||
return PEAR::raiseError("Console_Getopt: option --$opt requires an argument");
|
||||
$msg = "Console_Getopt: option requires an argument --$opt";
|
||||
return PEAR::raiseError($msg);
|
||||
}
|
||||
if (Console_Getopt::_isShortOpt($opt_arg) || Console_Getopt::_isLongOpt($opt_arg)) {
|
||||
return PEAR::raiseError("Console_Getopt: option requires an argument --$opt");
|
||||
|
||||
if (Console_Getopt::_isShortOpt($opt_arg)
|
||||
|| Console_Getopt::_isLongOpt($opt_arg)) {
|
||||
$msg = "Console_Getopt: option requires an argument --$opt";
|
||||
return PEAR::raiseError($msg);
|
||||
}
|
||||
}
|
||||
} else if ($opt_arg) {
|
||||
return PEAR::raiseError("Console_Getopt: option --$opt doesn't allow an argument");
|
||||
$msg = "Console_Getopt: option --$opt doesn't allow an argument";
|
||||
return PEAR::raiseError($msg);
|
||||
}
|
||||
|
||||
$opts[] = array('--' . $opt, $opt_arg);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($skip_unknown === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
return PEAR::raiseError("Console_Getopt: unrecognized option --$opt");
|
||||
}
|
||||
|
||||
@ -276,7 +353,8 @@ class Console_Getopt {
|
||||
if (!is_array($argv)) {
|
||||
if (!@is_array($_SERVER['argv'])) {
|
||||
if (!@is_array($GLOBALS['HTTP_SERVER_VARS']['argv'])) {
|
||||
return PEAR::raiseError("Console_Getopt: Could not read cmd args (register_argc_argv=Off?)");
|
||||
$msg = "Could not read cmd args (register_argc_argv=Off?)";
|
||||
return PEAR::raiseError("Console_Getopt: " . $msg);
|
||||
}
|
||||
return $GLOBALS['HTTP_SERVER_VARS']['argv'];
|
||||
}
|
||||
@ -286,5 +364,3 @@ class Console_Getopt {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -15,7 +15,7 @@
|
||||
* @author Alan Knowles <alan@akbkhome.com>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
||||
* @version CVS: $Id: DataObject.php 291349 2009-11-27 09:15:18Z alan_k $
|
||||
* @version CVS: $Id: DataObject.php 301030 2010-07-07 02:26:31Z alan_k $
|
||||
* @link http://pear.php.net/package/DB_DataObject
|
||||
*/
|
||||
|
||||
@ -235,7 +235,7 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
var $_DB_DataObject_version = "1.9.0";
|
||||
var $_DB_DataObject_version = "1.9.5";
|
||||
|
||||
/**
|
||||
* The Database table (used by table extends)
|
||||
@ -369,6 +369,32 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* build the basic select query.
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
|
||||
function _build_select()
|
||||
{
|
||||
global $_DB_DATAOBJECT;
|
||||
$quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
|
||||
if ($quoteIdentifiers) {
|
||||
$this->_connect();
|
||||
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
|
||||
}
|
||||
$sql = 'SELECT ' .
|
||||
$this->_query['data_select'] . " \n" .
|
||||
' FROM ' . ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table) . " \n" .
|
||||
$this->_join . " \n" .
|
||||
$this->_query['condition'] . " \n" .
|
||||
$this->_query['group_by'] . " \n" .
|
||||
$this->_query['having'] . " \n";
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* find results, either normal or crosstable
|
||||
*
|
||||
@ -411,20 +437,21 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
$query_before = $this->_query;
|
||||
$this->_build_condition($this->table()) ;
|
||||
|
||||
$quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
|
||||
|
||||
$this->_connect();
|
||||
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
|
||||
|
||||
/* We are checking for method modifyLimitQuery as it is PEAR DB specific */
|
||||
$sql = 'SELECT ' .
|
||||
$this->_query['data_select'] . " \n" .
|
||||
' FROM ' . ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table) . " \n" .
|
||||
$this->_join . " \n" .
|
||||
$this->_query['condition'] . " \n" .
|
||||
$this->_query['group_by'] . " \n" .
|
||||
$this->_query['having'] . " \n" .
|
||||
$this->_query['order_by'] . " \n";
|
||||
|
||||
$sql = $this->_build_select();
|
||||
|
||||
foreach ($this->_query['unions'] as $union_ar) {
|
||||
$sql .= $union_ar[1] . $union_ar[0]->_build_select() . " \n";
|
||||
}
|
||||
|
||||
$sql .= $this->_query['order_by'] . " \n";
|
||||
|
||||
|
||||
/* We are checking for method modifyLimitQuery as it is PEAR DB specific */
|
||||
if ((!isset($_DB_DATAOBJECT['CONFIG']['db_driver'])) ||
|
||||
($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) {
|
||||
/* PEAR DB specific */
|
||||
@ -578,6 +605,85 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fetches all results as an array,
|
||||
*
|
||||
* return format is dependant on args.
|
||||
* if selectAdd() has not been called on the object, then it will add the correct columns to the query.
|
||||
*
|
||||
* A) Array of values (eg. a list of 'id')
|
||||
*
|
||||
* $x = DB_DataObject::factory('mytable');
|
||||
* $x->whereAdd('something = 1')
|
||||
* $ar = $x->fetchAll('id');
|
||||
* -- returns array(1,2,3,4,5)
|
||||
*
|
||||
* B) Array of values (not from table)
|
||||
*
|
||||
* $x = DB_DataObject::factory('mytable');
|
||||
* $x->whereAdd('something = 1');
|
||||
* $x->selectAdd();
|
||||
* $x->selectAdd('distinct(group_id) as group_id');
|
||||
* $ar = $x->fetchAll('group_id');
|
||||
* -- returns array(1,2,3,4,5)
|
||||
* *
|
||||
* C) A key=>value associative array
|
||||
*
|
||||
* $x = DB_DataObject::factory('mytable');
|
||||
* $x->whereAdd('something = 1')
|
||||
* $ar = $x->fetchAll('id','name');
|
||||
* -- returns array(1=>'fred',2=>'blogs',3=> .......
|
||||
*
|
||||
* D) array of objects
|
||||
* $x = DB_DataObject::factory('mytable');
|
||||
* $x->whereAdd('something = 1');
|
||||
* $ar = $x->fetchAll();
|
||||
*
|
||||
* E) array of arrays (for example)
|
||||
* $x = DB_DataObject::factory('mytable');
|
||||
* $x->whereAdd('something = 1');
|
||||
* $ar = $x->fetchAll(false,false,'toArray');
|
||||
*
|
||||
*
|
||||
* @param string|false $k key
|
||||
* @param string|false $v value
|
||||
* @param string|false $method method to call on each result to get array value (eg. 'toArray')
|
||||
* @access public
|
||||
* @return array format dependant on arguments, may be empty
|
||||
*/
|
||||
function fetchAll($k= false, $v = false, $method = false)
|
||||
{
|
||||
// should it even do this!!!?!?
|
||||
if ($k !== false &&
|
||||
( // only do this is we have not been explicit..
|
||||
empty($this->_query['data_select']) ||
|
||||
($this->_query['data_select'] == '*')
|
||||
)
|
||||
) {
|
||||
$this->selectAdd();
|
||||
$this->selectAdd($k);
|
||||
if ($v !== false) {
|
||||
$this->selectAdd($v);
|
||||
}
|
||||
}
|
||||
|
||||
$this->find();
|
||||
$ret = array();
|
||||
while ($this->fetch()) {
|
||||
if ($v !== false) {
|
||||
$ret[$this->$k] = $this->$v;
|
||||
continue;
|
||||
}
|
||||
$ret[] = $k === false ?
|
||||
($method == false ? clone($this) : $this->$method())
|
||||
: $this->$k;
|
||||
}
|
||||
return $ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a condition to the WHERE statement, defaults to AND
|
||||
*
|
||||
@ -622,6 +728,47 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a 'IN' condition to the WHERE statement
|
||||
*
|
||||
* $object->whereAddIn('id', $array, 'int'); //minimal usage
|
||||
* $object->whereAddIn('price', $array, 'float', 'OR'); // cast to float, and call whereAdd with 'OR'
|
||||
* $object->whereAddIn('name', $array, 'string'); // quote strings
|
||||
*
|
||||
* @param string $key key column to match
|
||||
* @param array $list list of values to match
|
||||
* @param string $type string|int|integer|float|bool cast to type.
|
||||
* @param string $logic optional logic to call whereAdd with eg. "OR" (defaults to "AND")
|
||||
* @access public
|
||||
* @return string|PEAR::Error - previous condition or Error when invalid args found
|
||||
*/
|
||||
function whereAddIn($key, $list, $type, $logic = 'AND')
|
||||
{
|
||||
$not = '';
|
||||
if ($key[0] == '!') {
|
||||
$not = 'NOT ';
|
||||
$key = substr($key, 1);
|
||||
}
|
||||
// fix type for short entry.
|
||||
$type = $type == 'int' ? 'integer' : $type;
|
||||
|
||||
if ($type == 'string') {
|
||||
$this->_connect();
|
||||
}
|
||||
|
||||
$ar = array();
|
||||
foreach($list as $k) {
|
||||
settype($k, $type);
|
||||
$ar[] = $type =='string' ? $this->_quote($k) : $k;
|
||||
}
|
||||
if (!$ar) {
|
||||
return $not ? $this->_query['condition'] : $this->whereAdd("1=0");
|
||||
}
|
||||
return $this->whereAdd("$key $not IN (". implode(',', $ar). ')', $logic );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Adds a order by condition
|
||||
*
|
||||
@ -1175,7 +1322,7 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
$seq = $this->sequenceKey();
|
||||
if ($seq[0] !== false) {
|
||||
$keys = array($seq[0]);
|
||||
if (empty($this->{$keys[0]}) && $dataObject !== true) {
|
||||
if (!isset($this->{$keys[0]}) && $dataObject !== true) {
|
||||
$this->raiseError("update: trying to perform an update without
|
||||
the key set, and argument to update is not
|
||||
DB_DATAOBJECT_WHEREADD_ONLY
|
||||
@ -1670,6 +1817,7 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
'limit_start' => '', // the LIMIT condition
|
||||
'limit_count' => '', // the LIMIT condition
|
||||
'data_select' => '*', // the columns to be SELECTed
|
||||
'unions' => array(), // the added unions
|
||||
);
|
||||
|
||||
|
||||
@ -2032,9 +2180,9 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
$seqname = false;
|
||||
|
||||
if (!empty($_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table])) {
|
||||
$usekey = $_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table];
|
||||
if (strpos($usekey,':') !== false) {
|
||||
list($usekey,$seqname) = explode(':',$usekey);
|
||||
$seqname = $_DB_DATAOBJECT['CONFIG']['sequence_'.$this->__table];
|
||||
if (strpos($seqname,':') !== false) {
|
||||
list($usekey,$seqname) = explode(':',$seqname);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3068,9 +3216,9 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
}
|
||||
|
||||
/**
|
||||
* IS THIS SUPPORTED/USED ANYMORE????
|
||||
*return a list of options for a linked table
|
||||
*
|
||||
* getLinkArray
|
||||
* Fetch an array of related objects. This should be used in conjunction with a <dbname>.links.ini file configuration (see the introduction on linking for details on this).
|
||||
* You may also use this with all parameters to specify, the column and related table.
|
||||
* This is highly dependant on naming columns 'correctly' :)
|
||||
* using colname = xxxxx_yyyyyy
|
||||
* xxxxxx = related table; (yyyyy = user defined..)
|
||||
@ -3078,7 +3226,21 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
* stores it in $this->_xxxxx_yyyyy
|
||||
*
|
||||
* @access public
|
||||
* @return array of results (empty array on failure)
|
||||
* @param string $column - either column or column.xxxxx
|
||||
* @param string $table - name of table to look up value in
|
||||
* @return array - array of results (empty array on failure)
|
||||
*
|
||||
* Example - Getting the related objects
|
||||
*
|
||||
* $person = new DataObjects_Person;
|
||||
* $person->get(12);
|
||||
* $children = $person->getLinkArray('children');
|
||||
*
|
||||
* echo 'There are ', count($children), ' descendant(s):<br />';
|
||||
* foreach ($children as $child) {
|
||||
* echo $child->name, '<br />';
|
||||
* }
|
||||
*
|
||||
*/
|
||||
function &getLinkArray($row, $table = null)
|
||||
{
|
||||
@ -3123,6 +3285,46 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* unionAdd - adds another dataobject to this, building a unioned query.
|
||||
*
|
||||
* usage:
|
||||
* $doTable1 = DB_DataObject::factory("table1");
|
||||
* $doTable2 = DB_DataObject::factory("table2");
|
||||
*
|
||||
* $doTable1->selectAdd();
|
||||
* $doTable1->selectAdd("col1,col2");
|
||||
* $doTable1->whereAdd("col1 > 100");
|
||||
* $doTable1->orderBy("col1");
|
||||
*
|
||||
* $doTable2->selectAdd();
|
||||
* $doTable2->selectAdd("col1, col2");
|
||||
* $doTable2->whereAdd("col2 = 'v'");
|
||||
*
|
||||
* $doTable1->unionAdd($doTable2);
|
||||
* $doTable1->find();
|
||||
*
|
||||
* Note: this model may be a better way to implement joinAdd?, eg. do the building in find?
|
||||
*
|
||||
*
|
||||
* @param $obj object|false the union object or false to reset
|
||||
* @param optional $is_all string 'ALL' to do all.
|
||||
* @returns $obj object|array the added object, or old list if reset.
|
||||
*/
|
||||
|
||||
function unionAdd($obj,$is_all= '')
|
||||
{
|
||||
if ($obj === false) {
|
||||
$ret = $this->_query['unions'];
|
||||
$this->_query['unions'] = array();
|
||||
return $ret;
|
||||
}
|
||||
$this->_query['unions'][] = array($obj, 'UNION ' . $is_all . ' ') ;
|
||||
return $obj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The JOIN condition
|
||||
*
|
||||
@ -3248,7 +3450,19 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
/* otherwise see if there are any links from this table to the obj. */
|
||||
//print_r($this->links());
|
||||
if (($ofield === false) && ($links = $this->links())) {
|
||||
foreach ($links as $k => $v) {
|
||||
// this enables for support for arrays of links in ini file.
|
||||
// link contains this_column[] = linked_table:linked_column
|
||||
// or standard way.
|
||||
// link contains this_column = linked_table:linked_column
|
||||
foreach ($links as $k => $linkVar) {
|
||||
|
||||
if (!is_array($linkVar)) {
|
||||
$linkVar = array($linkVar);
|
||||
}
|
||||
foreach($linkVar as $v) {
|
||||
|
||||
|
||||
|
||||
/* link contains {this column} = {linked table}:{linked column} */
|
||||
$ar = explode(':', $v);
|
||||
// Feature Request #4266 - Allow joins with multiple keys
|
||||
@ -3259,20 +3473,23 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
$ar[1] = explode(',', $ar[1]);
|
||||
}
|
||||
|
||||
if ($ar[0] == $obj->__table) {
|
||||
if ($joinCol !== false) {
|
||||
if ($k == $joinCol) {
|
||||
$tfield = $k;
|
||||
$ofield = $ar[1];
|
||||
break;
|
||||
} else {
|
||||
if ($ar[0] != $obj->__table) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if ($joinCol !== false) {
|
||||
if ($k == $joinCol) {
|
||||
// got it!?
|
||||
$tfield = $k;
|
||||
$ofield = $ar[1];
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
|
||||
}
|
||||
$tfield = $k;
|
||||
$ofield = $ar[1];
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3280,12 +3497,17 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
//print_r($obj->links());
|
||||
if (!$ofield && ($olinks = $obj->links())) {
|
||||
|
||||
foreach ($olinks as $k => $v) {
|
||||
foreach ($olinks as $k => $linkVar) {
|
||||
/* link contains {this column} = array ( {linked table}:{linked column} )*/
|
||||
if (!is_array($linkVar)) {
|
||||
$linkVar = array($linkVar);
|
||||
}
|
||||
foreach($linkVar as $v) {
|
||||
|
||||
/* link contains {this column} = {linked table}:{linked column} */
|
||||
$ar = explode(':', $v);
|
||||
|
||||
// Feature Request #4266 - Allow joins with multiple keys
|
||||
|
||||
$links_key_array = strpos($k,',');
|
||||
if ($links_key_array !== false) {
|
||||
$k = explode(',', $k);
|
||||
@ -3296,7 +3518,9 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
$ar[1] = explode(',', $ar[1]);
|
||||
}
|
||||
|
||||
if ($ar[0] == $this->__table) {
|
||||
if ($ar[0] != $this->__table) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// you have explictly specified the column
|
||||
// and the col is listed here..
|
||||
@ -3315,6 +3539,7 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
$ofield = $k;
|
||||
$tfield = $ar[1];
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3573,7 +3798,14 @@ class DB_DataObject extends DB_DataObject_Overload
|
||||
if (!$k) {
|
||||
continue; // ignore empty keys!!! what
|
||||
}
|
||||
if (is_object($from) && isset($from->{sprintf($format,$k)})) {
|
||||
|
||||
$chk = is_object($from) &&
|
||||
(version_compare(phpversion(), "5.1.0" , ">=") ?
|
||||
property_exists($from, sprintf($format,$k)) : // php5.1
|
||||
array_key_exists( sprintf($format,$k), get_class_vars($from)) //older
|
||||
);
|
||||
// if from has property ($format($k)
|
||||
if ($chk) {
|
||||
$kk = (strtolower($k) == 'from') ? '_from' : $k;
|
||||
if (method_exists($this,'set'.$kk)) {
|
||||
$ret = $this->{'set'.$kk}($from->{sprintf($format,$k)});
|
||||
|
@ -15,7 +15,7 @@
|
||||
* @author Alan Knowles <alan@akbkhome.com>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://www.php.net/license/3_01.txt PHP License 3.01
|
||||
* @version CVS: $Id: Generator.php 289384 2009-10-09 00:17:26Z alan_k $
|
||||
* @version CVS: $Id: Generator.php 298560 2010-04-25 23:01:51Z alan_k $
|
||||
* @link http://pear.php.net/package/DB_DataObject
|
||||
*/
|
||||
|
||||
@ -383,8 +383,8 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
return false;
|
||||
}
|
||||
$__DB = &$GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'][$this->_database_dsn_md5];
|
||||
if (!in_array($__DB->phptype, array('mysql','mysqli'))) {
|
||||
echo "WARNING: cant handle non-mysql introspection for defaults.";
|
||||
if (!in_array($__DB->phptype, array('mysql', 'mysqli', 'pgsql'))) {
|
||||
echo "WARNING: cant handle non-mysql and pgsql introspection for defaults.";
|
||||
return; // cant handle non-mysql introspection for defaults.
|
||||
}
|
||||
|
||||
@ -392,6 +392,44 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
|
||||
$fk = array();
|
||||
|
||||
|
||||
switch ($DB->phptype) {
|
||||
|
||||
|
||||
case 'pgsql':
|
||||
foreach($this->tables as $this->table) {
|
||||
$quotedTable = !empty($options['quote_identifiers_tableinfo']) ? $DB->quoteIdentifier($table) : $this->table;
|
||||
$res =& $DB->query("SELECT
|
||||
pg_catalog.pg_get_constraintdef(r.oid, true) AS condef
|
||||
FROM pg_catalog.pg_constraint r,
|
||||
pg_catalog.pg_class c
|
||||
WHERE c.oid=r.conrelid
|
||||
AND r.contype = 'f'
|
||||
AND c.relname = '" . $quotedTable . "'");
|
||||
if (PEAR::isError($res)) {
|
||||
die($res->getMessage());
|
||||
}
|
||||
|
||||
while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
|
||||
$treffer = array();
|
||||
// this only picks up one of these.. see this for why: http://pear.php.net/bugs/bug.php?id=17049
|
||||
preg_match(
|
||||
"/FOREIGN KEY \((\w*)\) REFERENCES (\w*)\((\w*)\)/i",
|
||||
$row['condef'],
|
||||
$treffer);
|
||||
if (!count($treffer)) {
|
||||
continue;
|
||||
}
|
||||
$fk[$this->table][$treffer[1]] = $treffer[2] . ":" . $treffer[3];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 'mysql':
|
||||
case 'mysqli':
|
||||
default:
|
||||
|
||||
foreach($this->tables as $this->table) {
|
||||
$quotedTable = !empty($options['quote_identifiers_tableinfo']) ? $DB->quoteIdentifier($table) : $this->table;
|
||||
|
||||
@ -410,15 +448,16 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
$treffer,
|
||||
PREG_SET_ORDER);
|
||||
|
||||
if (count($treffer) < 1) {
|
||||
if (!count($treffer)) {
|
||||
continue;
|
||||
}
|
||||
for ($i = 0; $i < count($treffer); $i++) {
|
||||
$fk[$this->table][$treffer[$i][1]] = $treffer[$i][2] . ":" . $treffer[$i][3];
|
||||
foreach($treffer as $i=> $tref) {
|
||||
$fk[$this->table][$tref[1]] = $tref[2] . ":" . $tref[3];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
$links_ini = "";
|
||||
|
||||
foreach($fk as $table => $details) {
|
||||
@ -861,10 +900,8 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
$body = "\n ###START_AUTOCODE\n";
|
||||
$body .= " /* the code below is auto generated do not remove the above tag */\n\n";
|
||||
// table
|
||||
$padding = (30 - strlen($this->table));
|
||||
$padding = ($padding < 2) ? 2 : $padding;
|
||||
|
||||
$p = str_repeat(' ',$padding) ;
|
||||
$p = str_repeat(' ',max(2, (18 - strlen($this->table)))) ;
|
||||
|
||||
$options = &PEAR::getStaticProperty('DB_DataObject','options');
|
||||
|
||||
@ -887,6 +924,7 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
// Only include the $_database property if the omit_database_var is unset or false
|
||||
|
||||
if (isset($options["database_{$this->_database}"]) && empty($GLOBALS['_DB_DATAOBJECT']['CONFIG']['generator_omit_database_var'])) {
|
||||
$p = str_repeat(' ', max(2, (16 - strlen($this->table))));
|
||||
$body .= " {$var} \$_database = '{$this->_database}'; {$p}// database name (used with database_{*} config)\n";
|
||||
}
|
||||
|
||||
@ -900,6 +938,7 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
// show nice information!
|
||||
$connections = array();
|
||||
$sets = array();
|
||||
|
||||
foreach($defs as $t) {
|
||||
if (!strlen(trim($t->name))) {
|
||||
continue;
|
||||
@ -915,10 +954,7 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$padding = (30 - strlen($t->name));
|
||||
if ($padding < 2) $padding =2;
|
||||
$p = str_repeat(' ',$padding) ;
|
||||
$p = str_repeat(' ',max(2, (30 - strlen($t->name))));
|
||||
|
||||
$length = empty($t->len) ? '' : '('.$t->len.')';
|
||||
$body .=" {$var} \${$t->name}; {$p}// {$t->type}$length {$t->flags}\n";
|
||||
@ -926,9 +962,11 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
// can not do set as PEAR::DB table info doesnt support it.
|
||||
//if (substr($t->Type,0,3) == "set")
|
||||
// $sets[$t->Field] = "array".substr($t->Type,3);
|
||||
$body .= $this->derivedHookVar($t,$padding);
|
||||
$body .= $this->derivedHookVar($t,strlen($p));
|
||||
}
|
||||
|
||||
$body .= $this->derivedHookPostVar($defs);
|
||||
|
||||
// THIS IS TOTALLY BORKED old FC creation
|
||||
// IT WILL BE REMOVED!!!!! in DataObjects 1.6
|
||||
// grep -r __clone * to find all it's uses
|
||||
@ -1078,7 +1116,21 @@ class DB_DataObject_Generator extends DB_DataObject
|
||||
// It MUST NOT be changed here!!!
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* hook for after var lines (
|
||||
* called at the end of the output of var line have generated, override to add extra var
|
||||
* lines
|
||||
*
|
||||
* @param array cols containing array of objects with type,len,flags etc. from tableInfo call
|
||||
* @access public
|
||||
* @return string added to class eg. functions.
|
||||
*/
|
||||
function derivedHookPostVar($t)
|
||||
{
|
||||
// This is so derived generator classes can generate variabels
|
||||
// It MUST NOT be changed here!!!
|
||||
return "";
|
||||
}
|
||||
/**
|
||||
* hook to add extra page-level (in terms of phpDocumentor) DocBlock
|
||||
*
|
||||
|
261
extlib/PEAR.php
261
extlib/PEAR.php
@ -6,21 +6,15 @@
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category pear
|
||||
* @package PEAR
|
||||
* @author Sterling Hughes <sterling@php.net>
|
||||
* @author Stig Bakken <ssb@php.net>
|
||||
* @author Tomas V.V.Cox <cox@idecnet.com>
|
||||
* @author Greg Beaver <cellog@php.net>
|
||||
* @copyright 1997-2008 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id: PEAR.php,v 1.104 2008/01/03 20:26:34 cellog Exp $
|
||||
* @copyright 1997-2010 The Authors
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: PEAR.php 307683 2011-01-23 21:56:12Z dufuz $
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since File available since Release 0.1
|
||||
*/
|
||||
@ -52,15 +46,6 @@ if (substr(PHP_OS, 0, 3) == 'WIN') {
|
||||
define('PEAR_OS', 'Unix'); // blatant assumption
|
||||
}
|
||||
|
||||
// instant backwards compatibility
|
||||
if (!defined('PATH_SEPARATOR')) {
|
||||
if (OS_WINDOWS) {
|
||||
define('PATH_SEPARATOR', ';');
|
||||
} else {
|
||||
define('PATH_SEPARATOR', ':');
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['_PEAR_default_error_mode'] = PEAR_ERROR_RETURN;
|
||||
$GLOBALS['_PEAR_default_error_options'] = E_USER_NOTICE;
|
||||
$GLOBALS['_PEAR_destructor_object_list'] = array();
|
||||
@ -92,8 +77,8 @@ $GLOBALS['_PEAR_error_handler_stack'] = array();
|
||||
* @author Tomas V.V. Cox <cox@idecnet.com>
|
||||
* @author Greg Beaver <cellog@php.net>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.7.2
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @see PEAR_Error
|
||||
* @since Class available since PHP 4.0.2
|
||||
@ -101,8 +86,6 @@ $GLOBALS['_PEAR_error_handler_stack'] = array();
|
||||
*/
|
||||
class PEAR
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
/**
|
||||
* Whether to enable internal debug messages.
|
||||
*
|
||||
@ -153,10 +136,6 @@ class PEAR
|
||||
*/
|
||||
var $_expected_errors = array();
|
||||
|
||||
// }}}
|
||||
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* Constructor. Registers this object in
|
||||
* $_PEAR_destructor_object_list for destructor emulation if a
|
||||
@ -173,9 +152,11 @@ class PEAR
|
||||
if ($this->_debug) {
|
||||
print "PEAR constructor called, class=$classname\n";
|
||||
}
|
||||
|
||||
if ($error_class !== null) {
|
||||
$this->_error_class = $error_class;
|
||||
}
|
||||
|
||||
while ($classname && strcasecmp($classname, "pear")) {
|
||||
$destructor = "_$classname";
|
||||
if (method_exists($this, $destructor)) {
|
||||
@ -192,9 +173,6 @@ class PEAR
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ destructor
|
||||
|
||||
/**
|
||||
* Destructor (the emulated type of...). Does nothing right now,
|
||||
* but is included for forward compatibility, so subclass
|
||||
@ -212,9 +190,6 @@ class PEAR
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getStaticProperty()
|
||||
|
||||
/**
|
||||
* If you have a class that's mostly/entirely static, and you need static
|
||||
* properties, you can use this method to simulate them. Eg. in your method(s)
|
||||
@ -233,15 +208,14 @@ class PEAR
|
||||
if (!isset($properties[$class])) {
|
||||
$properties[$class] = array();
|
||||
}
|
||||
|
||||
if (!array_key_exists($var, $properties[$class])) {
|
||||
$properties[$class][$var] = null;
|
||||
}
|
||||
|
||||
return $properties[$class][$var];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ registerShutdownFunc()
|
||||
|
||||
/**
|
||||
* Use this function to register a shutdown method for static
|
||||
* classes.
|
||||
@ -262,9 +236,6 @@ class PEAR
|
||||
$GLOBALS['_PEAR_shutdown_funcs'][] = array($func, $args);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ isError()
|
||||
|
||||
/**
|
||||
* Tell whether a value is a PEAR error.
|
||||
*
|
||||
@ -278,20 +249,18 @@ class PEAR
|
||||
*/
|
||||
function isError($data, $code = null)
|
||||
{
|
||||
if (is_a($data, 'PEAR_Error')) {
|
||||
if (!is_a($data, 'PEAR_Error')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_null($code)) {
|
||||
return true;
|
||||
} elseif (is_string($code)) {
|
||||
return $data->getMessage() == $code;
|
||||
} else {
|
||||
return $data->getCode() == $code;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ setErrorHandling()
|
||||
return $data->getCode() == $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets how errors generated by this object should be handled.
|
||||
@ -331,7 +300,6 @@ class PEAR
|
||||
*
|
||||
* @since PHP 4.0.5
|
||||
*/
|
||||
|
||||
function setErrorHandling($mode = null, $options = null)
|
||||
{
|
||||
if (isset($this) && is_a($this, 'PEAR')) {
|
||||
@ -369,9 +337,6 @@ class PEAR
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ expectError()
|
||||
|
||||
/**
|
||||
* This method is used to tell which errors you expect to get.
|
||||
* Expected errors are always returned with error mode
|
||||
@ -394,12 +359,9 @@ class PEAR
|
||||
} else {
|
||||
array_push($this->_expected_errors, array($code));
|
||||
}
|
||||
return sizeof($this->_expected_errors);
|
||||
return count($this->_expected_errors);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ popExpect()
|
||||
|
||||
/**
|
||||
* This method pops one element off the expected error codes
|
||||
* stack.
|
||||
@ -411,9 +373,6 @@ class PEAR
|
||||
return array_pop($this->_expected_errors);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ _checkDelExpect()
|
||||
|
||||
/**
|
||||
* This method checks unsets an error code if available
|
||||
*
|
||||
@ -425,8 +384,7 @@ class PEAR
|
||||
function _checkDelExpect($error_code)
|
||||
{
|
||||
$deleted = false;
|
||||
|
||||
foreach ($this->_expected_errors AS $key => $error_array) {
|
||||
foreach ($this->_expected_errors as $key => $error_array) {
|
||||
if (in_array($error_code, $error_array)) {
|
||||
unset($this->_expected_errors[$key][array_search($error_code, $error_array)]);
|
||||
$deleted = true;
|
||||
@ -437,12 +395,10 @@ class PEAR
|
||||
unset($this->_expected_errors[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ delExpect()
|
||||
|
||||
/**
|
||||
* This method deletes all occurences of the specified element from
|
||||
* the expected error codes stack.
|
||||
@ -455,34 +411,26 @@ class PEAR
|
||||
function delExpect($error_code)
|
||||
{
|
||||
$deleted = false;
|
||||
|
||||
if ((is_array($error_code) && (0 != count($error_code)))) {
|
||||
// $error_code is a non-empty array here;
|
||||
// we walk through it trying to unset all
|
||||
// values
|
||||
foreach($error_code as $key => $error) {
|
||||
if ($this->_checkDelExpect($error)) {
|
||||
$deleted = true;
|
||||
} else {
|
||||
$deleted = false;
|
||||
}
|
||||
// $error_code is a non-empty array here; we walk through it trying
|
||||
// to unset all values
|
||||
foreach ($error_code as $key => $error) {
|
||||
$deleted = $this->_checkDelExpect($error) ? true : false;
|
||||
}
|
||||
|
||||
return $deleted ? true : PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
|
||||
} elseif (!empty($error_code)) {
|
||||
// $error_code comes alone, trying to unset it
|
||||
if ($this->_checkDelExpect($error_code)) {
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
|
||||
return PEAR::raiseError("The expected error you submitted does not exist"); // IMPROVE ME
|
||||
}
|
||||
} else {
|
||||
|
||||
// $error_code is empty
|
||||
return PEAR::raiseError("The expected error you submitted is empty"); // IMPROVE ME
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ raiseError()
|
||||
|
||||
/**
|
||||
* This method is a wrapper that returns an instance of the
|
||||
@ -538,13 +486,20 @@ class PEAR
|
||||
$message = $message->getMessage();
|
||||
}
|
||||
|
||||
if (isset($this) && isset($this->_expected_errors) && sizeof($this->_expected_errors) > 0 && sizeof($exp = end($this->_expected_errors))) {
|
||||
if (
|
||||
isset($this) &&
|
||||
isset($this->_expected_errors) &&
|
||||
count($this->_expected_errors) > 0 &&
|
||||
count($exp = end($this->_expected_errors))
|
||||
) {
|
||||
if ($exp[0] == "*" ||
|
||||
(is_int(reset($exp)) && in_array($code, $exp)) ||
|
||||
(is_string(reset($exp)) && in_array($message, $exp))) {
|
||||
(is_string(reset($exp)) && in_array($message, $exp))
|
||||
) {
|
||||
$mode = PEAR_ERROR_RETURN;
|
||||
}
|
||||
}
|
||||
|
||||
// No mode given, try global ones
|
||||
if ($mode === null) {
|
||||
// Class error handler
|
||||
@ -565,43 +520,49 @@ class PEAR
|
||||
} else {
|
||||
$ec = 'PEAR_Error';
|
||||
}
|
||||
|
||||
if (intval(PHP_VERSION) < 5) {
|
||||
// little non-eval hack to fix bug #12147
|
||||
include 'PEAR/FixPHP5PEARWarnings.php';
|
||||
return $a;
|
||||
}
|
||||
|
||||
if ($skipmsg) {
|
||||
$a = new $ec($code, $mode, $options, $userinfo);
|
||||
} else {
|
||||
$a = new $ec($message, $code, $mode, $options, $userinfo);
|
||||
}
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ throwError()
|
||||
|
||||
/**
|
||||
* Simpler form of raiseError with fewer options. In most cases
|
||||
* message, code and userinfo are enough.
|
||||
*
|
||||
* @param string $message
|
||||
* @param mixed $message a text error message or a PEAR error object
|
||||
*
|
||||
* @param int $code a numeric error code (it is up to your class
|
||||
* to define these if you want to use codes)
|
||||
*
|
||||
* @param string $userinfo If you need to pass along for example debug
|
||||
* information, this parameter is meant for that.
|
||||
*
|
||||
* @access public
|
||||
* @return object a PEAR error object
|
||||
* @see PEAR::raiseError
|
||||
*/
|
||||
function &throwError($message = null,
|
||||
$code = null,
|
||||
$userinfo = null)
|
||||
function &throwError($message = null, $code = null, $userinfo = null)
|
||||
{
|
||||
if (isset($this) && is_a($this, 'PEAR')) {
|
||||
$a = &$this->raiseError($message, $code, null, null, $userinfo);
|
||||
return $a;
|
||||
} else {
|
||||
}
|
||||
|
||||
$a = &PEAR::raiseError($message, $code, null, null, $userinfo);
|
||||
return $a;
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
function staticPushErrorHandling($mode, $options = null)
|
||||
{
|
||||
$stack = &$GLOBALS['_PEAR_error_handler_stack'];
|
||||
@ -673,8 +634,6 @@ class PEAR
|
||||
return true;
|
||||
}
|
||||
|
||||
// {{{ pushErrorHandling()
|
||||
|
||||
/**
|
||||
* Push a new error handler on top of the error handler options stack. With this
|
||||
* you can easily override the actual error handler for some code and restore
|
||||
@ -708,9 +667,6 @@ class PEAR
|
||||
return true;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ popErrorHandling()
|
||||
|
||||
/**
|
||||
* Pop the last error handler used
|
||||
*
|
||||
@ -732,9 +688,6 @@ class PEAR
|
||||
return true;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ loadExtension()
|
||||
|
||||
/**
|
||||
* OS independant PHP extension load. Remember to take care
|
||||
* on the correct extension name for case sensitive OSes.
|
||||
@ -744,11 +697,19 @@ class PEAR
|
||||
*/
|
||||
function loadExtension($ext)
|
||||
{
|
||||
if (!extension_loaded($ext)) {
|
||||
if (extension_loaded($ext)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if either returns true dl() will produce a FATAL error, stop that
|
||||
if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
|
||||
if (
|
||||
function_exists('dl') === false ||
|
||||
ini_get('enable_dl') != 1 ||
|
||||
ini_get('safe_mode') == 1
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (OS_WINDOWS) {
|
||||
$suffix = '.dll';
|
||||
} elseif (PHP_OS == 'HP-UX') {
|
||||
@ -760,15 +721,14 @@ class PEAR
|
||||
} else {
|
||||
$suffix = '.so';
|
||||
}
|
||||
|
||||
return @dl('php_'.$ext.$suffix) || @dl($ext.$suffix);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
// {{{ _PEAR_call_destructors()
|
||||
if (PEAR_ZE2) {
|
||||
include_once 'PEAR5.php';
|
||||
}
|
||||
|
||||
function _PEAR_call_destructors()
|
||||
{
|
||||
@ -777,9 +737,16 @@ function _PEAR_call_destructors()
|
||||
sizeof($_PEAR_destructor_object_list))
|
||||
{
|
||||
reset($_PEAR_destructor_object_list);
|
||||
if (PEAR::getStaticProperty('PEAR', 'destructlifo')) {
|
||||
if (PEAR_ZE2) {
|
||||
$destructLifoExists = PEAR5::getStaticProperty('PEAR', 'destructlifo');
|
||||
} else {
|
||||
$destructLifoExists = PEAR::getStaticProperty('PEAR', 'destructlifo');
|
||||
}
|
||||
|
||||
if ($destructLifoExists) {
|
||||
$_PEAR_destructor_object_list = array_reverse($_PEAR_destructor_object_list);
|
||||
}
|
||||
|
||||
while (list($k, $objref) = each($_PEAR_destructor_object_list)) {
|
||||
$classname = get_class($objref);
|
||||
while ($classname) {
|
||||
@ -798,14 +765,17 @@ function _PEAR_call_destructors()
|
||||
}
|
||||
|
||||
// Now call the shutdown functions
|
||||
if (is_array($GLOBALS['_PEAR_shutdown_funcs']) AND !empty($GLOBALS['_PEAR_shutdown_funcs'])) {
|
||||
if (
|
||||
isset($GLOBALS['_PEAR_shutdown_funcs']) &&
|
||||
is_array($GLOBALS['_PEAR_shutdown_funcs']) &&
|
||||
!empty($GLOBALS['_PEAR_shutdown_funcs'])
|
||||
) {
|
||||
foreach ($GLOBALS['_PEAR_shutdown_funcs'] as $value) {
|
||||
call_user_func_array($value[0], $value[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
/**
|
||||
* Standard PEAR error class for PHP 4
|
||||
*
|
||||
@ -817,16 +787,14 @@ function _PEAR_call_destructors()
|
||||
* @author Tomas V.V. Cox <cox@idecnet.com>
|
||||
* @author Gregory Beaver <cellog@php.net>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.7.2
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/manual/en/core.pear.pear-error.php
|
||||
* @see PEAR::raiseError(), PEAR::throwError()
|
||||
* @since Class available since PHP 4.0.2
|
||||
*/
|
||||
class PEAR_Error
|
||||
{
|
||||
// {{{ properties
|
||||
|
||||
var $error_message_prefix = '';
|
||||
var $mode = PEAR_ERROR_RETURN;
|
||||
var $level = E_USER_NOTICE;
|
||||
@ -835,9 +803,6 @@ class PEAR_Error
|
||||
var $userinfo = '';
|
||||
var $backtrace = null;
|
||||
|
||||
// }}}
|
||||
// {{{ constructor
|
||||
|
||||
/**
|
||||
* PEAR_Error constructor
|
||||
*
|
||||
@ -868,12 +833,20 @@ class PEAR_Error
|
||||
$this->code = $code;
|
||||
$this->mode = $mode;
|
||||
$this->userinfo = $userinfo;
|
||||
if (!PEAR::getStaticProperty('PEAR_Error', 'skiptrace')) {
|
||||
|
||||
if (PEAR_ZE2) {
|
||||
$skiptrace = PEAR5::getStaticProperty('PEAR_Error', 'skiptrace');
|
||||
} else {
|
||||
$skiptrace = PEAR::getStaticProperty('PEAR_Error', 'skiptrace');
|
||||
}
|
||||
|
||||
if (!$skiptrace) {
|
||||
$this->backtrace = debug_backtrace();
|
||||
if (isset($this->backtrace[0]) && isset($this->backtrace[0]['object'])) {
|
||||
unset($this->backtrace[0]['object']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($mode & PEAR_ERROR_CALLBACK) {
|
||||
$this->level = E_USER_NOTICE;
|
||||
$this->callback = $options;
|
||||
@ -881,20 +854,25 @@ class PEAR_Error
|
||||
if ($options === null) {
|
||||
$options = E_USER_NOTICE;
|
||||
}
|
||||
|
||||
$this->level = $options;
|
||||
$this->callback = null;
|
||||
}
|
||||
|
||||
if ($this->mode & PEAR_ERROR_PRINT) {
|
||||
if (is_null($options) || is_int($options)) {
|
||||
$format = "%s";
|
||||
} else {
|
||||
$format = $options;
|
||||
}
|
||||
|
||||
printf($format, $this->getMessage());
|
||||
}
|
||||
|
||||
if ($this->mode & PEAR_ERROR_TRIGGER) {
|
||||
trigger_error($this->getMessage(), $this->level);
|
||||
}
|
||||
|
||||
if ($this->mode & PEAR_ERROR_DIE) {
|
||||
$msg = $this->getMessage();
|
||||
if (is_null($options) || is_int($options)) {
|
||||
@ -907,47 +885,39 @@ class PEAR_Error
|
||||
}
|
||||
die(sprintf($format, $msg));
|
||||
}
|
||||
if ($this->mode & PEAR_ERROR_CALLBACK) {
|
||||
if (is_callable($this->callback)) {
|
||||
|
||||
if ($this->mode & PEAR_ERROR_CALLBACK && is_callable($this->callback)) {
|
||||
call_user_func($this->callback, $this);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->mode & PEAR_ERROR_EXCEPTION) {
|
||||
trigger_error("PEAR_ERROR_EXCEPTION is obsolete, use class PEAR_Exception for exceptions", E_USER_WARNING);
|
||||
eval('$e = new Exception($this->message, $this->code);throw($e);');
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getMode()
|
||||
|
||||
/**
|
||||
* Get the error mode from an error object.
|
||||
*
|
||||
* @return int error mode
|
||||
* @access public
|
||||
*/
|
||||
function getMode() {
|
||||
function getMode()
|
||||
{
|
||||
return $this->mode;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getCallback()
|
||||
|
||||
/**
|
||||
* Get the callback function/method from an error object.
|
||||
*
|
||||
* @return mixed callback function or object/method array
|
||||
* @access public
|
||||
*/
|
||||
function getCallback() {
|
||||
function getCallback()
|
||||
{
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getMessage()
|
||||
|
||||
|
||||
/**
|
||||
* Get the error message from an error object.
|
||||
*
|
||||
@ -959,10 +929,6 @@ class PEAR_Error
|
||||
return ($this->error_message_prefix . $this->message);
|
||||
}
|
||||
|
||||
|
||||
// }}}
|
||||
// {{{ getCode()
|
||||
|
||||
/**
|
||||
* Get error code from an error object
|
||||
*
|
||||
@ -974,9 +940,6 @@ class PEAR_Error
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getType()
|
||||
|
||||
/**
|
||||
* Get the name of this error/exception.
|
||||
*
|
||||
@ -988,9 +951,6 @@ class PEAR_Error
|
||||
return get_class($this);
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getUserInfo()
|
||||
|
||||
/**
|
||||
* Get additional user-supplied information.
|
||||
*
|
||||
@ -1002,9 +962,6 @@ class PEAR_Error
|
||||
return $this->userinfo;
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getDebugInfo()
|
||||
|
||||
/**
|
||||
* Get additional debug information supplied by the application.
|
||||
*
|
||||
@ -1016,9 +973,6 @@ class PEAR_Error
|
||||
return $this->getUserInfo();
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ getBacktrace()
|
||||
|
||||
/**
|
||||
* Get the call backtrace from where the error was generated.
|
||||
* Supported with PHP 4.3.0 or newer.
|
||||
@ -1038,9 +992,6 @@ class PEAR_Error
|
||||
return $this->backtrace[$frame];
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ addUserInfo()
|
||||
|
||||
function addUserInfo($info)
|
||||
{
|
||||
if (empty($this->userinfo)) {
|
||||
@ -1050,14 +1001,10 @@ class PEAR_Error
|
||||
}
|
||||
}
|
||||
|
||||
// }}}
|
||||
// {{{ toString()
|
||||
function __toString()
|
||||
{
|
||||
return $this->getMessage();
|
||||
}
|
||||
// }}}
|
||||
// {{{ toString()
|
||||
|
||||
/**
|
||||
* Make a string representation of this object.
|
||||
@ -1065,7 +1012,8 @@ class PEAR_Error
|
||||
* @return string a string with an object summary
|
||||
* @access public
|
||||
*/
|
||||
function toString() {
|
||||
function toString()
|
||||
{
|
||||
$modes = array();
|
||||
$levels = array(E_USER_NOTICE => 'notice',
|
||||
E_USER_WARNING => 'warning',
|
||||
@ -1104,8 +1052,6 @@ class PEAR_Error
|
||||
$this->error_message_prefix,
|
||||
$this->userinfo);
|
||||
}
|
||||
|
||||
// }}}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1115,4 +1061,3 @@ class PEAR_Error
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
||||
?>
|
||||
|
985
extlib/PEAR/ErrorStack.php
Normal file
985
extlib/PEAR/ErrorStack.php
Normal file
@ -0,0 +1,985 @@
|
||||
<?php
|
||||
/**
|
||||
* Error Stack Implementation
|
||||
*
|
||||
* This is an incredibly simple implementation of a very complex error handling
|
||||
* facility. It contains the ability
|
||||
* to track multiple errors from multiple packages simultaneously. In addition,
|
||||
* it can track errors of many levels, save data along with the error, context
|
||||
* information such as the exact file, line number, class and function that
|
||||
* generated the error, and if necessary, it can raise a traditional PEAR_Error.
|
||||
* It has built-in support for PEAR::Log, to log errors as they occur
|
||||
*
|
||||
* Since version 0.2alpha, it is also possible to selectively ignore errors,
|
||||
* through the use of an error callback, see {@link pushCallback()}
|
||||
*
|
||||
* Since version 0.3alpha, it is possible to specify the exception class
|
||||
* returned from {@link push()}
|
||||
*
|
||||
* Since version PEAR1.3.2, ErrorStack no longer instantiates an exception class. This can
|
||||
* still be done quite handily in an error callback or by manipulating the returned array
|
||||
* @category Debugging
|
||||
* @package PEAR_ErrorStack
|
||||
* @author Greg Beaver <cellog@php.net>
|
||||
* @copyright 2004-2008 Greg Beaver
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: ErrorStack.php 307683 2011-01-23 21:56:12Z dufuz $
|
||||
* @link http://pear.php.net/package/PEAR_ErrorStack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Singleton storage
|
||||
*
|
||||
* Format:
|
||||
* <pre>
|
||||
* array(
|
||||
* 'package1' => PEAR_ErrorStack object,
|
||||
* 'package2' => PEAR_ErrorStack object,
|
||||
* ...
|
||||
* )
|
||||
* </pre>
|
||||
* @access private
|
||||
* @global array $GLOBALS['_PEAR_ERRORSTACK_SINGLETON']
|
||||
*/
|
||||
$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] = array();
|
||||
|
||||
/**
|
||||
* Global error callback (default)
|
||||
*
|
||||
* This is only used if set to non-false. * is the default callback for
|
||||
* all packages, whereas specific packages may set a default callback
|
||||
* for all instances, regardless of whether they are a singleton or not.
|
||||
*
|
||||
* To exclude non-singletons, only set the local callback for the singleton
|
||||
* @see PEAR_ErrorStack::setDefaultCallback()
|
||||
* @access private
|
||||
* @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']
|
||||
*/
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'] = array(
|
||||
'*' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
* Global Log object (default)
|
||||
*
|
||||
* This is only used if set to non-false. Use to set a default log object for
|
||||
* all stacks, regardless of instantiation order or location
|
||||
* @see PEAR_ErrorStack::setDefaultLogger()
|
||||
* @access private
|
||||
* @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
|
||||
*/
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = false;
|
||||
|
||||
/**
|
||||
* Global Overriding Callback
|
||||
*
|
||||
* This callback will override any error callbacks that specific loggers have set.
|
||||
* Use with EXTREME caution
|
||||
* @see PEAR_ErrorStack::staticPushCallback()
|
||||
* @access private
|
||||
* @global array $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']
|
||||
*/
|
||||
$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
|
||||
|
||||
/**#@+
|
||||
* One of four possible return values from the error Callback
|
||||
* @see PEAR_ErrorStack::_errorCallback()
|
||||
*/
|
||||
/**
|
||||
* If this is returned, then the error will be both pushed onto the stack
|
||||
* and logged.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_PUSHANDLOG', 1);
|
||||
/**
|
||||
* If this is returned, then the error will only be pushed onto the stack,
|
||||
* and not logged.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_PUSH', 2);
|
||||
/**
|
||||
* If this is returned, then the error will only be logged, but not pushed
|
||||
* onto the error stack.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_LOG', 3);
|
||||
/**
|
||||
* If this is returned, then the error is completely ignored.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_IGNORE', 4);
|
||||
/**
|
||||
* If this is returned, then the error is logged and die() is called.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_DIE', 5);
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Error code for an attempt to instantiate a non-class as a PEAR_ErrorStack in
|
||||
* the singleton method.
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_ERR_NONCLASS', 1);
|
||||
|
||||
/**
|
||||
* Error code for an attempt to pass an object into {@link PEAR_ErrorStack::getMessage()}
|
||||
* that has no __toString() method
|
||||
*/
|
||||
define('PEAR_ERRORSTACK_ERR_OBJTOSTRING', 2);
|
||||
/**
|
||||
* Error Stack Implementation
|
||||
*
|
||||
* Usage:
|
||||
* <code>
|
||||
* // global error stack
|
||||
* $global_stack = &PEAR_ErrorStack::singleton('MyPackage');
|
||||
* // local error stack
|
||||
* $local_stack = new PEAR_ErrorStack('MyPackage');
|
||||
* </code>
|
||||
* @author Greg Beaver <cellog@php.net>
|
||||
* @version 1.9.2
|
||||
* @package PEAR_ErrorStack
|
||||
* @category Debugging
|
||||
* @copyright 2004-2008 Greg Beaver
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: ErrorStack.php 307683 2011-01-23 21:56:12Z dufuz $
|
||||
* @link http://pear.php.net/package/PEAR_ErrorStack
|
||||
*/
|
||||
class PEAR_ErrorStack {
|
||||
/**
|
||||
* Errors are stored in the order that they are pushed on the stack.
|
||||
* @since 0.4alpha Errors are no longer organized by error level.
|
||||
* This renders pop() nearly unusable, and levels could be more easily
|
||||
* handled in a callback anyway
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_errors = array();
|
||||
|
||||
/**
|
||||
* Storage of errors by level.
|
||||
*
|
||||
* Allows easy retrieval and deletion of only errors from a particular level
|
||||
* @since PEAR 1.4.0dev
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
var $_errorsByLevel = array();
|
||||
|
||||
/**
|
||||
* Package name this error stack represents
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
var $_package;
|
||||
|
||||
/**
|
||||
* Determines whether a PEAR_Error is thrown upon every error addition
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
var $_compat = false;
|
||||
|
||||
/**
|
||||
* If set to a valid callback, this will be used to generate the error
|
||||
* message from the error code, otherwise the message passed in will be
|
||||
* used
|
||||
* @var false|string|array
|
||||
* @access private
|
||||
*/
|
||||
var $_msgCallback = false;
|
||||
|
||||
/**
|
||||
* If set to a valid callback, this will be used to generate the error
|
||||
* context for an error. For PHP-related errors, this will be a file
|
||||
* and line number as retrieved from debug_backtrace(), but can be
|
||||
* customized for other purposes. The error might actually be in a separate
|
||||
* configuration file, or in a database query.
|
||||
* @var false|string|array
|
||||
* @access protected
|
||||
*/
|
||||
var $_contextCallback = false;
|
||||
|
||||
/**
|
||||
* If set to a valid callback, this will be called every time an error
|
||||
* is pushed onto the stack. The return value will be used to determine
|
||||
* whether to allow an error to be pushed or logged.
|
||||
*
|
||||
* The return value must be one an PEAR_ERRORSTACK_* constant
|
||||
* @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
|
||||
* @var false|string|array
|
||||
* @access protected
|
||||
*/
|
||||
var $_errorCallback = array();
|
||||
|
||||
/**
|
||||
* PEAR::Log object for logging errors
|
||||
* @var false|Log
|
||||
* @access protected
|
||||
*/
|
||||
var $_logger = false;
|
||||
|
||||
/**
|
||||
* Error messages - designed to be overridden
|
||||
* @var array
|
||||
* @abstract
|
||||
*/
|
||||
var $_errorMsgs = array();
|
||||
|
||||
/**
|
||||
* Set up a new error stack
|
||||
*
|
||||
* @param string $package name of the package this error stack represents
|
||||
* @param callback $msgCallback callback used for error message generation
|
||||
* @param callback $contextCallback callback used for context generation,
|
||||
* defaults to {@link getFileLine()}
|
||||
* @param boolean $throwPEAR_Error
|
||||
*/
|
||||
function PEAR_ErrorStack($package, $msgCallback = false, $contextCallback = false,
|
||||
$throwPEAR_Error = false)
|
||||
{
|
||||
$this->_package = $package;
|
||||
$this->setMessageCallback($msgCallback);
|
||||
$this->setContextCallback($contextCallback);
|
||||
$this->_compat = $throwPEAR_Error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a single error stack for this package.
|
||||
*
|
||||
* Note that all parameters are ignored if the stack for package $package
|
||||
* has already been instantiated
|
||||
* @param string $package name of the package this error stack represents
|
||||
* @param callback $msgCallback callback used for error message generation
|
||||
* @param callback $contextCallback callback used for context generation,
|
||||
* defaults to {@link getFileLine()}
|
||||
* @param boolean $throwPEAR_Error
|
||||
* @param string $stackClass class to instantiate
|
||||
* @static
|
||||
* @return PEAR_ErrorStack
|
||||
*/
|
||||
function &singleton($package, $msgCallback = false, $contextCallback = false,
|
||||
$throwPEAR_Error = false, $stackClass = 'PEAR_ErrorStack')
|
||||
{
|
||||
if (isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
|
||||
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
|
||||
}
|
||||
if (!class_exists($stackClass)) {
|
||||
if (function_exists('debug_backtrace')) {
|
||||
$trace = debug_backtrace();
|
||||
}
|
||||
PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_NONCLASS,
|
||||
'exception', array('stackclass' => $stackClass),
|
||||
'stack class "%stackclass%" is not a valid class name (should be like PEAR_ErrorStack)',
|
||||
false, $trace);
|
||||
}
|
||||
$GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package] =
|
||||
new $stackClass($package, $msgCallback, $contextCallback, $throwPEAR_Error);
|
||||
|
||||
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package];
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal error handler for PEAR_ErrorStack class
|
||||
*
|
||||
* Dies if the error is an exception (and would have died anyway)
|
||||
* @access private
|
||||
*/
|
||||
function _handleError($err)
|
||||
{
|
||||
if ($err['level'] == 'exception') {
|
||||
$message = $err['message'];
|
||||
if (isset($_SERVER['REQUEST_URI'])) {
|
||||
echo '<br />';
|
||||
} else {
|
||||
echo "\n";
|
||||
}
|
||||
var_dump($err['context']);
|
||||
die($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a PEAR::Log object for all error stacks that don't have one
|
||||
* @param Log $log
|
||||
* @static
|
||||
*/
|
||||
function setDefaultLogger(&$log)
|
||||
{
|
||||
if (is_object($log) && method_exists($log, 'log') ) {
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
|
||||
} elseif (is_callable($log)) {
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'] = &$log;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up a PEAR::Log object for this error stack
|
||||
* @param Log $log
|
||||
*/
|
||||
function setLogger(&$log)
|
||||
{
|
||||
if (is_object($log) && method_exists($log, 'log') ) {
|
||||
$this->_logger = &$log;
|
||||
} elseif (is_callable($log)) {
|
||||
$this->_logger = &$log;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an error code => error message mapping callback
|
||||
*
|
||||
* This method sets the callback that can be used to generate error
|
||||
* messages for any instance
|
||||
* @param array|string Callback function/method
|
||||
*/
|
||||
function setMessageCallback($msgCallback)
|
||||
{
|
||||
if (!$msgCallback) {
|
||||
$this->_msgCallback = array(&$this, 'getErrorMessage');
|
||||
} else {
|
||||
if (is_callable($msgCallback)) {
|
||||
$this->_msgCallback = $msgCallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an error code => error message mapping callback
|
||||
*
|
||||
* This method returns the current callback that can be used to generate error
|
||||
* messages
|
||||
* @return array|string|false Callback function/method or false if none
|
||||
*/
|
||||
function getMessageCallback()
|
||||
{
|
||||
return $this->_msgCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default callback to be used by all error stacks
|
||||
*
|
||||
* This method sets the callback that can be used to generate error
|
||||
* messages for a singleton
|
||||
* @param array|string Callback function/method
|
||||
* @param string Package name, or false for all packages
|
||||
* @static
|
||||
*/
|
||||
function setDefaultCallback($callback = false, $package = false)
|
||||
{
|
||||
if (!is_callable($callback)) {
|
||||
$callback = false;
|
||||
}
|
||||
$package = $package ? $package : '*';
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$package] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback that generates context information (location of error) for an error stack
|
||||
*
|
||||
* This method sets the callback that can be used to generate context
|
||||
* information for an error. Passing in NULL will disable context generation
|
||||
* and remove the expensive call to debug_backtrace()
|
||||
* @param array|string|null Callback function/method
|
||||
*/
|
||||
function setContextCallback($contextCallback)
|
||||
{
|
||||
if ($contextCallback === null) {
|
||||
return $this->_contextCallback = false;
|
||||
}
|
||||
if (!$contextCallback) {
|
||||
$this->_contextCallback = array(&$this, 'getFileLine');
|
||||
} else {
|
||||
if (is_callable($contextCallback)) {
|
||||
$this->_contextCallback = $contextCallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an error Callback
|
||||
* If set to a valid callback, this will be called every time an error
|
||||
* is pushed onto the stack. The return value will be used to determine
|
||||
* whether to allow an error to be pushed or logged.
|
||||
*
|
||||
* The return value must be one of the ERRORSTACK_* constants.
|
||||
*
|
||||
* This functionality can be used to emulate PEAR's pushErrorHandling, and
|
||||
* the PEAR_ERROR_CALLBACK mode, without affecting the integrity of
|
||||
* the error stack or logging
|
||||
* @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
|
||||
* @see popCallback()
|
||||
* @param string|array $cb
|
||||
*/
|
||||
function pushCallback($cb)
|
||||
{
|
||||
array_push($this->_errorCallback, $cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a callback from the error callback stack
|
||||
* @see pushCallback()
|
||||
* @return array|string|false
|
||||
*/
|
||||
function popCallback()
|
||||
{
|
||||
if (!count($this->_errorCallback)) {
|
||||
return false;
|
||||
}
|
||||
return array_pop($this->_errorCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a temporary overriding error callback for every package error stack
|
||||
*
|
||||
* Use this to temporarily disable all existing callbacks (can be used
|
||||
* to emulate the @ operator, for instance)
|
||||
* @see PEAR_ERRORSTACK_PUSHANDLOG, PEAR_ERRORSTACK_PUSH, PEAR_ERRORSTACK_LOG
|
||||
* @see staticPopCallback(), pushCallback()
|
||||
* @param string|array $cb
|
||||
* @static
|
||||
*/
|
||||
function staticPushCallback($cb)
|
||||
{
|
||||
array_push($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'], $cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a temporary overriding error callback
|
||||
* @see staticPushCallback()
|
||||
* @return array|string|false
|
||||
* @static
|
||||
*/
|
||||
function staticPopCallback()
|
||||
{
|
||||
$ret = array_pop($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK']);
|
||||
if (!is_array($GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'])) {
|
||||
$GLOBALS['_PEAR_ERRORSTACK_OVERRIDE_CALLBACK'] = array();
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error to the stack
|
||||
*
|
||||
* If the message generator exists, it is called with 2 parameters.
|
||||
* - the current Error Stack object
|
||||
* - an array that is in the same format as an error. Available indices
|
||||
* are 'code', 'package', 'time', 'params', 'level', and 'context'
|
||||
*
|
||||
* Next, if the error should contain context information, this is
|
||||
* handled by the context grabbing method.
|
||||
* Finally, the error is pushed onto the proper error stack
|
||||
* @param int $code Package-specific error code
|
||||
* @param string $level Error level. This is NOT spell-checked
|
||||
* @param array $params associative array of error parameters
|
||||
* @param string $msg Error message, or a portion of it if the message
|
||||
* is to be generated
|
||||
* @param array $repackage If this error re-packages an error pushed by
|
||||
* another package, place the array returned from
|
||||
* {@link pop()} in this parameter
|
||||
* @param array $backtrace Protected parameter: use this to pass in the
|
||||
* {@link debug_backtrace()} that should be used
|
||||
* to find error context
|
||||
* @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
|
||||
* thrown. If a PEAR_Error is returned, the userinfo
|
||||
* property is set to the following array:
|
||||
*
|
||||
* <code>
|
||||
* array(
|
||||
* 'code' => $code,
|
||||
* 'params' => $params,
|
||||
* 'package' => $this->_package,
|
||||
* 'level' => $level,
|
||||
* 'time' => time(),
|
||||
* 'context' => $context,
|
||||
* 'message' => $msg,
|
||||
* //['repackage' => $err] repackaged error array/Exception class
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
* Normally, the previous array is returned.
|
||||
*/
|
||||
function push($code, $level = 'error', $params = array(), $msg = false,
|
||||
$repackage = false, $backtrace = false)
|
||||
{
|
||||
$context = false;
|
||||
// grab error context
|
||||
if ($this->_contextCallback) {
|
||||
if (!$backtrace) {
|
||||
$backtrace = debug_backtrace();
|
||||
}
|
||||
$context = call_user_func($this->_contextCallback, $code, $params, $backtrace);
|
||||
}
|
||||
|
||||
// save error
|
||||
$time = explode(' ', microtime());
|
||||
$time = $time[1] + $time[0];
|
||||
$err = array(
|
||||
'code' => $code,
|
||||
'params' => $params,
|
||||
'package' => $this->_package,
|
||||
'level' => $level,
|
||||
'time' => $time,
|
||||
'context' => $context,
|
||||
'message' => $msg,
|
||||
);
|
||||
|
||||
if ($repackage) {
|
||||
$err['repackage'] = $repackage;
|
||||
}
|
||||
|
||||
// set up the error message, if necessary
|
||||
if ($this->_msgCallback) {
|
||||
$msg = call_user_func_array($this->_msgCallback,
|
||||
array(&$this, $err));
|
||||
$err['message'] = $msg;
|
||||
}
|
||||
$push = $log = true;
|
||||
$die = false;
|
||||
// try the overriding callback first
|
||||
$callback = $this->staticPopCallback();
|
||||
if ($callback) {
|
||||
$this->staticPushCallback($callback);
|
||||
}
|
||||
if (!is_callable($callback)) {
|
||||
// try the local callback next
|
||||
$callback = $this->popCallback();
|
||||
if (is_callable($callback)) {
|
||||
$this->pushCallback($callback);
|
||||
} else {
|
||||
// try the default callback
|
||||
$callback = isset($GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package]) ?
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK'][$this->_package] :
|
||||
$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_CALLBACK']['*'];
|
||||
}
|
||||
}
|
||||
if (is_callable($callback)) {
|
||||
switch(call_user_func($callback, $err)){
|
||||
case PEAR_ERRORSTACK_IGNORE:
|
||||
return $err;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_PUSH:
|
||||
$log = false;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_LOG:
|
||||
$push = false;
|
||||
break;
|
||||
case PEAR_ERRORSTACK_DIE:
|
||||
$die = true;
|
||||
break;
|
||||
// anything else returned has the same effect as pushandlog
|
||||
}
|
||||
}
|
||||
if ($push) {
|
||||
array_unshift($this->_errors, $err);
|
||||
if (!isset($this->_errorsByLevel[$err['level']])) {
|
||||
$this->_errorsByLevel[$err['level']] = array();
|
||||
}
|
||||
$this->_errorsByLevel[$err['level']][] = &$this->_errors[0];
|
||||
}
|
||||
if ($log) {
|
||||
if ($this->_logger || $GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER']) {
|
||||
$this->_log($err);
|
||||
}
|
||||
}
|
||||
if ($die) {
|
||||
die();
|
||||
}
|
||||
if ($this->_compat && $push) {
|
||||
return $this->raiseError($msg, $code, null, null, $err);
|
||||
}
|
||||
return $err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static version of {@link push()}
|
||||
*
|
||||
* @param string $package Package name this error belongs to
|
||||
* @param int $code Package-specific error code
|
||||
* @param string $level Error level. This is NOT spell-checked
|
||||
* @param array $params associative array of error parameters
|
||||
* @param string $msg Error message, or a portion of it if the message
|
||||
* is to be generated
|
||||
* @param array $repackage If this error re-packages an error pushed by
|
||||
* another package, place the array returned from
|
||||
* {@link pop()} in this parameter
|
||||
* @param array $backtrace Protected parameter: use this to pass in the
|
||||
* {@link debug_backtrace()} that should be used
|
||||
* to find error context
|
||||
* @return PEAR_Error|array if compatibility mode is on, a PEAR_Error is also
|
||||
* thrown. see docs for {@link push()}
|
||||
* @static
|
||||
*/
|
||||
function staticPush($package, $code, $level = 'error', $params = array(),
|
||||
$msg = false, $repackage = false, $backtrace = false)
|
||||
{
|
||||
$s = &PEAR_ErrorStack::singleton($package);
|
||||
if ($s->_contextCallback) {
|
||||
if (!$backtrace) {
|
||||
if (function_exists('debug_backtrace')) {
|
||||
$backtrace = debug_backtrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $s->push($code, $level, $params, $msg, $repackage, $backtrace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an error using PEAR::Log
|
||||
* @param array $err Error array
|
||||
* @param array $levels Error level => Log constant map
|
||||
* @access protected
|
||||
*/
|
||||
function _log($err)
|
||||
{
|
||||
if ($this->_logger) {
|
||||
$logger = &$this->_logger;
|
||||
} else {
|
||||
$logger = &$GLOBALS['_PEAR_ERRORSTACK_DEFAULT_LOGGER'];
|
||||
}
|
||||
if (is_a($logger, 'Log')) {
|
||||
$levels = array(
|
||||
'exception' => PEAR_LOG_CRIT,
|
||||
'alert' => PEAR_LOG_ALERT,
|
||||
'critical' => PEAR_LOG_CRIT,
|
||||
'error' => PEAR_LOG_ERR,
|
||||
'warning' => PEAR_LOG_WARNING,
|
||||
'notice' => PEAR_LOG_NOTICE,
|
||||
'info' => PEAR_LOG_INFO,
|
||||
'debug' => PEAR_LOG_DEBUG);
|
||||
if (isset($levels[$err['level']])) {
|
||||
$level = $levels[$err['level']];
|
||||
} else {
|
||||
$level = PEAR_LOG_INFO;
|
||||
}
|
||||
$logger->log($err['message'], $level, $err);
|
||||
} else { // support non-standard logs
|
||||
call_user_func($logger, $err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pop an error off of the error stack
|
||||
*
|
||||
* @return false|array
|
||||
* @since 0.4alpha it is no longer possible to specify a specific error
|
||||
* level to return - the last error pushed will be returned, instead
|
||||
*/
|
||||
function pop()
|
||||
{
|
||||
$err = @array_shift($this->_errors);
|
||||
if (!is_null($err)) {
|
||||
@array_pop($this->_errorsByLevel[$err['level']]);
|
||||
if (!count($this->_errorsByLevel[$err['level']])) {
|
||||
unset($this->_errorsByLevel[$err['level']]);
|
||||
}
|
||||
}
|
||||
return $err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop an error off of the error stack, static method
|
||||
*
|
||||
* @param string package name
|
||||
* @return boolean
|
||||
* @since PEAR1.5.0a1
|
||||
*/
|
||||
function staticPop($package)
|
||||
{
|
||||
if ($package) {
|
||||
if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
|
||||
return false;
|
||||
}
|
||||
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->pop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether there are any errors on the stack
|
||||
* @param string|array Level name. Use to determine if any errors
|
||||
* of level (string), or levels (array) have been pushed
|
||||
* @return boolean
|
||||
*/
|
||||
function hasErrors($level = false)
|
||||
{
|
||||
if ($level) {
|
||||
return isset($this->_errorsByLevel[$level]);
|
||||
}
|
||||
return count($this->_errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all errors since last purge
|
||||
*
|
||||
* @param boolean set in order to empty the error stack
|
||||
* @param string level name, to return only errors of a particular severity
|
||||
* @return array
|
||||
*/
|
||||
function getErrors($purge = false, $level = false)
|
||||
{
|
||||
if (!$purge) {
|
||||
if ($level) {
|
||||
if (!isset($this->_errorsByLevel[$level])) {
|
||||
return array();
|
||||
} else {
|
||||
return $this->_errorsByLevel[$level];
|
||||
}
|
||||
} else {
|
||||
return $this->_errors;
|
||||
}
|
||||
}
|
||||
if ($level) {
|
||||
$ret = $this->_errorsByLevel[$level];
|
||||
foreach ($this->_errorsByLevel[$level] as $i => $unused) {
|
||||
// entries are references to the $_errors array
|
||||
$this->_errorsByLevel[$level][$i] = false;
|
||||
}
|
||||
// array_filter removes all entries === false
|
||||
$this->_errors = array_filter($this->_errors);
|
||||
unset($this->_errorsByLevel[$level]);
|
||||
return $ret;
|
||||
}
|
||||
$ret = $this->_errors;
|
||||
$this->_errors = array();
|
||||
$this->_errorsByLevel = array();
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether there are any errors on a single error stack, or on any error stack
|
||||
*
|
||||
* The optional parameter can be used to test the existence of any errors without the need of
|
||||
* singleton instantiation
|
||||
* @param string|false Package name to check for errors
|
||||
* @param string Level name to check for a particular severity
|
||||
* @return boolean
|
||||
* @static
|
||||
*/
|
||||
function staticHasErrors($package = false, $level = false)
|
||||
{
|
||||
if ($package) {
|
||||
if (!isset($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package])) {
|
||||
return false;
|
||||
}
|
||||
return $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->hasErrors($level);
|
||||
}
|
||||
foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
|
||||
if ($obj->hasErrors($level)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of all errors since last purge, organized by package
|
||||
* @since PEAR 1.4.0dev BC break! $level is now in the place $merge used to be
|
||||
* @param boolean $purge Set to purge the error stack of existing errors
|
||||
* @param string $level Set to a level name in order to retrieve only errors of a particular level
|
||||
* @param boolean $merge Set to return a flat array, not organized by package
|
||||
* @param array $sortfunc Function used to sort a merged array - default
|
||||
* sorts by time, and should be good for most cases
|
||||
* @static
|
||||
* @return array
|
||||
*/
|
||||
function staticGetErrors($purge = false, $level = false, $merge = false,
|
||||
$sortfunc = array('PEAR_ErrorStack', '_sortErrors'))
|
||||
{
|
||||
$ret = array();
|
||||
if (!is_callable($sortfunc)) {
|
||||
$sortfunc = array('PEAR_ErrorStack', '_sortErrors');
|
||||
}
|
||||
foreach ($GLOBALS['_PEAR_ERRORSTACK_SINGLETON'] as $package => $obj) {
|
||||
$test = $GLOBALS['_PEAR_ERRORSTACK_SINGLETON'][$package]->getErrors($purge, $level);
|
||||
if ($test) {
|
||||
if ($merge) {
|
||||
$ret = array_merge($ret, $test);
|
||||
} else {
|
||||
$ret[$package] = $test;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($merge) {
|
||||
usort($ret, $sortfunc);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error sorting function, sorts by time
|
||||
* @access private
|
||||
*/
|
||||
function _sortErrors($a, $b)
|
||||
{
|
||||
if ($a['time'] == $b['time']) {
|
||||
return 0;
|
||||
}
|
||||
if ($a['time'] < $b['time']) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard file/line number/function/class context callback
|
||||
*
|
||||
* This function uses a backtrace generated from {@link debug_backtrace()}
|
||||
* and so will not work at all in PHP < 4.3.0. The frame should
|
||||
* reference the frame that contains the source of the error.
|
||||
* @return array|false either array('file' => file, 'line' => line,
|
||||
* 'function' => function name, 'class' => class name) or
|
||||
* if this doesn't work, then false
|
||||
* @param unused
|
||||
* @param integer backtrace frame.
|
||||
* @param array Results of debug_backtrace()
|
||||
* @static
|
||||
*/
|
||||
function getFileLine($code, $params, $backtrace = null)
|
||||
{
|
||||
if ($backtrace === null) {
|
||||
return false;
|
||||
}
|
||||
$frame = 0;
|
||||
$functionframe = 1;
|
||||
if (!isset($backtrace[1])) {
|
||||
$functionframe = 0;
|
||||
} else {
|
||||
while (isset($backtrace[$functionframe]['function']) &&
|
||||
$backtrace[$functionframe]['function'] == 'eval' &&
|
||||
isset($backtrace[$functionframe + 1])) {
|
||||
$functionframe++;
|
||||
}
|
||||
}
|
||||
if (isset($backtrace[$frame])) {
|
||||
if (!isset($backtrace[$frame]['file'])) {
|
||||
$frame++;
|
||||
}
|
||||
$funcbacktrace = $backtrace[$functionframe];
|
||||
$filebacktrace = $backtrace[$frame];
|
||||
$ret = array('file' => $filebacktrace['file'],
|
||||
'line' => $filebacktrace['line']);
|
||||
// rearrange for eval'd code or create function errors
|
||||
if (strpos($filebacktrace['file'], '(') &&
|
||||
preg_match(';^(.*?)\((\d+)\) : (.*?)\\z;', $filebacktrace['file'],
|
||||
$matches)) {
|
||||
$ret['file'] = $matches[1];
|
||||
$ret['line'] = $matches[2] + 0;
|
||||
}
|
||||
if (isset($funcbacktrace['function']) && isset($backtrace[1])) {
|
||||
if ($funcbacktrace['function'] != 'eval') {
|
||||
if ($funcbacktrace['function'] == '__lambda_func') {
|
||||
$ret['function'] = 'create_function() code';
|
||||
} else {
|
||||
$ret['function'] = $funcbacktrace['function'];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($funcbacktrace['class']) && isset($backtrace[1])) {
|
||||
$ret['class'] = $funcbacktrace['class'];
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard error message generation callback
|
||||
*
|
||||
* This method may also be called by a custom error message generator
|
||||
* to fill in template values from the params array, simply
|
||||
* set the third parameter to the error message template string to use
|
||||
*
|
||||
* The special variable %__msg% is reserved: use it only to specify
|
||||
* where a message passed in by the user should be placed in the template,
|
||||
* like so:
|
||||
*
|
||||
* Error message: %msg% - internal error
|
||||
*
|
||||
* If the message passed like so:
|
||||
*
|
||||
* <code>
|
||||
* $stack->push(ERROR_CODE, 'error', array(), 'server error 500');
|
||||
* </code>
|
||||
*
|
||||
* The returned error message will be "Error message: server error 500 -
|
||||
* internal error"
|
||||
* @param PEAR_ErrorStack
|
||||
* @param array
|
||||
* @param string|false Pre-generated error message template
|
||||
* @static
|
||||
* @return string
|
||||
*/
|
||||
function getErrorMessage(&$stack, $err, $template = false)
|
||||
{
|
||||
if ($template) {
|
||||
$mainmsg = $template;
|
||||
} else {
|
||||
$mainmsg = $stack->getErrorMessageTemplate($err['code']);
|
||||
}
|
||||
$mainmsg = str_replace('%__msg%', $err['message'], $mainmsg);
|
||||
if (is_array($err['params']) && count($err['params'])) {
|
||||
foreach ($err['params'] as $name => $val) {
|
||||
if (is_array($val)) {
|
||||
// @ is needed in case $val is a multi-dimensional array
|
||||
$val = @implode(', ', $val);
|
||||
}
|
||||
if (is_object($val)) {
|
||||
if (method_exists($val, '__toString')) {
|
||||
$val = $val->__toString();
|
||||
} else {
|
||||
PEAR_ErrorStack::staticPush('PEAR_ErrorStack', PEAR_ERRORSTACK_ERR_OBJTOSTRING,
|
||||
'warning', array('obj' => get_class($val)),
|
||||
'object %obj% passed into getErrorMessage, but has no __toString() method');
|
||||
$val = 'Object';
|
||||
}
|
||||
}
|
||||
$mainmsg = str_replace('%' . $name . '%', $val, $mainmsg);
|
||||
}
|
||||
}
|
||||
return $mainmsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard Error Message Template generator from code
|
||||
* @return string
|
||||
*/
|
||||
function getErrorMessageTemplate($code)
|
||||
{
|
||||
if (!isset($this->_errorMsgs[$code])) {
|
||||
return '%__msg%';
|
||||
}
|
||||
return $this->_errorMsgs[$code];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Error Message Template array
|
||||
*
|
||||
* The array format must be:
|
||||
* <pre>
|
||||
* array(error code => 'message template',...)
|
||||
* </pre>
|
||||
*
|
||||
* Error message parameters passed into {@link push()} will be used as input
|
||||
* for the error message. If the template is 'message %foo% was %bar%', and the
|
||||
* parameters are array('foo' => 'one', 'bar' => 'six'), the error message returned will
|
||||
* be 'message one was six'
|
||||
* @return string
|
||||
*/
|
||||
function setErrorMessageTemplate($template)
|
||||
{
|
||||
$this->_errorMsgs = $template;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* emulate PEAR::raiseError()
|
||||
*
|
||||
* @return PEAR_Error
|
||||
*/
|
||||
function raiseError()
|
||||
{
|
||||
require_once 'PEAR.php';
|
||||
$args = func_get_args();
|
||||
return call_user_func_array(array('PEAR', 'raiseError'), $args);
|
||||
}
|
||||
}
|
||||
$stack = &PEAR_ErrorStack::singleton('PEAR_ErrorStack');
|
||||
$stack->pushCallback(array('PEAR_ErrorStack', '_handleError'));
|
||||
?>
|
@ -5,21 +5,15 @@
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* LICENSE: This source file is subject to version 3.0 of the PHP license
|
||||
* that is available through the world-wide-web at the following URI:
|
||||
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
|
||||
* the PHP License and are unable to obtain it through the web, please
|
||||
* send a note to license@php.net so we can mail you a copy immediately.
|
||||
*
|
||||
* @category pear
|
||||
* @package PEAR
|
||||
* @author Tomas V. V. Cox <cox@idecnet.com>
|
||||
* @author Hans Lellelid <hans@velum.net>
|
||||
* @author Bertrand Mansion <bmansion@mamasam.com>
|
||||
* @author Greg Beaver <cellog@php.net>
|
||||
* @copyright 1997-2008 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version CVS: $Id: Exception.php,v 1.29 2008/01/03 20:26:35 cellog Exp $
|
||||
* @copyright 1997-2009 The Authors
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: Exception.php 307683 2011-01-23 21:56:12Z dufuz $
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since File available since Release 1.3.3
|
||||
*/
|
||||
@ -93,9 +87,9 @@
|
||||
* @author Hans Lellelid <hans@velum.net>
|
||||
* @author Bertrand Mansion <bmansion@mamasam.com>
|
||||
* @author Greg Beaver <cellog@php.net>
|
||||
* @copyright 1997-2008 The PHP Group
|
||||
* @license http://www.php.net/license/3_0.txt PHP License 3.0
|
||||
* @version Release: 1.7.2
|
||||
* @copyright 1997-2009 The Authors
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since Class available since Release 1.3.3
|
||||
*
|
||||
@ -331,21 +325,21 @@ class PEAR_Exception extends Exception
|
||||
$trace = $this->getTraceSafe();
|
||||
$causes = array();
|
||||
$this->getCauseMessage($causes);
|
||||
$html = '<table border="1" cellspacing="0">' . "\n";
|
||||
$html = '<table style="border: 1px" cellspacing="0">' . "\n";
|
||||
foreach ($causes as $i => $cause) {
|
||||
$html .= '<tr><td colspan="3" bgcolor="#ff9999">'
|
||||
$html .= '<tr><td colspan="3" style="background: #ff9999">'
|
||||
. str_repeat('-', $i) . ' <b>' . $cause['class'] . '</b>: '
|
||||
. htmlspecialchars($cause['message']) . ' in <b>' . $cause['file'] . '</b> '
|
||||
. 'on line <b>' . $cause['line'] . '</b>'
|
||||
. "</td></tr>\n";
|
||||
}
|
||||
$html .= '<tr><td colspan="3" bgcolor="#aaaaaa" align="center"><b>Exception trace</b></td></tr>' . "\n"
|
||||
. '<tr><td align="center" bgcolor="#cccccc" width="20"><b>#</b></td>'
|
||||
. '<td align="center" bgcolor="#cccccc"><b>Function</b></td>'
|
||||
. '<td align="center" bgcolor="#cccccc"><b>Location</b></td></tr>' . "\n";
|
||||
$html .= '<tr><td colspan="3" style="background-color: #aaaaaa; text-align: center; font-weight: bold;">Exception trace</td></tr>' . "\n"
|
||||
. '<tr><td style="text-align: center; background: #cccccc; width:20px; font-weight: bold;">#</td>'
|
||||
. '<td style="text-align: center; background: #cccccc; font-weight: bold;">Function</td>'
|
||||
. '<td style="text-align: center; background: #cccccc; font-weight: bold;">Location</td></tr>' . "\n";
|
||||
|
||||
foreach ($trace as $k => $v) {
|
||||
$html .= '<tr><td align="center">' . $k . '</td>'
|
||||
$html .= '<tr><td style="text-align: center;">' . $k . '</td>'
|
||||
. '<td>';
|
||||
if (!empty($v['class'])) {
|
||||
$html .= $v['class'] . $v['type'];
|
||||
@ -373,7 +367,7 @@ class PEAR_Exception extends Exception
|
||||
. ':' . (isset($v['line']) ? $v['line'] : 'unknown')
|
||||
. '</td></tr>' . "\n";
|
||||
}
|
||||
$html .= '<tr><td align="center">' . ($k+1) . '</td>'
|
||||
$html .= '<tr><td style="text-align: center;">' . ($k+1) . '</td>'
|
||||
. '<td>{main}</td>'
|
||||
. '<td> </td></tr>' . "\n"
|
||||
. '</table>';
|
||||
@ -393,5 +387,3 @@ class PEAR_Exception extends Exception
|
||||
return $causeMsg . $this->getTraceAsString();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
33
extlib/PEAR5.php
Normal file
33
extlib/PEAR5.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
/**
|
||||
* This is only meant for PHP 5 to get rid of certain strict warning
|
||||
* that doesn't get hidden since it's in the shutdown function
|
||||
*/
|
||||
class PEAR5
|
||||
{
|
||||
/**
|
||||
* If you have a class that's mostly/entirely static, and you need static
|
||||
* properties, you can use this method to simulate them. Eg. in your method(s)
|
||||
* do this: $myVar = &PEAR5::getStaticProperty('myclass', 'myVar');
|
||||
* You MUST use a reference, or they will not persist!
|
||||
*
|
||||
* @access public
|
||||
* @param string $class The calling classname, to prevent clashes
|
||||
* @param string $var The variable to retrieve.
|
||||
* @return mixed A reference to the variable. If not set it will be
|
||||
* auto initialised to NULL.
|
||||
*/
|
||||
static function &getStaticProperty($class, $var)
|
||||
{
|
||||
static $properties;
|
||||
if (!isset($properties[$class])) {
|
||||
$properties[$class] = array();
|
||||
}
|
||||
|
||||
if (!array_key_exists($var, $properties[$class])) {
|
||||
$properties[$class][$var] = null;
|
||||
}
|
||||
|
||||
return $properties[$class][$var];
|
||||
}
|
||||
}
|
621
extlib/System.php
Normal file
621
extlib/System.php
Normal file
@ -0,0 +1,621 @@
|
||||
<?php
|
||||
/**
|
||||
* File/Directory manipulation
|
||||
*
|
||||
* PHP versions 4 and 5
|
||||
*
|
||||
* @category pear
|
||||
* @package System
|
||||
* @author Tomas V.V.Cox <cox@idecnet.com>
|
||||
* @copyright 1997-2009 The Authors
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version CVS: $Id: System.php 307683 2011-01-23 21:56:12Z dufuz $
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since File available since Release 0.1
|
||||
*/
|
||||
|
||||
/**
|
||||
* base class
|
||||
*/
|
||||
require_once 'PEAR.php';
|
||||
require_once 'Console/Getopt.php';
|
||||
|
||||
$GLOBALS['_System_temp_files'] = array();
|
||||
|
||||
/**
|
||||
* System offers cross plattform compatible system functions
|
||||
*
|
||||
* Static functions for different operations. Should work under
|
||||
* Unix and Windows. The names and usage has been taken from its respectively
|
||||
* GNU commands. The functions will return (bool) false on error and will
|
||||
* trigger the error with the PHP trigger_error() function (you can silence
|
||||
* the error by prefixing a '@' sign after the function call, but this
|
||||
* is not recommended practice. Instead use an error handler with
|
||||
* {@link set_error_handler()}).
|
||||
*
|
||||
* Documentation on this class you can find in:
|
||||
* http://pear.php.net/manual/
|
||||
*
|
||||
* Example usage:
|
||||
* if (!@System::rm('-r file1 dir1')) {
|
||||
* print "could not delete file1 or dir1";
|
||||
* }
|
||||
*
|
||||
* In case you need to to pass file names with spaces,
|
||||
* pass the params as an array:
|
||||
*
|
||||
* System::rm(array('-r', $file1, $dir1));
|
||||
*
|
||||
* @category pear
|
||||
* @package System
|
||||
* @author Tomas V.V. Cox <cox@idecnet.com>
|
||||
* @copyright 1997-2006 The PHP Group
|
||||
* @license http://opensource.org/licenses/bsd-license.php New BSD License
|
||||
* @version Release: 1.9.2
|
||||
* @link http://pear.php.net/package/PEAR
|
||||
* @since Class available since Release 0.1
|
||||
* @static
|
||||
*/
|
||||
class System
|
||||
{
|
||||
/**
|
||||
* returns the commandline arguments of a function
|
||||
*
|
||||
* @param string $argv the commandline
|
||||
* @param string $short_options the allowed option short-tags
|
||||
* @param string $long_options the allowed option long-tags
|
||||
* @return array the given options and there values
|
||||
* @static
|
||||
* @access private
|
||||
*/
|
||||
function _parseArgs($argv, $short_options, $long_options = null)
|
||||
{
|
||||
if (!is_array($argv) && $argv !== null) {
|
||||
$argv = preg_split('/\s+/', $argv, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
return Console_Getopt::getopt2($argv, $short_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output errors with PHP trigger_error(). You can silence the errors
|
||||
* with prefixing a "@" sign to the function call: @System::mkdir(..);
|
||||
*
|
||||
* @param mixed $error a PEAR error or a string with the error message
|
||||
* @return bool false
|
||||
* @static
|
||||
* @access private
|
||||
*/
|
||||
function raiseError($error)
|
||||
{
|
||||
if (PEAR::isError($error)) {
|
||||
$error = $error->getMessage();
|
||||
}
|
||||
trigger_error($error, E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nested array representing the structure of a directory
|
||||
*
|
||||
* System::_dirToStruct('dir1', 0) =>
|
||||
* Array
|
||||
* (
|
||||
* [dirs] => Array
|
||||
* (
|
||||
* [0] => dir1
|
||||
* )
|
||||
*
|
||||
* [files] => Array
|
||||
* (
|
||||
* [0] => dir1/file2
|
||||
* [1] => dir1/file3
|
||||
* )
|
||||
* )
|
||||
* @param string $sPath Name of the directory
|
||||
* @param integer $maxinst max. deep of the lookup
|
||||
* @param integer $aktinst starting deep of the lookup
|
||||
* @param bool $silent if true, do not emit errors.
|
||||
* @return array the structure of the dir
|
||||
* @static
|
||||
* @access private
|
||||
*/
|
||||
function _dirToStruct($sPath, $maxinst, $aktinst = 0, $silent = false)
|
||||
{
|
||||
$struct = array('dirs' => array(), 'files' => array());
|
||||
if (($dir = @opendir($sPath)) === false) {
|
||||
if (!$silent) {
|
||||
System::raiseError("Could not open dir $sPath");
|
||||
}
|
||||
return $struct; // XXX could not open error
|
||||
}
|
||||
|
||||
$struct['dirs'][] = $sPath = realpath($sPath); // XXX don't add if '.' or '..' ?
|
||||
$list = array();
|
||||
while (false !== ($file = readdir($dir))) {
|
||||
if ($file != '.' && $file != '..') {
|
||||
$list[] = $file;
|
||||
}
|
||||
}
|
||||
|
||||
closedir($dir);
|
||||
natsort($list);
|
||||
if ($aktinst < $maxinst || $maxinst == 0) {
|
||||
foreach ($list as $val) {
|
||||
$path = $sPath . DIRECTORY_SEPARATOR . $val;
|
||||
if (is_dir($path) && !is_link($path)) {
|
||||
$tmp = System::_dirToStruct($path, $maxinst, $aktinst+1, $silent);
|
||||
$struct = array_merge_recursive($struct, $tmp);
|
||||
} else {
|
||||
$struct['files'][] = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nested array representing the structure of a directory and files
|
||||
*
|
||||
* @param array $files Array listing files and dirs
|
||||
* @return array
|
||||
* @static
|
||||
* @see System::_dirToStruct()
|
||||
*/
|
||||
function _multipleToStruct($files)
|
||||
{
|
||||
$struct = array('dirs' => array(), 'files' => array());
|
||||
settype($files, 'array');
|
||||
foreach ($files as $file) {
|
||||
if (is_dir($file) && !is_link($file)) {
|
||||
$tmp = System::_dirToStruct($file, 0);
|
||||
$struct = array_merge_recursive($tmp, $struct);
|
||||
} else {
|
||||
if (!in_array($file, $struct['files'])) {
|
||||
$struct['files'][] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $struct;
|
||||
}
|
||||
|
||||
/**
|
||||
* The rm command for removing files.
|
||||
* Supports multiple files and dirs and also recursive deletes
|
||||
*
|
||||
* @param string $args the arguments for rm
|
||||
* @return mixed PEAR_Error or true for success
|
||||
* @static
|
||||
* @access public
|
||||
*/
|
||||
function rm($args)
|
||||
{
|
||||
$opts = System::_parseArgs($args, 'rf'); // "f" does nothing but I like it :-)
|
||||
if (PEAR::isError($opts)) {
|
||||
return System::raiseError($opts);
|
||||
}
|
||||
foreach ($opts[0] as $opt) {
|
||||
if ($opt[0] == 'r') {
|
||||
$do_recursive = true;
|
||||
}
|
||||
}
|
||||
$ret = true;
|
||||
if (isset($do_recursive)) {
|
||||
$struct = System::_multipleToStruct($opts[1]);
|
||||
foreach ($struct['files'] as $file) {
|
||||
if (!@unlink($file)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
rsort($struct['dirs']);
|
||||
foreach ($struct['dirs'] as $dir) {
|
||||
if (!@rmdir($dir)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($opts[1] as $file) {
|
||||
$delete = (is_dir($file)) ? 'rmdir' : 'unlink';
|
||||
if (!@$delete($file)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make directories.
|
||||
*
|
||||
* The -p option will create parent directories
|
||||
* @param string $args the name of the director(y|ies) to create
|
||||
* @return bool True for success
|
||||
* @static
|
||||
* @access public
|
||||
*/
|
||||
function mkDir($args)
|
||||
{
|
||||
$opts = System::_parseArgs($args, 'pm:');
|
||||
if (PEAR::isError($opts)) {
|
||||
return System::raiseError($opts);
|
||||
}
|
||||
|
||||
$mode = 0777; // default mode
|
||||
foreach ($opts[0] as $opt) {
|
||||
if ($opt[0] == 'p') {
|
||||
$create_parents = true;
|
||||
} elseif ($opt[0] == 'm') {
|
||||
// if the mode is clearly an octal number (starts with 0)
|
||||
// convert it to decimal
|
||||
if (strlen($opt[1]) && $opt[1]{0} == '0') {
|
||||
$opt[1] = octdec($opt[1]);
|
||||
} else {
|
||||
// convert to int
|
||||
$opt[1] += 0;
|
||||
}
|
||||
$mode = $opt[1];
|
||||
}
|
||||
}
|
||||
|
||||
$ret = true;
|
||||
if (isset($create_parents)) {
|
||||
foreach ($opts[1] as $dir) {
|
||||
$dirstack = array();
|
||||
while ((!file_exists($dir) || !is_dir($dir)) &&
|
||||
$dir != DIRECTORY_SEPARATOR) {
|
||||
array_unshift($dirstack, $dir);
|
||||
$dir = dirname($dir);
|
||||
}
|
||||
|
||||
while ($newdir = array_shift($dirstack)) {
|
||||
if (!is_writeable(dirname($newdir))) {
|
||||
$ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mkdir($newdir, $mode)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach($opts[1] as $dir) {
|
||||
if ((@file_exists($dir) || !is_dir($dir)) && !mkdir($dir, $mode)) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate files
|
||||
*
|
||||
* Usage:
|
||||
* 1) $var = System::cat('sample.txt test.txt');
|
||||
* 2) System::cat('sample.txt test.txt > final.txt');
|
||||
* 3) System::cat('sample.txt test.txt >> final.txt');
|
||||
*
|
||||
* Note: as the class use fopen, urls should work also (test that)
|
||||
*
|
||||
* @param string $args the arguments
|
||||
* @return boolean true on success
|
||||
* @static
|
||||
* @access public
|
||||
*/
|
||||
function &cat($args)
|
||||
{
|
||||
$ret = null;
|
||||
$files = array();
|
||||
if (!is_array($args)) {
|
||||
$args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
|
||||
$count_args = count($args);
|
||||
for ($i = 0; $i < $count_args; $i++) {
|
||||
if ($args[$i] == '>') {
|
||||
$mode = 'wb';
|
||||
$outputfile = $args[$i+1];
|
||||
break;
|
||||
} elseif ($args[$i] == '>>') {
|
||||
$mode = 'ab+';
|
||||
$outputfile = $args[$i+1];
|
||||
break;
|
||||
} else {
|
||||
$files[] = $args[$i];
|
||||
}
|
||||
}
|
||||
$outputfd = false;
|
||||
if (isset($mode)) {
|
||||
if (!$outputfd = fopen($outputfile, $mode)) {
|
||||
$err = System::raiseError("Could not open $outputfile");
|
||||
return $err;
|
||||
}
|
||||
$ret = true;
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
if (!$fd = fopen($file, 'r')) {
|
||||
System::raiseError("Could not open $file");
|
||||
continue;
|
||||
}
|
||||
while ($cont = fread($fd, 2048)) {
|
||||
if (is_resource($outputfd)) {
|
||||
fwrite($outputfd, $cont);
|
||||
} else {
|
||||
$ret .= $cont;
|
||||
}
|
||||
}
|
||||
fclose($fd);
|
||||
}
|
||||
if (is_resource($outputfd)) {
|
||||
fclose($outputfd);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates temporary files or directories. This function will remove
|
||||
* the created files when the scripts finish its execution.
|
||||
*
|
||||
* Usage:
|
||||
* 1) $tempfile = System::mktemp("prefix");
|
||||
* 2) $tempdir = System::mktemp("-d prefix");
|
||||
* 3) $tempfile = System::mktemp();
|
||||
* 4) $tempfile = System::mktemp("-t /var/tmp prefix");
|
||||
*
|
||||
* prefix -> The string that will be prepended to the temp name
|
||||
* (defaults to "tmp").
|
||||
* -d -> A temporary dir will be created instead of a file.
|
||||
* -t -> The target dir where the temporary (file|dir) will be created. If
|
||||
* this param is missing by default the env vars TMP on Windows or
|
||||
* TMPDIR in Unix will be used. If these vars are also missing
|
||||
* c:\windows\temp or /tmp will be used.
|
||||
*
|
||||
* @param string $args The arguments
|
||||
* @return mixed the full path of the created (file|dir) or false
|
||||
* @see System::tmpdir()
|
||||
* @static
|
||||
* @access public
|
||||
*/
|
||||
function mktemp($args = null)
|
||||
{
|
||||
static $first_time = true;
|
||||
$opts = System::_parseArgs($args, 't:d');
|
||||
if (PEAR::isError($opts)) {
|
||||
return System::raiseError($opts);
|
||||
}
|
||||
|
||||
foreach ($opts[0] as $opt) {
|
||||
if ($opt[0] == 'd') {
|
||||
$tmp_is_dir = true;
|
||||
} elseif ($opt[0] == 't') {
|
||||
$tmpdir = $opt[1];
|
||||
}
|
||||
}
|
||||
|
||||
$prefix = (isset($opts[1][0])) ? $opts[1][0] : 'tmp';
|
||||
if (!isset($tmpdir)) {
|
||||
$tmpdir = System::tmpdir();
|
||||
}
|
||||
|
||||
if (!System::mkDir(array('-p', $tmpdir))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$tmp = tempnam($tmpdir, $prefix);
|
||||
if (isset($tmp_is_dir)) {
|
||||
unlink($tmp); // be careful possible race condition here
|
||||
if (!mkdir($tmp, 0700)) {
|
||||
return System::raiseError("Unable to create temporary directory $tmpdir");
|
||||
}
|
||||
}
|
||||
|
||||
$GLOBALS['_System_temp_files'][] = $tmp;
|
||||
if (isset($tmp_is_dir)) {
|
||||
//$GLOBALS['_System_temp_files'][] = dirname($tmp);
|
||||
}
|
||||
|
||||
if ($first_time) {
|
||||
PEAR::registerShutdownFunc(array('System', '_removeTmpFiles'));
|
||||
$first_time = false;
|
||||
}
|
||||
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove temporary files created my mkTemp. This function is executed
|
||||
* at script shutdown time
|
||||
*
|
||||
* @static
|
||||
* @access private
|
||||
*/
|
||||
function _removeTmpFiles()
|
||||
{
|
||||
if (count($GLOBALS['_System_temp_files'])) {
|
||||
$delete = $GLOBALS['_System_temp_files'];
|
||||
array_unshift($delete, '-r');
|
||||
System::rm($delete);
|
||||
$GLOBALS['_System_temp_files'] = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path of the temporal directory set in the system
|
||||
* by looking in its environments variables.
|
||||
* Note: php.ini-recommended removes the "E" from the variables_order setting,
|
||||
* making unavaible the $_ENV array, that s why we do tests with _ENV
|
||||
*
|
||||
* @static
|
||||
* @return string The temporary directory on the system
|
||||
*/
|
||||
function tmpdir()
|
||||
{
|
||||
if (OS_WINDOWS) {
|
||||
if ($var = isset($_ENV['TMP']) ? $_ENV['TMP'] : getenv('TMP')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['TEMP']) ? $_ENV['TEMP'] : getenv('TEMP')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['USERPROFILE']) ? $_ENV['USERPROFILE'] : getenv('USERPROFILE')) {
|
||||
return $var;
|
||||
}
|
||||
if ($var = isset($_ENV['windir']) ? $_ENV['windir'] : getenv('windir')) {
|
||||
return $var;
|
||||
}
|
||||
return getenv('SystemRoot') . '\temp';
|
||||
}
|
||||
if ($var = isset($_ENV['TMPDIR']) ? $_ENV['TMPDIR'] : getenv('TMPDIR')) {
|
||||
return $var;
|
||||
}
|
||||
return realpath('/tmp');
|
||||
}
|
||||
|
||||
/**
|
||||
* The "which" command (show the full path of a command)
|
||||
*
|
||||
* @param string $program The command to search for
|
||||
* @param mixed $fallback Value to return if $program is not found
|
||||
*
|
||||
* @return mixed A string with the full path or false if not found
|
||||
* @static
|
||||
* @author Stig Bakken <ssb@php.net>
|
||||
*/
|
||||
function which($program, $fallback = false)
|
||||
{
|
||||
// enforce API
|
||||
if (!is_string($program) || '' == $program) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
// full path given
|
||||
if (basename($program) != $program) {
|
||||
$path_elements[] = dirname($program);
|
||||
$program = basename($program);
|
||||
} else {
|
||||
// Honor safe mode
|
||||
if (!ini_get('safe_mode') || !$path = ini_get('safe_mode_exec_dir')) {
|
||||
$path = getenv('PATH');
|
||||
if (!$path) {
|
||||
$path = getenv('Path'); // some OSes are just stupid enough to do this
|
||||
}
|
||||
}
|
||||
$path_elements = explode(PATH_SEPARATOR, $path);
|
||||
}
|
||||
|
||||
if (OS_WINDOWS) {
|
||||
$exe_suffixes = getenv('PATHEXT')
|
||||
? explode(PATH_SEPARATOR, getenv('PATHEXT'))
|
||||
: array('.exe','.bat','.cmd','.com');
|
||||
// allow passing a command.exe param
|
||||
if (strpos($program, '.') !== false) {
|
||||
array_unshift($exe_suffixes, '');
|
||||
}
|
||||
// is_executable() is not available on windows for PHP4
|
||||
$pear_is_executable = (function_exists('is_executable')) ? 'is_executable' : 'is_file';
|
||||
} else {
|
||||
$exe_suffixes = array('');
|
||||
$pear_is_executable = 'is_executable';
|
||||
}
|
||||
|
||||
foreach ($exe_suffixes as $suff) {
|
||||
foreach ($path_elements as $dir) {
|
||||
$file = $dir . DIRECTORY_SEPARATOR . $program . $suff;
|
||||
if (@$pear_is_executable($file)) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "find" command
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* System::find($dir);
|
||||
* System::find("$dir -type d");
|
||||
* System::find("$dir -type f");
|
||||
* System::find("$dir -name *.php");
|
||||
* System::find("$dir -name *.php -name *.htm*");
|
||||
* System::find("$dir -maxdepth 1");
|
||||
*
|
||||
* Params implmented:
|
||||
* $dir -> Start the search at this directory
|
||||
* -type d -> return only directories
|
||||
* -type f -> return only files
|
||||
* -maxdepth <n> -> max depth of recursion
|
||||
* -name <pattern> -> search pattern (bash style). Multiple -name param allowed
|
||||
*
|
||||
* @param mixed Either array or string with the command line
|
||||
* @return array Array of found files
|
||||
* @static
|
||||
*
|
||||
*/
|
||||
function find($args)
|
||||
{
|
||||
if (!is_array($args)) {
|
||||
$args = preg_split('/\s+/', $args, -1, PREG_SPLIT_NO_EMPTY);
|
||||
}
|
||||
$dir = realpath(array_shift($args));
|
||||
if (!$dir) {
|
||||
return array();
|
||||
}
|
||||
$patterns = array();
|
||||
$depth = 0;
|
||||
$do_files = $do_dirs = true;
|
||||
$args_count = count($args);
|
||||
for ($i = 0; $i < $args_count; $i++) {
|
||||
switch ($args[$i]) {
|
||||
case '-type':
|
||||
if (in_array($args[$i+1], array('d', 'f'))) {
|
||||
if ($args[$i+1] == 'd') {
|
||||
$do_files = false;
|
||||
} else {
|
||||
$do_dirs = false;
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
break;
|
||||
case '-name':
|
||||
$name = preg_quote($args[$i+1], '#');
|
||||
// our magic characters ? and * have just been escaped,
|
||||
// so now we change the escaped versions to PCRE operators
|
||||
$name = strtr($name, array('\?' => '.', '\*' => '.*'));
|
||||
$patterns[] = '('.$name.')';
|
||||
$i++;
|
||||
break;
|
||||
case '-maxdepth':
|
||||
$depth = $args[$i+1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
$path = System::_dirToStruct($dir, $depth, 0, true);
|
||||
if ($do_files && $do_dirs) {
|
||||
$files = array_merge($path['files'], $path['dirs']);
|
||||
} elseif ($do_dirs) {
|
||||
$files = $path['dirs'];
|
||||
} else {
|
||||
$files = $path['files'];
|
||||
}
|
||||
if (count($patterns)) {
|
||||
$dsq = preg_quote(DIRECTORY_SEPARATOR, '#');
|
||||
$pattern = '#(^|'.$dsq.')'.implode('|', $patterns).'($|'.$dsq.')#';
|
||||
$ret = array();
|
||||
$files_count = count($files);
|
||||
for ($i = 0; $i < $files_count; $i++) {
|
||||
// only search in the part of the file below the current directory
|
||||
$filepart = basename($files[$i]);
|
||||
if (preg_match($pattern, $filepart)) {
|
||||
$ret[] = $files[$i];
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
}
|
12
js/util.js
12
js/util.js
@ -1590,6 +1590,18 @@ var SN = { // StatusNet
|
||||
SN.U.FormXHR($(this));
|
||||
return false;
|
||||
});
|
||||
$('form.ajax input[type=submit]').live('click', function() {
|
||||
// Some forms rely on knowing which submit button was clicked.
|
||||
// Save a hidden input field which'll be picked up during AJAX
|
||||
// submit...
|
||||
var button = $(this);
|
||||
var form = button.closest('form');
|
||||
form.find('.hidden-submit-button').remove();
|
||||
$('<input class="hidden-submit-button" type="hidden" />')
|
||||
.attr('name', button.attr('name'))
|
||||
.val(button.val())
|
||||
.appendTo(form);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
2
js/util.min.js
vendored
2
js/util.min.js
vendored
File diff suppressed because one or more lines are too long
@ -46,7 +46,6 @@ require_once INSTALLDIR.'/lib/peopletags.php';
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class AccountProfileBlock extends ProfileBlock
|
||||
{
|
||||
protected $profile = null;
|
||||
@ -149,9 +148,9 @@ class AccountProfileBlock extends ProfileBlock
|
||||
$this->out->elementStart('li', 'entity_edit');
|
||||
$this->out->element('a', array('href' => common_local_url('profilesettings'),
|
||||
// TRANS: Link title for link on user profile.
|
||||
'title' => _('Edit profile settings')),
|
||||
'title' => _('Edit profile settings.')),
|
||||
// TRANS: Link text for link on user profile.
|
||||
_('Edit'));
|
||||
_m('BUTTON','Edit'));
|
||||
$this->out->elementEnd('li');
|
||||
} else { // someone else's page
|
||||
|
||||
@ -162,6 +161,9 @@ class AccountProfileBlock extends ProfileBlock
|
||||
if ($cur->isSubscribed($this->profile)) {
|
||||
$usf = new UnsubscribeForm($this->out, $this->profile);
|
||||
$usf->show();
|
||||
} else if ($cur->hasPendingSubscription($this->profile)) {
|
||||
$sf = new CancelSubscriptionForm($this->out, $this->profile);
|
||||
$sf->show();
|
||||
} else {
|
||||
$sf = new SubscribeForm($this->out, $this->profile);
|
||||
$sf->show();
|
||||
@ -175,9 +177,9 @@ class AccountProfileBlock extends ProfileBlock
|
||||
$this->out->elementStart('li', 'entity_send-a-message');
|
||||
$this->out->element('a', array('href' => common_local_url('newmessage', array('to' => $this->user->id)),
|
||||
// TRANS: Link title for link on user profile.
|
||||
'title' => _('Send a direct message to this user')),
|
||||
'title' => _('Send a direct message to this user.')),
|
||||
// TRANS: Link text for link on user profile.
|
||||
_('Message'));
|
||||
_m('BUTTON','Message'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
// nudge
|
||||
@ -303,6 +305,6 @@ class AccountProfileBlock extends ProfileBlock
|
||||
$this->out->element('a', array('href' => $url,
|
||||
'class' => 'entity_remote_subscribe'),
|
||||
// TRANS: Link text for link that will subscribe to a remote profile.
|
||||
_('Subscribe'));
|
||||
_m('BUTTON','Subscribe'));
|
||||
}
|
||||
}
|
||||
|
@ -663,7 +663,8 @@ class Action extends HTMLOutputter // lawsuit
|
||||
|
||||
if (Event::handle('StartMakeEntryForm', array($tag, $this, &$form))) {
|
||||
if ($tag == 'status') {
|
||||
$form = new NoticeForm($this);
|
||||
$options = $this->noticeFormOptions();
|
||||
$form = new NoticeForm($this, $options);
|
||||
}
|
||||
Event::handle('EndMakeEntryForm', array($tag, $this, $form));
|
||||
}
|
||||
@ -679,6 +680,11 @@ class Action extends HTMLOutputter // lawsuit
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function noticeFormOptions()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show anonymous message.
|
||||
*
|
||||
|
@ -292,7 +292,7 @@ class ApiAction extends Action
|
||||
if ($get_notice) {
|
||||
$notice = $profile->getCurrentNotice();
|
||||
if ($notice) {
|
||||
# don't get user!
|
||||
// don't get user!
|
||||
$twitter_user['status'] = $this->twitterStatusArray($notice, false);
|
||||
}
|
||||
}
|
||||
@ -397,7 +397,7 @@ class ApiAction extends Action
|
||||
}
|
||||
|
||||
if ($include_user && $profile) {
|
||||
# Don't get notice (recursive!)
|
||||
// Don't get notice (recursive!)
|
||||
$twitter_user = $this->twitterUserArray($profile, false);
|
||||
$twitter_status['user'] = $twitter_user;
|
||||
}
|
||||
@ -738,7 +738,7 @@ class ApiAction extends Action
|
||||
$this->element('guid', null, $entry['guid']);
|
||||
$this->element('link', null, $entry['link']);
|
||||
|
||||
# RSS only supports 1 enclosure per item
|
||||
// RSS only supports 1 enclosure per item
|
||||
if(array_key_exists('enclosures', $entry) and !empty($entry['enclosures'])){
|
||||
$enclosure = $entry['enclosures'][0];
|
||||
$this->element('enclosure', array('url'=>$enclosure['url'],'type'=>$enclosure['mimetype'],'length'=>$enclosure['size']), null);
|
||||
@ -873,7 +873,7 @@ class ApiAction extends Action
|
||||
}
|
||||
|
||||
if (!is_null($suplink)) {
|
||||
# For FriendFeed's SUP protocol
|
||||
// For FriendFeed's SUP protocol
|
||||
$this->element('link', array('rel' => 'http://api.friendfeed.com/2008/03#sup',
|
||||
'href' => $suplink,
|
||||
'type' => 'application/json'));
|
||||
|
@ -46,7 +46,6 @@ require_once INSTALLDIR.'/lib/form.php';
|
||||
*
|
||||
* @see UnsubscribeForm
|
||||
*/
|
||||
|
||||
class ApproveGroupForm extends Form
|
||||
{
|
||||
/**
|
||||
@ -62,7 +61,6 @@ class ApproveGroupForm extends Form
|
||||
* @param HTMLOutputter $out output channel
|
||||
* @param group $group group to leave
|
||||
*/
|
||||
|
||||
function __construct($out=null, $group=null, $profile=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
@ -76,10 +74,9 @@ class ApproveGroupForm extends Form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'group-cancel-' . $this->group->id;
|
||||
return 'group-queue-' . $this->group->id;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,10 +84,9 @@ class ApproveGroupForm extends Form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_group_join ajax';
|
||||
return 'form_group_queue ajax';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,7 +94,6 @@ class ApproveGroupForm extends Form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
$params = array();
|
||||
@ -117,6 +112,9 @@ class ApproveGroupForm extends Form
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Approve'));
|
||||
// TRANS: Submit button text to accept a group membership request on approve group form.
|
||||
$this->out->submit('approve', _m('BUTTON','Accept'));
|
||||
// TRANS: Submit button text to reject a group membership request on approve group form.
|
||||
$this->out->submit('cancel', _m('BUTTON','Reject'));
|
||||
}
|
||||
}
|
||||
|
114
lib/approvesubform.php
Normal file
114
lib/approvesubform.php
Normal file
@ -0,0 +1,114 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Form for leaving a group
|
||||
*
|
||||
* 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 Form
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/form.php';
|
||||
|
||||
/**
|
||||
* Form for leaving a group
|
||||
*
|
||||
* @category Form
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see UnsubscribeForm
|
||||
*/
|
||||
class ApproveSubForm extends Form
|
||||
{
|
||||
var $profile = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param HTMLOutputter $out output channel
|
||||
* @param Profile $profile user whose request to accept or drop
|
||||
*/
|
||||
function __construct($out=null, $profile=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
|
||||
$this->profile = $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
function id()
|
||||
{
|
||||
return 'sub-queue-' . $this->profile->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
function formClass()
|
||||
{
|
||||
return 'form_sub_queue ajax';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
function action()
|
||||
{
|
||||
$params = array();
|
||||
if ($this->profile) {
|
||||
$params['profile_id'] = $this->profile->id;
|
||||
}
|
||||
return common_local_url('approvesub',
|
||||
array(), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
// TRANS: Submit button text to accept a subscription request on approve sub form.
|
||||
$this->out->submit('approve', _m('BUTTON','Accept'));
|
||||
// TRANS: Submit button text to reject a subscription request on approve sub form.
|
||||
$this->out->submit('cancel', _m('BUTTON','Reject'));
|
||||
}
|
||||
}
|
129
lib/cachingnoticestream.php
Normal file
129
lib/cachingnoticestream.php
Normal file
@ -0,0 +1,129 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2011, StatusNet, Inc.
|
||||
*
|
||||
* A stream of notices
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* 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 Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for notice streams
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class CachingNoticeStream extends NoticeStream
|
||||
{
|
||||
const CACHE_WINDOW = 200;
|
||||
|
||||
public $stream = null;
|
||||
public $cachekey = null;
|
||||
|
||||
function __construct($stream, $cachekey)
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$this->cachekey = $cachekey;
|
||||
}
|
||||
|
||||
function getNoticeIds($offset, $limit, $sinceId, $maxId)
|
||||
{
|
||||
$cache = Cache::instance();
|
||||
|
||||
// We cache self::CACHE_WINDOW elements at the tip of the stream.
|
||||
// If the cache won't be hit, just generate directly.
|
||||
|
||||
if (empty($cache) ||
|
||||
$sinceId != 0 || $maxId != 0 ||
|
||||
is_null($limit) ||
|
||||
($offset + $limit) > self::CACHE_WINDOW) {
|
||||
return $this->stream->getNoticeIds($offset, $limit, $sinceId, $maxId);
|
||||
}
|
||||
|
||||
// Check the cache to see if we have the stream.
|
||||
|
||||
$idkey = Cache::key($this->cachekey);
|
||||
|
||||
$idstr = $cache->get($idkey);
|
||||
|
||||
if ($idstr !== false) {
|
||||
// Cache hit! Woohoo!
|
||||
$window = explode(',', $idstr);
|
||||
$ids = array_slice($window, $offset, $limit);
|
||||
return $ids;
|
||||
}
|
||||
|
||||
// Check the cache to see if we have a "last-known-good" version.
|
||||
// The actual cache gets blown away when new notices are added, but
|
||||
// the "last" value holds a lot of info. We might need to only generate
|
||||
// a few at the "tip", which can bound our queries and save lots
|
||||
// of time.
|
||||
|
||||
$laststr = $cache->get($idkey.';last');
|
||||
|
||||
if ($laststr !== false) {
|
||||
$window = explode(',', $laststr);
|
||||
$last_id = $window[0];
|
||||
$new_ids = $this->stream->getNoticeIds(0, self::CACHE_WINDOW, $last_id, 0);
|
||||
|
||||
$new_window = array_merge($new_ids, $window);
|
||||
|
||||
$new_windowstr = implode(',', $new_window);
|
||||
|
||||
$result = $cache->set($idkey, $new_windowstr);
|
||||
$result = $cache->set($idkey . ';last', $new_windowstr);
|
||||
|
||||
$ids = array_slice($new_window, $offset, $limit);
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
// No cache hits :( Generate directly and stick the results
|
||||
// into the cache. Note we generate the full cache window.
|
||||
|
||||
$window = $this->stream->getNoticeIds(0, self::CACHE_WINDOW, 0, 0);
|
||||
|
||||
$windowstr = implode(',', $window);
|
||||
|
||||
$result = $cache->set($idkey, $windowstr);
|
||||
$result = $cache->set($idkey . ';last', $windowstr);
|
||||
|
||||
// Return just the slice that was requested
|
||||
|
||||
$ids = array_slice($window, $offset, $limit);
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
@ -46,7 +46,6 @@ require_once INSTALLDIR.'/lib/form.php';
|
||||
*
|
||||
* @see UnsubscribeForm
|
||||
*/
|
||||
|
||||
class CancelGroupForm extends Form
|
||||
{
|
||||
/**
|
||||
@ -62,7 +61,6 @@ class CancelGroupForm extends Form
|
||||
* @param HTMLOutputter $out output channel
|
||||
* @param group $group group to leave
|
||||
*/
|
||||
|
||||
function __construct($out=null, $group=null, $profile=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
@ -76,7 +74,6 @@ class CancelGroupForm extends Form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
return 'group-cancel-' . $this->group->id;
|
||||
@ -87,7 +84,6 @@ class CancelGroupForm extends Form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_group_leave ajax';
|
||||
@ -98,7 +94,6 @@ class CancelGroupForm extends Form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
$params = array();
|
||||
@ -114,9 +109,9 @@ class CancelGroupForm extends Form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('submit', _('Cancel join request'));
|
||||
// TRANS: Submit button text on form to cancel group join request.
|
||||
$this->out->submit('submit', _m('BUTTON','Cancel join request'));
|
||||
}
|
||||
}
|
||||
|
124
lib/cancelsubscriptionform.php
Normal file
124
lib/cancelsubscriptionform.php
Normal file
@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Form for leaving a group
|
||||
*
|
||||
* 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 Form
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/form.php';
|
||||
|
||||
/**
|
||||
* Form for leaving a group
|
||||
*
|
||||
* @category Form
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see UnsubscribeForm
|
||||
*/
|
||||
class CancelSubscriptionForm extends Form
|
||||
{
|
||||
/**
|
||||
* user being subscribed to
|
||||
*/
|
||||
|
||||
var $profile = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param HTMLOutputter $out output channel
|
||||
* @param Profile $profile being subscribed to
|
||||
*/
|
||||
function __construct($out=null, $profile=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
|
||||
$this->profile = $profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
function id()
|
||||
{
|
||||
return 'subscription-cancel-' . $this->profile->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
function formClass()
|
||||
{
|
||||
return 'form_unsubscribe ajax';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
function action()
|
||||
{
|
||||
return common_local_url('cancelsubscription',
|
||||
array(),
|
||||
array('id' => $this->profile->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function formData()
|
||||
{
|
||||
$this->out->hidden('unsubscribeto-' . $this->profile->id,
|
||||
$this->profile->id,
|
||||
'unsubscribeto');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function formActions()
|
||||
{
|
||||
// TRANS: Button text for form action to cancel a subscription request.
|
||||
$this->out->submit('submit', _m('BUTTON','Cancel subscription request'));
|
||||
}
|
||||
}
|
@ -95,9 +95,9 @@ class WebChannel extends Channel
|
||||
|
||||
function output($user, $text)
|
||||
{
|
||||
# XXX: buffer all output and send it at the end
|
||||
# XXX: even better, redirect to appropriate page
|
||||
# depending on what command was run
|
||||
// XXX: buffer all output and send it at the end
|
||||
// XXX: even better, redirect to appropriate page
|
||||
// depending on what command was run
|
||||
$this->out->startHTML();
|
||||
$this->out->elementStart('head');
|
||||
// TRANS: Title for command results.
|
||||
|
@ -635,29 +635,15 @@ class RepeatCommand extends Command
|
||||
{
|
||||
$notice = $this->getNotice($this->other);
|
||||
|
||||
if($this->user->id == $notice->profile_id)
|
||||
{
|
||||
// TRANS: Error text shown when trying to repeat an own notice.
|
||||
$channel->error($this->user, _('Cannot repeat your own notice.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->user->getProfile()->hasRepeated($notice->id)) {
|
||||
// TRANS: Error text shown when trying to repeat an notice that was already repeated by the user.
|
||||
$channel->error($this->user, _('Already repeated that notice.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$repeat = $notice->repeat($this->user->id, $channel->source);
|
||||
|
||||
if ($repeat) {
|
||||
try {
|
||||
$repeat = $notice->repeat($this->user->id, $channel->source());
|
||||
$recipient = $notice->getProfile();
|
||||
|
||||
// TRANS: Message given having repeated a notice from another user.
|
||||
// TRANS: %s is the name of the user for which the notice was repeated.
|
||||
$channel->output($this->user, sprintf(_('Notice from %s repeated.'), $recipient->nickname));
|
||||
} else {
|
||||
// TRANS: Error text shown when repeating a notice fails with an unknown reason.
|
||||
$channel->error($this->user, _('Error repeating notice.'));
|
||||
} catch (Exception $e) {
|
||||
$channel->error($this->user, $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
106
lib/conversationnoticestream.php
Normal file
106
lib/conversationnoticestream.php
Normal file
@ -0,0 +1,106 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2011, StatusNet, Inc.
|
||||
*
|
||||
* Notice stream for a conversation
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* 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 Cache
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice stream for a conversation
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ConversationNoticeStream extends ScopingNoticeStream
|
||||
{
|
||||
function __construct($id)
|
||||
{
|
||||
parent::__construct(new CachingNoticeStream(new RawConversationNoticeStream($id),
|
||||
'notice:conversation_ids:'.$id));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice stream for a conversation
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class RawConversationNoticeStream extends NoticeStream
|
||||
{
|
||||
protected $id;
|
||||
|
||||
function __construct($id)
|
||||
{
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
function getNoticeIds($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->selectAdd(); // clears it
|
||||
$notice->selectAdd('id');
|
||||
|
||||
$notice->conversation = $this->id;
|
||||
|
||||
$notice->orderBy('created DESC, id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$notice->limit($offset, $limit);
|
||||
}
|
||||
|
||||
Notice::addWhereSinceId($notice, $since_id);
|
||||
Notice::addWhereMaxId($notice, $max_id);
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($notice->find()) {
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
@ -293,7 +293,8 @@ $default =
|
||||
array('enabled' => true,
|
||||
'css' => ''),
|
||||
'notice' =>
|
||||
array('contentlimit' => null),
|
||||
array('contentlimit' => null,
|
||||
'defaultscope' => 0), // set to 0 for default open
|
||||
'message' =>
|
||||
array('contentlimit' => null),
|
||||
'location' =>
|
||||
|
140
lib/favenoticestream.php
Normal file
140
lib/favenoticestream.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2011, StatusNet, Inc.
|
||||
*
|
||||
* Notice stream for favorites
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* 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 Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notice stream for favorites
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class FaveNoticeStream extends ScopingNoticeStream
|
||||
{
|
||||
function __construct($user_id, $own)
|
||||
{
|
||||
$stream = new RawFaveNoticeStream($user_id, $own);
|
||||
if ($own) {
|
||||
$key = 'fave:ids_by_user_own:'.$user_id;
|
||||
} else {
|
||||
$key = 'fave:ids_by_user:'.$user_id;
|
||||
}
|
||||
parent::__construct(new CachingNoticeStream($stream, $key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw notice stream for favorites
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class RawFaveNoticeStream extends NoticeStream
|
||||
{
|
||||
protected $user_id;
|
||||
protected $own;
|
||||
|
||||
function __construct($user_id, $own)
|
||||
{
|
||||
$this->user_id = $user_id;
|
||||
$this->own = $own;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note that the sorting for this is by order of *fave* not order of *notice*.
|
||||
*
|
||||
* @fixme add since_id, max_id support?
|
||||
*
|
||||
* @param <type> $user_id
|
||||
* @param <type> $own
|
||||
* @param <type> $offset
|
||||
* @param <type> $limit
|
||||
* @param <type> $since_id
|
||||
* @param <type> $max_id
|
||||
* @return <type>
|
||||
*/
|
||||
function getNoticeIds($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$fav = new Fave();
|
||||
$qry = null;
|
||||
|
||||
if ($this->own) {
|
||||
$qry = 'SELECT fave.* FROM fave ';
|
||||
$qry .= 'WHERE fave.user_id = ' . $this->user_id . ' ';
|
||||
} else {
|
||||
$qry = 'SELECT fave.* FROM fave ';
|
||||
$qry .= 'INNER JOIN notice ON fave.notice_id = notice.id ';
|
||||
$qry .= 'WHERE fave.user_id = ' . $this->user_id . ' ';
|
||||
$qry .= 'AND notice.is_local != ' . Notice::GATEWAY . ' ';
|
||||
}
|
||||
|
||||
if ($since_id != 0) {
|
||||
$qry .= 'AND notice_id > ' . $since_id . ' ';
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$qry .= 'AND notice_id <= ' . $max_id . ' ';
|
||||
}
|
||||
|
||||
// NOTE: we sort by fave time, not by notice time!
|
||||
|
||||
$qry .= 'ORDER BY modified DESC ';
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$qry .= "LIMIT $limit OFFSET $offset";
|
||||
}
|
||||
|
||||
$fav->query($qry);
|
||||
|
||||
$ids = array();
|
||||
|
||||
while ($fav->fetch()) {
|
||||
$ids[] = $fav->notice_id;
|
||||
}
|
||||
|
||||
$fav->free();
|
||||
unset($fav);
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
||||
|
105
lib/filenoticestream.php
Normal file
105
lib/filenoticestream.php
Normal file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2011, StatusNet, Inc.
|
||||
*
|
||||
* Stream of notices that reference an URL
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* 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 Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
class FileNoticeStream extends ScopingNoticeStream
|
||||
{
|
||||
function __construct($file)
|
||||
{
|
||||
parent::__construct(new CachingNoticeStream(new RawFileNoticeStream($file),
|
||||
'file:notice-ids:'.$this->url));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw stream for a file
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class RawFileNoticeStream extends NoticeStream
|
||||
{
|
||||
protected $file = null;
|
||||
|
||||
function __construct($file)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream of notices linking to this URL
|
||||
*
|
||||
* @param integer $offset Offset to show; default is 0
|
||||
* @param integer $limit Limit of notices to show
|
||||
* @param integer $since_id Since this notice
|
||||
* @param integer $max_id Before this notice
|
||||
*
|
||||
* @return array ids of notices that link to this file
|
||||
*/
|
||||
function getNoticeIds($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$f2p = new File_to_post();
|
||||
|
||||
$f2p->selectAdd();
|
||||
$f2p->selectAdd('post_id');
|
||||
|
||||
$f2p->file_id = $this->file->id;
|
||||
|
||||
Notice::addWhereSinceId($f2p, $since_id, 'post_id', 'modified');
|
||||
Notice::addWhereMaxId($f2p, $max_id, 'post_id', 'modified');
|
||||
|
||||
$f2p->orderBy('modified DESC, post_id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$f2p->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($f2p->find()) {
|
||||
while ($f2p->fetch()) {
|
||||
$ids[] = $f2p->post_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
115
lib/filteringnoticestream.php
Normal file
115
lib/filteringnoticestream.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2011, StatusNet, Inc.
|
||||
*
|
||||
* A notice stream that filters its upstream content
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* 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 Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* A class for presenting a filtered notice stream based on an upstream stream
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
abstract class FilteringNoticeStream extends NoticeStream
|
||||
{
|
||||
protected $upstream;
|
||||
|
||||
function __construct($upstream)
|
||||
{
|
||||
$this->upstream = $upstream;
|
||||
}
|
||||
|
||||
abstract function filter($notice);
|
||||
|
||||
function getNotices($offset, $limit, $sinceId, $maxId)
|
||||
{
|
||||
// "offset" is virtual; we have to get a lot
|
||||
$total = $offset + $limit;
|
||||
|
||||
$filtered = array();
|
||||
|
||||
$startAt = 0;
|
||||
$askFor = $total;
|
||||
|
||||
// Keep going till we have $total notices in $notices array,
|
||||
// or we get nothing from upstream.
|
||||
|
||||
$results = null;
|
||||
|
||||
do {
|
||||
|
||||
$raw = $this->upstream->getNotices($startAt, $askFor, $sinceId, $maxId);
|
||||
|
||||
$results = $raw->N;
|
||||
|
||||
if ($results == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
while ($raw->fetch()) {
|
||||
if ($this->filter($raw)) {
|
||||
$filtered[] = clone($raw);
|
||||
if (count($filtered) >= $total) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: make these smarter; factor hit rate into $askFor
|
||||
|
||||
$startAt += $askFor;
|
||||
$askFor = max($total - count($filtered), NOTICES_PER_PAGE);
|
||||
|
||||
} while (count($filtered) < $total && $results !== 0);
|
||||
|
||||
return new ArrayWrapper(array_slice($filtered, $offset, $limit));
|
||||
}
|
||||
|
||||
function getNoticeIds($offset, $limit, $sinceId, $maxId)
|
||||
{
|
||||
$notices = $this->getNotices($offset, $limit, $sinceId, $maxId);
|
||||
|
||||
$ids = array();
|
||||
|
||||
while ($notices->fetch()) {
|
||||
$ids[] = $notices->id;
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
@ -49,7 +49,7 @@ define('NOTICE_INBOX_SOURCE_FORWARD', 4);
|
||||
define('NOTICE_INBOX_SOURCE_PROFILE_TAG', 5);
|
||||
define('NOTICE_INBOX_SOURCE_GATEWAY', -1);
|
||||
|
||||
# append our extlib dir as the last-resort place to find libs
|
||||
// append our extlib dir as the last-resort place to find libs
|
||||
|
||||
set_include_path(get_include_path() . PATH_SEPARATOR . INSTALLDIR . '/extlib/');
|
||||
|
||||
@ -70,7 +70,7 @@ if (!function_exists('dl')) {
|
||||
}
|
||||
}
|
||||
|
||||
# global configuration object
|
||||
// global configuration object
|
||||
|
||||
require_once('PEAR.php');
|
||||
require_once('PEAR/Exception.php');
|
||||
|
@ -84,7 +84,7 @@ class GalleryAction extends OwnerDesignAction
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
# Post from the tag dropdown; redirect to a GET
|
||||
// Post from the tag dropdown; redirect to a GET
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
common_redirect($this->selfUrl(), 303);
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
|
||||
// @todo FIXME: standard file header missing.
|
||||
/**
|
||||
* Form for blocking a user from a group
|
||||
*
|
||||
|
@ -112,6 +112,7 @@ class GroupEditForm extends Form
|
||||
*/
|
||||
function formLegend()
|
||||
{
|
||||
// TRANS: Form legend for group edit form.
|
||||
$this->out->element('legend', null, _('Create a new group'));
|
||||
}
|
||||
|
||||
@ -142,44 +143,58 @@ class GroupEditForm extends Form
|
||||
if (Event::handle('StartGroupEditFormData', array($this))) {
|
||||
$this->out->elementStart('li');
|
||||
$this->out->hidden('groupid', $id);
|
||||
// TRANS: Field label on group edit form.
|
||||
$this->out->input('nickname', _('Nickname'),
|
||||
($this->out->arg('nickname')) ? $this->out->arg('nickname') : $nickname,
|
||||
_('1-64 lowercase letters or numbers, no punctuation or spaces'));
|
||||
// TRANS: Field title on group edit form.
|
||||
_('1-64 lowercase letters or numbers, no punctuation or spaces.'));
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
// TRANS: Field label on group edit form.
|
||||
$this->out->input('fullname', _('Full name'),
|
||||
($this->out->arg('fullname')) ? $this->out->arg('fullname') : $fullname);
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
// TRANS: Field label on group edit form; points to "more info" for a group.
|
||||
$this->out->input('homepage', _('Homepage'),
|
||||
($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage,
|
||||
// TRANS: Field title on group edit form.
|
||||
_('URL of the homepage or blog of the group or topic.'));
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
$desclimit = User_group::maxDescription();
|
||||
if ($desclimit == 0) {
|
||||
$descinstr = _('Describe the group or topic');
|
||||
// TRANS: Text area title for group description when there is no text limit.
|
||||
$descinstr = _('Describe the group or topic.');
|
||||
} else {
|
||||
$descinstr = sprintf(_m('Describe the group or topic in %d character or less',
|
||||
'Describe the group or topic in %d characters or less',
|
||||
// TRANS: Text area title for group description.
|
||||
// TRANS: %d is the number of characters available for the description.
|
||||
$descinstr = sprintf(_m('Describe the group or topic in %d character or less.',
|
||||
'Describe the group or topic in %d characters or less.',
|
||||
$desclimit),
|
||||
$desclimit);
|
||||
}
|
||||
// TRANS: Text area label on group edit form; contains description of group.
|
||||
$this->out->textarea('description', _('Description'),
|
||||
($this->out->arg('description')) ? $this->out->arg('description') : $description,
|
||||
$descinstr);
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
// TRANS: Field label on group edit form.
|
||||
$this->out->input('location', _('Location'),
|
||||
($this->out->arg('location')) ? $this->out->arg('location') : $location,
|
||||
// TRANS: Field title on group edit form.
|
||||
_('Location for the group, if any, like "City, State (or Region), Country".'));
|
||||
$this->out->elementEnd('li');
|
||||
if (common_config('group', 'maxaliases') > 0) {
|
||||
$aliases = (empty($this->group)) ? array() : $this->group->getAliases();
|
||||
$this->out->elementStart('li');
|
||||
// TRANS: Field label on group edit form.
|
||||
$this->out->input('aliases', _('Aliases'),
|
||||
($this->out->arg('aliases')) ? $this->out->arg('aliases') :
|
||||
(!empty($aliases)) ? implode(' ', $aliases) : '',
|
||||
// TRANS: Input field title for group aliases.
|
||||
// TRANS: %d is the maximum number of group aliases available.
|
||||
sprintf(_m('Extra nicknames for the group, separated with commas or spaces. Maximum %d alias allowed.',
|
||||
'Extra nicknames for the group, separated with commas or spaces. Maximum %d aliases allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
@ -188,9 +203,11 @@ class GroupEditForm extends Form
|
||||
}
|
||||
$this->out->elementStart('li');
|
||||
$this->out->dropdown('join_policy',
|
||||
// TRANS: Dropdown fieldd label on group edit form.
|
||||
_('Membership policy'),
|
||||
array(User_group::JOIN_POLICY_OPEN => _('Open to all'),
|
||||
User_group::JOIN_POLICY_MODERATE => _('Admin must approve all members')),
|
||||
// TRANS: Dropdown field title on group edit form.
|
||||
_('Whether admin approval is required to join this group.'),
|
||||
false,
|
||||
(empty($this->group->join_policy)) ? User_group::JOIN_POLICY_OPEN : $this->group->join_policy);
|
||||
@ -207,6 +224,7 @@ class GroupEditForm extends Form
|
||||
*/
|
||||
function formActions()
|
||||
{
|
||||
// TRANS: Text for save button on group edit form.
|
||||
$this->out->submit('submit', _m('BUTTON','Save'));
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ class GroupList extends Widget
|
||||
$this->out->elementEnd('p');
|
||||
}
|
||||
|
||||
# If we're on a list with an owner (subscriptions or subscribers)...
|
||||
// If we're on a list with an owner (subscriptions or subscribers)...
|
||||
|
||||
if (!empty($user) && !empty($this->owner) && $user->id == $this->owner->id) {
|
||||
$this->showOwnerControls();
|
||||
@ -149,8 +149,8 @@ class GroupList extends Widget
|
||||
$this->out->elementStart('div', 'entity_actions');
|
||||
$this->out->elementStart('ul');
|
||||
$this->out->elementStart('li', 'entity_subscribe');
|
||||
# XXX: special-case for user looking at own
|
||||
# subscriptions page
|
||||
// XXX: special-case for user looking at own
|
||||
// subscriptions page
|
||||
if ($user->isMember($this->group)) {
|
||||
$lf = new LeaveForm($this->out, $this->group);
|
||||
$lf->show();
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
// @todo FIXME: add documentation.
|
||||
|
||||
class GroupMemberList extends ProfileList
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
// @todo FIXME: add documentation.
|
||||
|
||||
class GroupMemberListItem extends ProfileListItem
|
||||
{
|
||||
@ -17,7 +18,7 @@ class GroupMemberListItem extends ProfileListItem
|
||||
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'));
|
||||
$this->out->element('span', 'role', _m('GROUPADMIN','Admin'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,4 +103,3 @@ class GroupMemberListItem extends ProfileListItem
|
||||
return $args;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,6 @@ require_once INSTALLDIR.'/lib/widget.php';
|
||||
*
|
||||
* @see HTMLOutputter
|
||||
*/
|
||||
|
||||
class GroupNav extends Menu
|
||||
{
|
||||
var $group = null;
|
||||
@ -58,7 +57,6 @@ class GroupNav extends Menu
|
||||
*
|
||||
* @param Action $action current action, used for output
|
||||
*/
|
||||
|
||||
function __construct($action=null, $group=null)
|
||||
{
|
||||
parent::__construct($action);
|
||||
@ -70,7 +68,6 @@ class GroupNav extends Menu
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function show()
|
||||
{
|
||||
$action_name = $this->action->trimmed('action');
|
||||
@ -105,7 +102,8 @@ class GroupNav extends Menu
|
||||
$this->out->menuItem(common_local_url('groupqueue', array('nickname' =>
|
||||
$nickname)),
|
||||
// TRANS: Menu item in the group navigation page. Only shown for group administrators.
|
||||
sprintf(_m('MENU','Pending members (%d)'), $pending),
|
||||
// TRANS: %d is the number of pending members.
|
||||
sprintf(_m('MENU','Pending members (%d)','Pending members (%d)',$pending), $pending),
|
||||
// TRANS: Tooltip for menu item in the group navigation page. Only shown for group administrators.
|
||||
// TRANS: %s is the nickname of the group.
|
||||
sprintf(_m('TOOLTIP','%s pending members'), $nickname),
|
||||
|
103
lib/groupnoticestream.php
Normal file
103
lib/groupnoticestream.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2011, StatusNet, Inc.
|
||||
*
|
||||
* Stream of notices for a group
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* 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 Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
// This check helps protect against security problems;
|
||||
// your code file can't be executed directly from the web.
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream of notices for a group
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class GroupNoticeStream extends ScopingNoticeStream
|
||||
{
|
||||
function __construct($group)
|
||||
{
|
||||
parent::__construct(new CachingNoticeStream(new RawGroupNoticeStream($group),
|
||||
'user_group:notice_ids:' . $group->id));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream of notices for a group
|
||||
*
|
||||
* @category Stream
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2011 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class RawGroupNoticeStream extends NoticeStream
|
||||
{
|
||||
protected $group;
|
||||
|
||||
function __construct($group)
|
||||
{
|
||||
$this->group = $group;
|
||||
}
|
||||
|
||||
function getNoticeIds($offset, $limit, $since_id, $max_id)
|
||||
{
|
||||
$inbox = new Group_inbox();
|
||||
|
||||
$inbox->group_id = $this->group->id;
|
||||
|
||||
$inbox->selectAdd();
|
||||
$inbox->selectAdd('notice_id');
|
||||
|
||||
Notice::addWhereSinceId($inbox, $since_id, 'notice_id');
|
||||
Notice::addWhereMaxId($inbox, $max_id, 'notice_id');
|
||||
|
||||
$inbox->orderBy('created DESC, notice_id DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$inbox->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($inbox->find()) {
|
||||
while ($inbox->fetch()) {
|
||||
$ids[] = $inbox->notice_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
@ -482,7 +482,10 @@ abstract class ImPlugin extends Plugin
|
||||
$body = trim(strip_tags($body));
|
||||
$content_shortened = common_shorten_links($body);
|
||||
if (Notice::contentTooLong($content_shortened)) {
|
||||
$this->sendFromSite($screenname, sprintf(_('Message too long - maximum is %1$d characters, you sent %2$d.'),
|
||||
$this->sendFromSite($screenname,
|
||||
sprintf(_m('Message too long - maximum is %1$d character, you sent %2$d.',
|
||||
'Message too long - maximum is %1$d characters, you sent %2$d.',
|
||||
Notice::maxContent()),
|
||||
Notice::maxContent(),
|
||||
mb_strlen($content_shortened)));
|
||||
return;
|
||||
|
299
lib/mail.php
299
lib/mail.php
@ -245,44 +245,13 @@ function mail_subscribe_notify_profile($listenee, $other)
|
||||
$other->getBestName(),
|
||||
common_config('site', 'name'));
|
||||
|
||||
// TRANS: This is a paragraph in a new-subscriber e-mail.
|
||||
// TRANS: %s is a URL where the subscriber can be reported as abusive.
|
||||
$blocklink = sprintf(_("If you believe this account is being used abusively, " .
|
||||
"you can block them from your subscribers list and " .
|
||||
"report as spam to site administrators at %s"),
|
||||
common_local_url('block', array('profileid' => $other->id)));
|
||||
|
||||
// TRANS: Main body of new-subscriber notification e-mail.
|
||||
// TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename,
|
||||
// TRANS: %3$s is the subscriber's profile URL, %4$s is the subscriber's location (or empty)
|
||||
// TRANS: %5$s is the subscriber's homepage URL (or empty), %6%s is the subscriber's bio (or empty)
|
||||
// TRANS: %7$s is a link to the addressed user's e-mail settings.
|
||||
$body = sprintf(_('%1$s is now listening to your notices on %2$s.'."\n\n".
|
||||
"\t".'%3$s'."\n\n".
|
||||
'%4$s'.
|
||||
'%5$s'.
|
||||
'%6$s'.
|
||||
"\n".'Faithfully yours,'."\n".'%2$s.'."\n\n".
|
||||
"----\n".
|
||||
"Change your email address or ".
|
||||
"notification options at ".'%7$s' ."\n"),
|
||||
// TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename.
|
||||
$body = sprintf(_('%1$s is now listening to your notices on %2$s.'),
|
||||
$long_name,
|
||||
common_config('site', 'name'),
|
||||
$other->profileurl,
|
||||
($other->location) ?
|
||||
// TRANS: Profile info line in new-subscriber notification e-mail.
|
||||
// TRANS: %s is a location.
|
||||
sprintf(_("Location: %s"), $other->location) . "\n" : '',
|
||||
($other->homepage) ?
|
||||
// TRANS: Profile info line in new-subscriber notification e-mail.
|
||||
// TRANS: %s is a homepage.
|
||||
sprintf(_("Homepage: %s"), $other->homepage) . "\n" : '',
|
||||
(($other->bio) ?
|
||||
// TRANS: Profile info line in new-subscriber notification e-mail.
|
||||
// TRANS: %s is biographical information.
|
||||
sprintf(_("Bio: %s"), $other->bio) . "\n" : '') .
|
||||
"\n\n" . $blocklink . "\n",
|
||||
common_local_url('emailsettings'));
|
||||
common_config('site', 'name')) .
|
||||
mail_profile_block($other) .
|
||||
mail_footer_block();
|
||||
|
||||
// reset localization
|
||||
common_switch_locale();
|
||||
@ -290,6 +259,112 @@ function mail_subscribe_notify_profile($listenee, $other)
|
||||
}
|
||||
}
|
||||
|
||||
function mail_subscribe_pending_notify_profile($listenee, $other)
|
||||
{
|
||||
if ($other->hasRight(Right::EMAILONSUBSCRIBE) &&
|
||||
$listenee->email && $listenee->emailnotifysub) {
|
||||
|
||||
$profile = $listenee->getProfile();
|
||||
|
||||
$name = $profile->getBestName();
|
||||
|
||||
$long_name = ($other->fullname) ?
|
||||
($other->fullname . ' (' . $other->nickname . ')') : $other->nickname;
|
||||
|
||||
$recipients = $listenee->email;
|
||||
|
||||
// use the recipient's localization
|
||||
common_switch_locale($listenee->language);
|
||||
|
||||
$headers = _mail_prepare_headers('subscribe', $listenee->nickname, $other->nickname);
|
||||
$headers['From'] = mail_notify_from();
|
||||
$headers['To'] = $name . ' <' . $listenee->email . '>';
|
||||
// TRANS: Subject of pending new-subscriber notification e-mail.
|
||||
// TRANS: %1$s is the subscribing user's nickname, %2$s is the StatusNet sitename.
|
||||
$headers['Subject'] = sprintf(_('%1$s would like to listen to '.
|
||||
'your notices on %2$s.'),
|
||||
$other->getBestName(),
|
||||
common_config('site', 'name'));
|
||||
|
||||
// TRANS: Main body of pending new-subscriber notification e-mail.
|
||||
// TRANS: %1$s is the subscriber's long name, %2$s is the StatusNet sitename.
|
||||
$body = sprintf(_('%1$s would like to listen to your notices on %2$s. ' .
|
||||
'You may approve or reject their subscription at %3$s'),
|
||||
$long_name,
|
||||
common_config('site', 'name'),
|
||||
common_local_url('subqueue', array('nickname' => $listenee->nickname))) .
|
||||
mail_profile_block($other) .
|
||||
mail_footer_block();
|
||||
|
||||
// reset localization
|
||||
common_switch_locale();
|
||||
mail_send($recipients, $headers, $body);
|
||||
}
|
||||
}
|
||||
|
||||
function mail_footer_block()
|
||||
{
|
||||
// TRANS: Common footer block for StatusNet notification emails.
|
||||
// TRANS: %1$s is the StatusNet sitename,
|
||||
// TRANS: %2$s is a link to the addressed user's e-mail settings.
|
||||
return "\n\n" . sprintf(_('Faithfully yours,'.
|
||||
"\n".'%1$s.'."\n\n".
|
||||
"----\n".
|
||||
"Change your email address or ".
|
||||
"notification options at ".'%2$s'),
|
||||
common_config('site', 'name'),
|
||||
common_local_url('emailsettings')) . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a block of profile info for a plaintext notification email.
|
||||
*
|
||||
* @param Profile $profile
|
||||
* @return string
|
||||
*/
|
||||
function mail_profile_block($profile)
|
||||
{
|
||||
// TRANS: Layout for
|
||||
// TRANS: %1$s is the subscriber's profile URL, %2$s is the subscriber's location (or empty)
|
||||
// TRANS: %3$s is the subscriber's homepage URL (or empty), %4%s is the subscriber's bio (or empty)
|
||||
$out = array();
|
||||
$out[] = "";
|
||||
$out[] = "";
|
||||
// TRANS: Profile info line in notification e-mail.
|
||||
// TRANS: %s is a URL.
|
||||
$out[] = sprintf(_("Profile: %s"), $profile->profileurl);
|
||||
if ($profile->location) {
|
||||
// TRANS: Profile info line in notification e-mail.
|
||||
// TRANS: %s is a location.
|
||||
$out[] = sprintf(_("Location: %s"), $profile->location);
|
||||
}
|
||||
if ($profile->homepage) {
|
||||
// TRANS: Profile info line in notification e-mail.
|
||||
// TRANS: %s is a homepage.
|
||||
$out[] = sprintf(_("Homepage: %s"), $profile->homepage);
|
||||
}
|
||||
if ($profile->bio) {
|
||||
// TRANS: Profile info line in notification e-mail.
|
||||
// TRANS: %s is biographical information.
|
||||
$out[] = sprintf(_("Bio: %s"), $profile->bio);
|
||||
}
|
||||
|
||||
$blocklink = common_local_url('block', array('profileid' => $profile->id));
|
||||
// This'll let ModPlus add the remote profile info so it's possible
|
||||
// to block remote users directly...
|
||||
Event::handle('MailProfileInfoBlockLink', array($profile, &$blocklink));
|
||||
|
||||
// TRANS: This is a paragraph in a new-subscriber e-mail.
|
||||
// TRANS: %s is a URL where the subscriber can be reported as abusive.
|
||||
$out[] = sprintf(_('If you believe this account is being used abusively, ' .
|
||||
'you can block them from your subscribers list and ' .
|
||||
'report as spam to site administrators at %s.'),
|
||||
$blocklink);
|
||||
$out[] = "";
|
||||
|
||||
return implode("\n", $out);
|
||||
}
|
||||
|
||||
/**
|
||||
* notify a user of their new incoming email address
|
||||
*
|
||||
@ -317,11 +392,11 @@ function mail_new_incoming_notify($user)
|
||||
// TRANS: to to post by e-mail, %3$s is a URL to more instructions.
|
||||
$body = sprintf(_("You have a new posting address on %1\$s.\n\n".
|
||||
"Send email to %2\$s to post new messages.\n\n".
|
||||
"More email instructions at %3\$s.\n\n".
|
||||
"Faithfully yours,\n%1\$s"),
|
||||
"More email instructions at %3\$s."),
|
||||
common_config('site', 'name'),
|
||||
$user->incomingemail,
|
||||
common_local_url('doc', array('title' => 'email')));
|
||||
common_local_url('doc', array('title' => 'email'))) .
|
||||
mail_footer_block();
|
||||
|
||||
mail_send($user->email, $headers, $body);
|
||||
}
|
||||
@ -466,7 +541,7 @@ function mail_confirm_sms($code, $nickname, $address)
|
||||
|
||||
// TRANS: Main body heading for SMS-by-email address confirmation message.
|
||||
// TRANS: %s is the addressed user's nickname.
|
||||
$body = sprintf(_("%s: confirm you own this phone number with this code:"), $nickname);
|
||||
$body = sprintf(_('%s: confirm you own this phone number with this code:'), $nickname);
|
||||
$body .= "\n\n";
|
||||
$body .= $code;
|
||||
$body .= "\n\n";
|
||||
@ -493,18 +568,16 @@ function mail_notify_nudge($from, $to)
|
||||
|
||||
// TRANS: Body for 'nudge' notification email.
|
||||
// TRANS: %1$s is the nuding user's long name, $2$s is the nudging user's nickname,
|
||||
// TRANS: %3$s is a URL to post notices at, %4$s is the StatusNet sitename.
|
||||
// TRANS: %3$s is a URL to post notices at.
|
||||
$body = sprintf(_("%1\$s (%2\$s) is wondering what you are up to ".
|
||||
"these days and is inviting you to post some news.\n\n".
|
||||
"So let's hear from you :)\n\n".
|
||||
"%3\$s\n\n".
|
||||
"Don't reply to this email; it won't get to them.\n\n".
|
||||
"With kind regards,\n".
|
||||
"%4\$s\n"),
|
||||
"Don't reply to this email; it won't get to them."),
|
||||
$from_profile->getBestName(),
|
||||
$from->nickname,
|
||||
common_local_url('all', array('nickname' => $to->nickname)),
|
||||
common_config('site', 'name'));
|
||||
common_local_url('all', array('nickname' => $to->nickname))) .
|
||||
mail_footer_block();
|
||||
common_switch_locale();
|
||||
|
||||
$headers = _mail_prepare_headers('nudge', $to->nickname, $from->nickname);
|
||||
@ -548,21 +621,18 @@ function mail_notify_message($message, $from=null, $to=null)
|
||||
// TRANS: Body for direct-message notification email.
|
||||
// TRANS: %1$s is the sending user's long name, %2$s is the sending user's nickname,
|
||||
// TRANS: %3$s is the message content, %4$s a URL to the message,
|
||||
// TRANS: %5$s is the StatusNet sitename.
|
||||
$body = sprintf(_("%1\$s (%2\$s) sent you a private message:\n\n".
|
||||
"------------------------------------------------------\n".
|
||||
"%3\$s\n".
|
||||
"------------------------------------------------------\n\n".
|
||||
"You can reply to their message here:\n\n".
|
||||
"%4\$s\n\n".
|
||||
"Don't reply to this email; it won't get to them.\n\n".
|
||||
"With kind regards,\n".
|
||||
"%5\$s\n"),
|
||||
"Don't reply to this email; it won't get to them."),
|
||||
$from_profile->getBestName(),
|
||||
$from->nickname,
|
||||
$message->content,
|
||||
common_local_url('newmessage', array('to' => $from->id)),
|
||||
common_config('site', 'name'));
|
||||
common_local_url('newmessage', array('to' => $from->id))) .
|
||||
mail_footer_block();
|
||||
|
||||
$headers = _mail_prepare_headers('message', $to->nickname, $from->nickname);
|
||||
|
||||
@ -571,7 +641,7 @@ function mail_notify_message($message, $from=null, $to=null)
|
||||
}
|
||||
|
||||
/**
|
||||
* notify a user that one of their notices has been chosen as a 'fave'
|
||||
* Notify a user that one of their notices has been chosen as a 'fave'
|
||||
*
|
||||
* Doesn't check that the user has an email address nor if they
|
||||
* want to receive notification of faves. Maybe this happens higher
|
||||
@ -615,9 +685,7 @@ function mail_notify_fave($other, $user, $notice)
|
||||
"The text of your notice is:\n\n" .
|
||||
"%4\$s\n\n" .
|
||||
"You can see the list of %1\$s's favorites here:\n\n" .
|
||||
"%5\$s\n\n" .
|
||||
"Faithfully yours,\n" .
|
||||
"%6\$s\n"),
|
||||
"%5\$s"),
|
||||
$bestname,
|
||||
common_exact_date($notice->created),
|
||||
common_local_url('shownotice',
|
||||
@ -626,7 +694,8 @@ function mail_notify_fave($other, $user, $notice)
|
||||
common_local_url('showfavorites',
|
||||
array('nickname' => $user->nickname)),
|
||||
common_config('site', 'name'),
|
||||
$user->nickname);
|
||||
$user->nickname) .
|
||||
mail_footer_block();
|
||||
|
||||
$headers = _mail_prepare_headers('fave', $other->nickname, $user->nickname);
|
||||
|
||||
@ -635,7 +704,7 @@ function mail_notify_fave($other, $user, $notice)
|
||||
}
|
||||
|
||||
/**
|
||||
* notify a user that they have received an "attn:" message AKA "@-reply"
|
||||
* Notify a user that they have received an "attn:" message AKA "@-reply"
|
||||
*
|
||||
* @param User $user The user who recevied the notice
|
||||
* @param Notice $notice The notice that was sent
|
||||
@ -677,12 +746,11 @@ function mail_notify_attn($user, $notice)
|
||||
$subject = sprintf(_('%1$s (@%2$s) sent a notice to your attention'), $bestname, $sender->nickname);
|
||||
|
||||
// TRANS: Body of @-reply notification e-mail.
|
||||
// TRANS: %1$s is the sending user's long name, $2$s is the StatusNet sitename,
|
||||
// TRANS: %1$s is the sending user's name, $2$s is the StatusNet sitename,
|
||||
// TRANS: %3$s is a URL to the notice, %4$s is the notice text,
|
||||
// TRANS: %5$s is a URL to the full conversion if it exists (otherwise empty),
|
||||
// TRANS: %6$s is a URL to reply to the notice, %7$s is a URL to all @-replied for the addressed user,
|
||||
// TRANS: %8$s is a URL to the addressed user's e-mail settings, %9$s is the sender's nickname.
|
||||
$body = sprintf(_("%1\$s (@%9\$s) just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
|
||||
// TRANS: %6$s is a URL to reply to the notice, %7$s is a URL to all @-replies for the addressed user,
|
||||
$body = sprintf(_("%1\$s just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
|
||||
"The notice is here:\n\n".
|
||||
"\t%3\$s\n\n" .
|
||||
"It reads:\n\n".
|
||||
@ -691,11 +759,8 @@ function mail_notify_attn($user, $notice)
|
||||
"You can reply back here:\n\n".
|
||||
"\t%6\$s\n\n" .
|
||||
"The list of all @-replies for you here:\n\n" .
|
||||
"%7\$s\n\n" .
|
||||
"Faithfully yours,\n" .
|
||||
"%2\$s\n\n" .
|
||||
"P.S. You can turn off these email notifications here: %8\$s\n"),
|
||||
$bestname,//%1
|
||||
"%7\$s"),
|
||||
$sender->getFancyName(),//%1
|
||||
common_config('site', 'name'),//%2
|
||||
common_local_url('shownotice',
|
||||
array('notice' => $notice->id)),//%3
|
||||
@ -704,10 +769,8 @@ function mail_notify_attn($user, $notice)
|
||||
common_local_url('newnotice',
|
||||
array('replyto' => $sender->nickname, 'inreplyto' => $notice->id)),//%6
|
||||
common_local_url('replies',
|
||||
array('nickname' => $user->nickname)),//%7
|
||||
common_local_url('emailsettings'), //%8
|
||||
$sender->nickname); //%9
|
||||
|
||||
array('nickname' => $user->nickname))) . //%7
|
||||
mail_footer_block();
|
||||
$headers = _mail_prepare_headers('mention', $user->nickname, $sender->nickname);
|
||||
|
||||
common_switch_locale();
|
||||
@ -734,3 +797,97 @@ function _mail_prepare_headers($msg_type, $to, $from)
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notification emails to group administrator.
|
||||
*
|
||||
* @param User_group $group
|
||||
* @param Profile $joiner
|
||||
*/
|
||||
function mail_notify_group_join($group, $joiner)
|
||||
{
|
||||
// This returns a Profile query...
|
||||
$admin = $group->getAdmins();
|
||||
while ($admin->fetch()) {
|
||||
// We need a local user for email notifications...
|
||||
$adminUser = User::staticGet('id', $admin->id);
|
||||
// @fixme check for email preference?
|
||||
if ($adminUser && $adminUser->email) {
|
||||
// use the recipient's localization
|
||||
common_switch_locale($adminUser->language);
|
||||
|
||||
$headers = _mail_prepare_headers('join', $admin->nickname, $joiner->nickname);
|
||||
$headers['From'] = mail_notify_from();
|
||||
$headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>';
|
||||
// TRANS: Subject of group join notification e-mail.
|
||||
// TRANS: %1$s is the joining user's nickname, %2$s is the group name, and %3$s is the StatusNet sitename.
|
||||
$headers['Subject'] = sprintf(_('%1$s has joined '.
|
||||
'your group %2$s on %3$s.'),
|
||||
$joiner->getBestName(),
|
||||
$group->getBestName(),
|
||||
common_config('site', 'name'));
|
||||
|
||||
// TRANS: Main body of group join notification e-mail.
|
||||
// TRANS: %1$s is the subscriber's long name, %2$s is the group name, and %3$s is the StatusNet sitename,
|
||||
// TRANS: %4$s is a block of profile info about the subscriber.
|
||||
// TRANS: %5$s is a link to the addressed user's e-mail settings.
|
||||
$body = sprintf(_('%1$s has joined your group %2$s on %3$s.'),
|
||||
$joiner->getFancyName(),
|
||||
$group->getFancyName(),
|
||||
common_config('site', 'name')) .
|
||||
mail_profile_block($joiner) .
|
||||
mail_footer_block();
|
||||
|
||||
// reset localization
|
||||
common_switch_locale();
|
||||
mail_send($adminUser->email, $headers, $body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send notification emails to group administrator.
|
||||
*
|
||||
* @param User_group $group
|
||||
* @param Profile $joiner
|
||||
*/
|
||||
function mail_notify_group_join_pending($group, $joiner)
|
||||
{
|
||||
$admin = $group->getAdmins();
|
||||
while ($admin->fetch()) {
|
||||
// We need a local user for email notifications...
|
||||
$adminUser = User::staticGet('id', $admin->id);
|
||||
// @fixme check for email preference?
|
||||
if ($adminUser && $adminUser->email) {
|
||||
// use the recipient's localization
|
||||
common_switch_locale($adminUser->language);
|
||||
|
||||
$headers = _mail_prepare_headers('join', $admin->nickname, $joiner->nickname);
|
||||
$headers['From'] = mail_notify_from();
|
||||
$headers['To'] = $admin->getBestName() . ' <' . $adminUser->email . '>';
|
||||
// TRANS: Subject of pending group join request notification e-mail.
|
||||
// TRANS: %1$s is the joining user's nickname, %2$s is the group name, and %3$s is the StatusNet sitename.
|
||||
$headers['Subject'] = sprintf(_('%1$s wants to join your group %2$s on %3$s.'),
|
||||
$joiner->getBestName(),
|
||||
$group->getBestName(),
|
||||
common_config('site', 'name'));
|
||||
|
||||
// TRANS: Main body of pending group join request notification e-mail.
|
||||
// TRANS: %1$s is the subscriber's long name, %2$s is the group name, and %3$s is the StatusNet sitename,
|
||||
// TRANS: %4$s is the URL to the moderation queue page.
|
||||
$body = sprintf(_('%1$s would like to join your group %2$s on %3$s. ' .
|
||||
'You may approve or reject their group membership at %4$s'),
|
||||
$joiner->getFancyName(),
|
||||
$group->getFancyName(),
|
||||
common_config('site', 'name'),
|
||||
common_local_url('groupqueue', array('nickname' => $group->nickname))) .
|
||||
mail_profile_block($joiner) .
|
||||
mail_footer_block();
|
||||
|
||||
// reset localization
|
||||
common_switch_locale();
|
||||
mail_send($adminUser->email, $headers, $body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ require_once(INSTALLDIR . '/lib/mail.php');
|
||||
require_once(INSTALLDIR . '/lib/mediafile.php');
|
||||
require_once('Mail/mimeDecode.php');
|
||||
|
||||
# FIXME: we use both Mail_mimeDecode and mailparse
|
||||
# Need to move everything to mailparse
|
||||
// FIXME: we use both Mail_mimeDecode and mailparse
|
||||
// Need to move everything to mailparse
|
||||
|
||||
class MailHandler
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?php
|
||||
// @todo FIXME: add standard file header.
|
||||
|
||||
/**
|
||||
* Form for making a user an admin for a group
|
||||
|
@ -512,7 +512,7 @@ abstract class MicroAppPlugin extends Plugin
|
||||
function onEndActivityObjectOutputJson(ActivityObject $obj, array &$out)
|
||||
{
|
||||
if (in_array($obj->type, $this->types())) {
|
||||
$this->activityObjectOutputJson($obj, &$out);
|
||||
$this->activityObjectOutputJson($obj, $out);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user